* src/mcs51/gen.c (toBoolean): fixed bug 1065458
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   SDCCgen51.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 //#define D(x)
32 #define D(x) x
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "SDCCglobl.h"
39 #include "newalloc.h"
40
41 #include "common.h"
42 #include "SDCCpeeph.h"
43 #include "ralloc.h"
44 #include "gen.h"
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0x00";
55 static char *one = "#0x01";
56 static char *spname;
57
58 char *fReturn8051[] =
59 {"dpl", "dph", "b", "a"};
60 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
61 char **fReturn = fReturn8051;
62 static char *accUse[] =
63 {"a", "b"};
64
65 static unsigned short rbank = -1;
66
67 static struct
68   {
69     short r0Pushed;
70     short r1Pushed;
71     union
72       {
73         struct
74           {
75             short r0InB : 2;//2 so we can see it overflow
76             short r1InB : 2;//2 so we can see it overflow
77             short OpInB : 2;//2 so we can see it overflow
78           } ;
79         short BInUse;
80       } ;
81     short accInUse;
82     short inLine;
83     short debugLine;
84     short nRegsSaved;
85     set *sendSet;
86     iCode *current_iCode;
87     symbol *currentFunc;
88   }
89 _G;
90
91 static char *rb1regs[] = {
92     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
93 };
94
95 extern int mcs51_ptrRegReq;
96 extern int mcs51_nRegs;
97 extern FILE *codeOutFile;
98 static void saveRBank (int, iCode *, bool);
99
100 #define RESULTONSTACK(x) \
101                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
102                          IC_RESULT(x)->aop->type == AOP_STK )
103
104 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
105 #define CLRC     emitcode("clr","c")
106 #define SETC     emitcode("setb","c")
107
108 static lineNode *lineHead = NULL;
109 static lineNode *lineCurr = NULL;
110
111 static unsigned char SLMask[] =
112 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
113  0xE0, 0xC0, 0x80, 0x00};
114 static unsigned char SRMask[] =
115 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
116  0x07, 0x03, 0x01, 0x00};
117
118 #define LSB     0
119 #define MSB16   1
120 #define MSB24   2
121 #define MSB32   3
122
123 /*-----------------------------------------------------------------*/
124 /* emitcode - writes the code into a file : for now it is simple    */
125 /*-----------------------------------------------------------------*/
126 static void
127 emitcode (char *inst, const char *fmt,...)
128 {
129   va_list ap;
130   char lb[INITIAL_INLINEASM];
131   char *lbp = lb;
132
133   va_start (ap, fmt);
134
135   if (inst && *inst)
136     {
137       if (fmt && *fmt)
138           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
139       else
140           SNPRINTF (lb, sizeof(lb), "%s", inst);
141       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
142     }
143   else
144       tvsprintf (lb, sizeof(lb), fmt, ap);
145
146   while (isspace (*lbp))
147       lbp++;
148
149   if (lbp && *lbp)
150       lineCurr = (lineCurr ?
151                   connectLine (lineCurr, newLineNode (lb)) :
152                   (lineHead = newLineNode (lb)));
153   lineCurr->isInline = _G.inLine;
154   lineCurr->isDebug = _G.debugLine;
155   lineCurr->ic = _G.current_iCode;
156   lineCurr->isComment = (*lbp==';');
157   va_end (ap);
158 }
159
160 /*-----------------------------------------------------------------*/
161 /* mcs51_emitDebuggerSymbol - associate the current code location  */
162 /*   with a debugger symbol                                        */
163 /*-----------------------------------------------------------------*/
164 void
165 mcs51_emitDebuggerSymbol (char * debugSym)
166 {
167   _G.debugLine = 1;
168   emitcode ("", "%s ==.", debugSym);
169   _G.debugLine = 0;
170 }
171
172 /*-----------------------------------------------------------------*/
173 /* mova - moves specified value into accumulator                   */
174 /*-----------------------------------------------------------------*/
175 static void
176 mova (const char *x)
177 {
178   /* do some early peephole optimization */
179   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
180     return;
181
182   emitcode("mov","a,%s", x);
183 }
184
185 /*-----------------------------------------------------------------*/
186 /* pushB - saves register B if necessary                           */
187 /*-----------------------------------------------------------------*/
188 static bool
189 pushB (void)
190 {
191   bool pushedB = FALSE;
192
193   if (_G.BInUse)
194     {
195       emitcode ("push", "b");
196 //    printf("B was in use !\n");
197       pushedB = TRUE;
198     }
199   else
200     {
201       _G.OpInB++;
202     }
203   return pushedB;
204 }
205
206 /*-----------------------------------------------------------------*/
207 /* popB - restores value of register B if necessary                */
208 /*-----------------------------------------------------------------*/
209 static void
210 popB (bool pushedB)
211 {
212   if (pushedB)
213     {
214       emitcode ("pop", "b");
215     }
216   else
217     {
218       _G.OpInB--;
219     }
220 }
221
222 /*-----------------------------------------------------------------*/
223 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
224 /*-----------------------------------------------------------------*/
225 static regs *
226 getFreePtr (iCode * ic, asmop ** aopp, bool result)
227 {
228   bool r0iu, r1iu;
229   bool r0ou, r1ou;
230
231   /* the logic: if r0 & r1 used in the instruction
232      then we are in trouble otherwise */
233
234   /* first check if r0 & r1 are used by this
235      instruction, in which case we are in trouble */
236   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
237   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
238   if (r0iu && r1iu) {
239       goto endOfWorld;
240     }
241
242   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
243   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
244
245   /* if no usage of r0 then return it */
246   if (!r0iu && !r0ou)
247     {
248       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
249       (*aopp)->type = AOP_R0;
250
251       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
252     }
253
254   /* if no usage of r1 then return it */
255   if (!r1iu && !r1ou)
256     {
257       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
258       (*aopp)->type = AOP_R1;
259
260       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
261     }
262
263   /* now we know they both have usage */
264   /* if r0 not used in this instruction */
265   if (!r0iu)
266     {
267       /* push it if not already pushed */
268       if (ic->op == IPUSH)
269         {
270           emitcode ("mov", "b,%s",
271                     mcs51_regWithIdx (R0_IDX)->dname);
272           _G.r0InB++;
273         }
274       else if (!_G.r0Pushed)
275         {
276           emitcode ("push", "%s",
277                     mcs51_regWithIdx (R0_IDX)->dname);
278           _G.r0Pushed++;
279         }
280
281       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
282       (*aopp)->type = AOP_R0;
283
284       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
285     }
286
287   /* if r1 not used then */
288
289   if (!r1iu)
290     {
291       /* push it if not already pushed */
292       if (ic->op == IPUSH)
293         {
294           emitcode ("mov", "b,%s",
295                     mcs51_regWithIdx (R1_IDX)->dname);
296           _G.r1InB++;
297         }
298       else if (!_G.r1Pushed)
299         {
300           emitcode ("push", "%s",
301                     mcs51_regWithIdx (R1_IDX)->dname);
302           _G.r1Pushed++;
303         }
304
305       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
306       (*aopp)->type = AOP_R1;
307       return mcs51_regWithIdx (R1_IDX);
308     }
309 endOfWorld:
310   /* I said end of world, but not quite end of world yet */
311   if (result) {
312     /* we can push it on the stack */
313     (*aopp)->type = AOP_STK;
314     return NULL;
315   } else {
316     /* in the case that result AND left AND right needs a pointer reg
317        we can safely use the result's */
318     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
319       (*aopp)->type = AOP_R0;
320       return mcs51_regWithIdx (R0_IDX);
321     }
322     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
323       (*aopp)->type = AOP_R1;
324       return mcs51_regWithIdx (R1_IDX);
325     }
326   }
327
328   /* now this is REALLY the end of the world */
329   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
330           "getFreePtr should never reach here");
331   exit (1);
332 }
333
334
335 /*-----------------------------------------------------------------*/
336 /* getTempRegs - initialize an array of pointers to GPR registers */
337 /*               that are not in use. Returns 1 if the requested   */
338 /*               number of registers were available, 0 otherwise.  */
339 /*-----------------------------------------------------------------*/
340 int
341 getTempRegs(regs **tempRegs, int size, iCode *ic)
342 {
343   bitVect * freeRegs;
344   int i;
345   int offset;
346
347   if (!ic)
348     ic = _G.current_iCode;
349   if (!ic)
350     return 0;
351   if (!_G.currentFunc)
352     return 0;
353
354   freeRegs = newBitVect(8);
355   bitVectSetBit (freeRegs, R2_IDX);
356   bitVectSetBit (freeRegs, R3_IDX);
357   bitVectSetBit (freeRegs, R4_IDX);
358   bitVectSetBit (freeRegs, R5_IDX);
359   bitVectSetBit (freeRegs, R6_IDX);
360   bitVectSetBit (freeRegs, R7_IDX);
361
362   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
363     {
364       bitVect * newfreeRegs;
365       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
366       freeBitVect(freeRegs);
367       freeRegs = newfreeRegs;
368     }
369   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
370
371   offset = 0;
372   for (i=0; i<freeRegs->size; i++)
373     {
374       if (bitVectBitValue(freeRegs,i))
375         tempRegs[offset++] = mcs51_regWithIdx(i);
376       if (offset>=size)
377         {
378           freeBitVect(freeRegs);
379           return 1;
380         }
381     }
382
383   freeBitVect(freeRegs);
384   return 1;
385 }
386
387
388 /*-----------------------------------------------------------------*/
389 /* newAsmop - creates a new asmOp                                  */
390 /*-----------------------------------------------------------------*/
391 static asmop *
392 newAsmop (short type)
393 {
394   asmop *aop;
395
396   aop = Safe_calloc (1, sizeof (asmop));
397   aop->type = type;
398   return aop;
399 }
400
401 /*-----------------------------------------------------------------*/
402 /* pointerCode - returns the code for a pointer type               */
403 /*-----------------------------------------------------------------*/
404 static int
405 pointerCode (sym_link * etype)
406 {
407
408   return PTR_TYPE (SPEC_OCLS (etype));
409
410 }
411
412 /*-----------------------------------------------------------------*/
413 /* leftRightUseAcc - returns size of accumulator use by operands   */
414 /*-----------------------------------------------------------------*/
415 static int
416 leftRightUseAcc(iCode *ic)
417 {
418   operand *op;
419   int size;
420   int accuseSize = 0;
421   int accuse = 0;
422
423   if (!ic)
424     {
425       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
426               "null iCode pointer");
427       return 0;
428     }
429
430   if (ic->op == IFX)
431     {
432       op = IC_COND (ic);
433       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
434         {
435           accuse = 1;
436           size = getSize (OP_SYMBOL (op)->type);
437           if (size>accuseSize)
438             accuseSize = size;
439         }
440     }
441   else if (ic->op == JUMPTABLE)
442     {
443       op = IC_JTCOND (ic);
444       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
445         {
446           accuse = 1;
447           size = getSize (OP_SYMBOL (op)->type);
448           if (size>accuseSize)
449             accuseSize = size;
450         }
451     }
452   else
453     {
454       op = IC_LEFT (ic);
455       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
456         {
457           accuse = 1;
458           size = getSize (OP_SYMBOL (op)->type);
459           if (size>accuseSize)
460             accuseSize = size;
461         }
462       op = IC_RIGHT (ic);
463       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
464         {
465           accuse = 1;
466           size = getSize (OP_SYMBOL (op)->type);
467           if (size>accuseSize)
468             accuseSize = size;
469         }
470     }
471
472   if (accuseSize)
473     return accuseSize;
474   else
475     return accuse;
476 }
477
478 /*-----------------------------------------------------------------*/
479 /* aopForSym - for a true symbol                                   */
480 /*-----------------------------------------------------------------*/
481 static asmop *
482 aopForSym (iCode * ic, symbol * sym, bool result)
483 {
484   asmop *aop;
485   memmap *space;
486
487   wassertl (ic != NULL, "Got a null iCode");
488   wassertl (sym != NULL, "Got a null symbol");
489
490   space = SPEC_OCLS (sym->etype);
491
492   /* if already has one */
493   if (sym->aop)
494     return sym->aop;
495
496   /* assign depending on the storage class */
497   /* if it is on the stack or indirectly addressable */
498   /* space we need to assign either r0 or r1 to it   */
499   if (sym->onStack || sym->iaccess)
500     {
501       sym->aop = aop = newAsmop (0);
502       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
503       aop->size = getSize (sym->type);
504
505       /* now assign the address of the variable to
506          the pointer register */
507       if (aop->type != AOP_STK)
508         {
509
510           if (sym->onStack)
511             {
512               if (_G.accInUse || leftRightUseAcc (ic))
513                 emitcode ("push", "acc");
514
515               emitcode ("mov", "a,_bp");
516               emitcode ("add", "a,#0x%02x",
517                         ((sym->stack < 0) ?
518                          ((char) (sym->stack - _G.nRegsSaved)) :
519                          ((char) sym->stack)) & 0xff);
520               emitcode ("mov", "%s,a",
521                         aop->aopu.aop_ptr->name);
522
523               if (_G.accInUse || leftRightUseAcc (ic))
524                 emitcode ("pop", "acc");
525             }
526           else
527             emitcode ("mov", "%s,#%s",
528                       aop->aopu.aop_ptr->name,
529                       sym->rname);
530           aop->paged = space->paged;
531         }
532       else
533         aop->aopu.aop_stk = sym->stack;
534       return aop;
535     }
536
537   /* if in bit space */
538   if (IN_BITSPACE (space))
539     {
540       sym->aop = aop = newAsmop (AOP_CRY);
541       aop->aopu.aop_dir = sym->rname;
542       aop->size = getSize (sym->type);
543       return aop;
544     }
545   /* if it is in direct space */
546   if (IN_DIRSPACE (space))
547     {
548       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
549       //printTypeChainRaw(sym->type, NULL);
550       //printf("space = %s\n", space ? space->sname : "NULL");
551       sym->aop = aop = newAsmop (AOP_DIR);
552       aop->aopu.aop_dir = sym->rname;
553       aop->size = getSize (sym->type);
554       return aop;
555     }
556
557   /* special case for a function */
558   if (IS_FUNC (sym->type))
559     {
560       sym->aop = aop = newAsmop (AOP_IMMD);
561       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
562       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
563       aop->size = FPTRSIZE;
564       return aop;
565     }
566
567   /* only remaining is far space */
568   /* in which case DPTR gets the address */
569   sym->aop = aop = newAsmop (AOP_DPTR);
570   emitcode ("mov", "dptr,#%s", sym->rname);
571   aop->size = getSize (sym->type);
572
573   /* if it is in code space */
574   if (IN_CODESPACE (space))
575     aop->code = 1;
576
577   return aop;
578 }
579
580 /*-----------------------------------------------------------------*/
581 /* aopForRemat - rematerialzes an object                           */
582 /*-----------------------------------------------------------------*/
583 static asmop *
584 aopForRemat (symbol * sym)
585 {
586   iCode *ic = sym->rematiCode;
587   asmop *aop = newAsmop (AOP_IMMD);
588   int ptr_type = 0;
589   int val = 0;
590
591   for (;;)
592     {
593       if (ic->op == '+')
594         val += (int) operandLitValue (IC_RIGHT (ic));
595       else if (ic->op == '-')
596         val -= (int) operandLitValue (IC_RIGHT (ic));
597       else if (IS_CAST_ICODE(ic)) {
598               sym_link *from_type = operandType(IC_RIGHT(ic));
599               aop->aopu.aop_immd.from_cast_remat = 1;
600               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
601               ptr_type = DCL_TYPE(from_type);
602               if (ptr_type == IPOINTER) {
603                 // bug #481053
604                 ptr_type = POINTER;
605               }
606               continue ;
607       } else break;
608
609       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
610     }
611
612   if (val)
613     sprintf (buffer, "(%s %c 0x%04x)",
614              OP_SYMBOL (IC_LEFT (ic))->rname,
615              val >= 0 ? '+' : '-',
616              abs (val) & 0xffff);
617   else
618     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
619
620   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
621   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
622   /* set immd2 field if required */
623   if (aop->aopu.aop_immd.from_cast_remat) {
624           sprintf(buffer,"#0x%02x",ptr_type);
625           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
626           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
627   }
628
629   return aop;
630 }
631
632 /*-----------------------------------------------------------------*/
633 /* regsInCommon - two operands have some registers in common       */
634 /*-----------------------------------------------------------------*/
635 static bool
636 regsInCommon (operand * op1, operand * op2)
637 {
638   symbol *sym1, *sym2;
639   int i;
640
641   /* if they have registers in common */
642   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
643     return FALSE;
644
645   sym1 = OP_SYMBOL (op1);
646   sym2 = OP_SYMBOL (op2);
647
648   if (sym1->nRegs == 0 || sym2->nRegs == 0)
649     return FALSE;
650
651   for (i = 0; i < sym1->nRegs; i++)
652     {
653       int j;
654       if (!sym1->regs[i])
655         continue;
656
657       for (j = 0; j < sym2->nRegs; j++)
658         {
659           if (!sym2->regs[j])
660             continue;
661
662           if (sym2->regs[j] == sym1->regs[i])
663             return TRUE;
664         }
665     }
666
667   return FALSE;
668 }
669
670 /*-----------------------------------------------------------------*/
671 /* operandsEqu - equivalent                                        */
672 /*-----------------------------------------------------------------*/
673 static bool
674 operandsEqu (operand * op1, operand * op2)
675 {
676   symbol *sym1, *sym2;
677
678   /* if they're not symbols */
679   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
680     return FALSE;
681
682   sym1 = OP_SYMBOL (op1);
683   sym2 = OP_SYMBOL (op2);
684
685   /* if both are itemps & one is spilt
686      and the other is not then false */
687   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
688       sym1->isspilt != sym2->isspilt)
689     return FALSE;
690
691   /* if they are the same */
692   if (sym1 == sym2)
693     return TRUE;
694
695   /* if they have the same rname */
696   if (sym1->rname[0] && sym2->rname[0]
697       && strcmp (sym1->rname, sym2->rname) == 0)
698     return TRUE;
699
700   /* if left is a tmp & right is not */
701   if (IS_ITEMP (op1) &&
702       !IS_ITEMP (op2) &&
703       sym1->isspilt &&
704       (sym1->usl.spillLoc == sym2))
705     return TRUE;
706
707   if (IS_ITEMP (op2) &&
708       !IS_ITEMP (op1) &&
709       sym2->isspilt &&
710       sym1->level > 0 &&
711       (sym2->usl.spillLoc == sym1))
712     return TRUE;
713
714   return FALSE;
715 }
716
717 /*-----------------------------------------------------------------*/
718 /* sameRegs - two asmops have the same registers                   */
719 /*-----------------------------------------------------------------*/
720 static bool
721 sameRegs (asmop * aop1, asmop * aop2)
722 {
723   int i;
724
725   if (aop1 == aop2)
726     return TRUE;
727
728   if (aop1->type != AOP_REG ||
729       aop2->type != AOP_REG)
730     return FALSE;
731
732   if (aop1->size != aop2->size)
733     return FALSE;
734
735   for (i = 0; i < aop1->size; i++)
736     if (aop1->aopu.aop_reg[i] !=
737         aop2->aopu.aop_reg[i])
738       return FALSE;
739
740   return TRUE;
741 }
742
743 /*-----------------------------------------------------------------*/
744 /* aopOp - allocates an asmop for an operand  :                    */
745 /*-----------------------------------------------------------------*/
746 static void
747 aopOp (operand * op, iCode * ic, bool result)
748 {
749   asmop *aop;
750   symbol *sym;
751   int i;
752
753   if (!op)
754     return;
755
756   /* if this a literal */
757   if (IS_OP_LITERAL (op))
758     {
759       op->aop = aop = newAsmop (AOP_LIT);
760       aop->aopu.aop_lit = op->operand.valOperand;
761       aop->size = getSize (operandType (op));
762       return;
763     }
764
765   /* if already has a asmop then continue */
766   if (op->aop )
767     return;
768
769   /* if the underlying symbol has a aop */
770   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
771     {
772       op->aop = OP_SYMBOL (op)->aop;
773       return;
774     }
775
776   /* if this is a true symbol */
777   if (IS_TRUE_SYMOP (op))
778     {
779       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
780       return;
781     }
782
783   /* this is a temporary : this has
784      only four choices :
785      a) register
786      b) spillocation
787      c) rematerialize
788      d) conditional
789      e) can be a return use only */
790
791   sym = OP_SYMBOL (op);
792
793   /* if the type is a conditional */
794   if (sym->regType == REG_CND)
795     {
796       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
797       aop->size = 0;
798       return;
799     }
800
801   /* if it is spilt then two situations
802      a) is rematerialize
803      b) has a spill location */
804   if (sym->isspilt || sym->nRegs == 0)
805     {
806
807       /* rematerialize it NOW */
808       if (sym->remat)
809         {
810           sym->aop = op->aop = aop =
811             aopForRemat (sym);
812           aop->size = getSize (sym->type);
813           return;
814         }
815
816       if (sym->accuse)
817         {
818           int i;
819           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
820           aop->size = getSize (sym->type);
821           for (i = 0; i < 2; i++)
822             aop->aopu.aop_str[i] = accUse[i];
823           return;
824         }
825
826       if (sym->ruonly)
827         {
828           unsigned i;
829
830           aop = op->aop = sym->aop = newAsmop (AOP_STR);
831           aop->size = getSize (sym->type);
832           for (i = 0; i < fReturnSizeMCS51; i++)
833             aop->aopu.aop_str[i] = fReturn[i];
834           return;
835         }
836
837       if (sym->usl.spillLoc)
838         {
839           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
840             {
841               /* force a new aop if sizes differ */
842               sym->usl.spillLoc->aop = NULL;
843             }
844           sym->aop = op->aop = aop =
845                      aopForSym (ic, sym->usl.spillLoc, result);
846           aop->size = getSize (sym->type);
847           return;
848         }
849
850       /* else must be a dummy iTemp */
851       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
852       aop->size = getSize (sym->type);
853       return;
854     }
855
856   /* must be in a register */
857   sym->aop = op->aop = aop = newAsmop (AOP_REG);
858   aop->size = sym->nRegs;
859   for (i = 0; i < sym->nRegs; i++)
860     aop->aopu.aop_reg[i] = sym->regs[i];
861 }
862
863 /*-----------------------------------------------------------------*/
864 /* freeAsmop - free up the asmop given to an operand               */
865 /*----------------------------------------------------------------*/
866 static void
867 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
868 {
869   asmop *aop;
870
871   if (!op)
872     aop = aaop;
873   else
874     aop = op->aop;
875
876   if (!aop)
877     return;
878
879   if (aop->freed)
880     goto dealloc;
881
882   aop->freed = 1;
883
884   /* depending on the asmop type only three cases need work AOP_RO
885      , AOP_R1 && AOP_STK */
886   switch (aop->type)
887     {
888     case AOP_R0:
889       if (_G.r0InB)
890         {
891           emitcode ("mov", "r0,b");
892           _G.r0InB--;
893         }
894       else if (_G.r0Pushed)
895         {
896           if (pop)
897             {
898               emitcode ("pop", "ar0");
899               _G.r0Pushed--;
900             }
901         }
902       bitVectUnSetBit (ic->rUsed, R0_IDX);
903       break;
904
905     case AOP_R1:
906       if (_G.r1InB)
907         {
908           emitcode ("mov", "r1,b");
909           _G.r1InB--;
910         }
911       if (_G.r1Pushed)
912         {
913           if (pop)
914             {
915               emitcode ("pop", "ar1");
916               _G.r1Pushed--;
917             }
918         }
919       bitVectUnSetBit (ic->rUsed, R1_IDX);
920       break;
921
922     case AOP_STK:
923       {
924         int sz = aop->size;
925         int stk = aop->aopu.aop_stk + aop->size - 1;
926         bitVectUnSetBit (ic->rUsed, R0_IDX);
927         bitVectUnSetBit (ic->rUsed, R1_IDX);
928
929         getFreePtr (ic, &aop, FALSE);
930
931         if (stk)
932           {
933             emitcode ("mov", "a,_bp");
934             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
935             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
936           }
937         else
938           {
939             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
940           }
941
942         while (sz--)
943           {
944             emitcode ("pop", "acc");
945             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
946             if (!sz)
947               break;
948             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
949           }
950         op->aop = aop;
951         freeAsmop (op, NULL, ic, TRUE);
952         if (_G.r1Pushed)
953           {
954             emitcode ("pop", "ar1");
955             _G.r1Pushed--;
956           }
957
958         if (_G.r0Pushed)
959           {
960             emitcode ("pop", "ar0");
961             _G.r0Pushed--;
962           }
963       }
964     }
965
966 dealloc:
967   /* all other cases just dealloc */
968   if (op)
969     {
970       op->aop = NULL;
971       if (IS_SYMOP (op))
972         {
973           OP_SYMBOL (op)->aop = NULL;
974           /* if the symbol has a spill */
975           if (SPIL_LOC (op))
976             SPIL_LOC (op)->aop = NULL;
977         }
978     }
979 }
980
981 /*------------------------------------------------------------------*/
982 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
983 /*                      pop r0 or r1 off stack if pushed            */
984 /*------------------------------------------------------------------*/
985 static void
986 freeForBranchAsmop (operand * op)
987 {
988   asmop *aop;
989
990   if (!op)
991     return;
992
993   aop = op->aop;
994
995   if (!aop)
996     return;
997
998   if (aop->freed)
999     return;
1000
1001   switch (aop->type)
1002     {
1003     case AOP_R0:
1004       if (_G.r0InB)
1005         {
1006           emitcode ("mov", "r0,b");
1007         }
1008       else if (_G.r0Pushed)
1009         {
1010           emitcode ("pop", "ar0");
1011         }
1012       break;
1013
1014     case AOP_R1:
1015       if (_G.r1InB)
1016         {
1017           emitcode ("mov", "r1,b");
1018         }
1019       else if (_G.r1Pushed)
1020         {
1021           emitcode ("pop", "ar1");
1022         }
1023       break;
1024
1025     case AOP_STK:
1026       {
1027         int sz = aop->size;
1028         int stk = aop->aopu.aop_stk + aop->size - 1;
1029
1030         emitcode ("mov", "b,r0");
1031         if (stk)
1032           {
1033             emitcode ("mov", "a,_bp");
1034             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1035             emitcode ("mov", "r0,a");
1036           }
1037         else
1038           {
1039             emitcode ("mov", "r0,_bp");
1040           }
1041
1042         while (sz--)
1043           {
1044             emitcode ("pop", "acc");
1045             emitcode ("mov", "@r0,a");
1046             if (!sz)
1047               break;
1048             emitcode ("dec", "r0");
1049           }
1050         emitcode ("mov", "r0,b");
1051       }
1052     }
1053
1054 }
1055
1056 /*-----------------------------------------------------------------*/
1057 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1058 /*                 clobber the accumulator                         */
1059 /*-----------------------------------------------------------------*/
1060 static bool
1061 aopGetUsesAcc (asmop *aop, int offset)
1062 {
1063   if (offset > (aop->size - 1))
1064     return FALSE;
1065
1066   switch (aop->type)
1067     {
1068
1069     case AOP_R0:
1070     case AOP_R1:
1071       if (aop->paged)
1072         return TRUE;
1073       return FALSE;
1074     case AOP_DPTR:
1075       return TRUE;
1076     case AOP_IMMD:
1077       return FALSE;
1078     case AOP_DIR:
1079       return FALSE;
1080     case AOP_REG:
1081       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1082       return FALSE;
1083     case AOP_CRY:
1084       return TRUE;
1085     case AOP_ACC:
1086       return TRUE;
1087     case AOP_LIT:
1088       return FALSE;
1089     case AOP_STR:
1090       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1091         return TRUE;
1092       return FALSE;
1093     case AOP_DUMMY:
1094       return FALSE;
1095     default:
1096       /* Error case --- will have been caught already */
1097       wassert(0);
1098       return FALSE;
1099     }
1100 }
1101
1102 /*-----------------------------------------------------------------*/
1103 /* aopGet - for fetching value of the aop                          */
1104 /*-----------------------------------------------------------------*/
1105 static char *
1106 aopGet (asmop * aop, int offset, bool bit16, bool dname)
1107 {
1108   char *s = buffer;
1109   char *rs;
1110
1111   /* offset is greater than
1112      size then zero */
1113   if (offset > (aop->size - 1) &&
1114       aop->type != AOP_LIT)
1115     return zero;
1116
1117   /* depending on type */
1118   switch (aop->type)
1119     {
1120     case AOP_DUMMY:
1121       return zero;
1122
1123     case AOP_R0:
1124     case AOP_R1:
1125       /* if we need to increment it */
1126       while (offset > aop->coff)
1127         {
1128           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1129           aop->coff++;
1130         }
1131
1132       while (offset < aop->coff)
1133         {
1134           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1135           aop->coff--;
1136         }
1137
1138       aop->coff = offset;
1139       if (aop->paged)
1140         {
1141           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1142           return (dname ? "acc" : "a");
1143         }
1144       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1145       rs = Safe_calloc (1, strlen (s) + 1);
1146       strcpy (rs, s);
1147       return rs;
1148
1149     case AOP_DPTR:
1150       if (aop->code && aop->coff==0 && offset>=1) {
1151         emitcode ("mov", "a,#0x%02x", offset);
1152         emitcode ("movc", "a,@a+dptr");
1153         return (dname ? "acc" : "a");
1154       }
1155
1156       while (offset > aop->coff)
1157         {
1158           emitcode ("inc", "dptr");
1159           aop->coff++;
1160         }
1161
1162       while (offset < aop->coff)
1163         {
1164           emitcode ("lcall", "__decdptr");
1165           aop->coff--;
1166         }
1167
1168       aop->coff = offset;
1169       if (aop->code)
1170         {
1171           emitcode ("clr", "a");
1172           emitcode ("movc", "a,@a+dptr");
1173         }
1174       else
1175         {
1176           emitcode ("movx", "a,@dptr");
1177         }
1178       return (dname ? "acc" : "a");
1179
1180
1181     case AOP_IMMD:
1182       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1183               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1184       } else if (bit16)
1185         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1186       else if (offset)
1187         sprintf (s, "#(%s >> %d)",
1188                  aop->aopu.aop_immd.aop_immd1,
1189                  offset * 8);
1190       else
1191         sprintf (s, "#%s",
1192                  aop->aopu.aop_immd.aop_immd1);
1193       rs = Safe_calloc (1, strlen (s) + 1);
1194       strcpy (rs, s);
1195       return rs;
1196
1197     case AOP_DIR:
1198       if (offset)
1199         sprintf (s, "(%s + %d)",
1200                  aop->aopu.aop_dir,
1201                  offset);
1202       else
1203         sprintf (s, "%s", aop->aopu.aop_dir);
1204       rs = Safe_calloc (1, strlen (s) + 1);
1205       strcpy (rs, s);
1206       return rs;
1207
1208     case AOP_REG:
1209       if (dname)
1210         return aop->aopu.aop_reg[offset]->dname;
1211       else
1212         return aop->aopu.aop_reg[offset]->name;
1213
1214     case AOP_CRY:
1215       emitcode ("clr", "a");
1216       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1217       emitcode ("rlc", "a");
1218       return (dname ? "acc" : "a");
1219
1220     case AOP_ACC:
1221       if (!offset && dname)
1222         return "acc";
1223       return aop->aopu.aop_str[offset];
1224
1225     case AOP_LIT:
1226       return aopLiteral (aop->aopu.aop_lit, offset);
1227
1228     case AOP_STR:
1229       aop->coff = offset;
1230       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1231           dname)
1232         return "acc";
1233
1234       return aop->aopu.aop_str[offset];
1235
1236     }
1237
1238   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1239           "aopget got unsupported aop->type");
1240   exit (1);
1241 }
1242 /*-----------------------------------------------------------------*/
1243 /* aopPut - puts a string for a aop                                */
1244 /*-----------------------------------------------------------------*/
1245 static void
1246 aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
1247 {
1248   char *d = buffer;
1249
1250   if (aop->size && offset > (aop->size - 1))
1251     {
1252       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1253               "aopPut got offset > aop->size");
1254       exit (1);
1255     }
1256
1257   /* will assign value to value */
1258   /* depending on where it is ofcourse */
1259   switch (aop->type)
1260     {
1261     case AOP_DUMMY:
1262       MOVA (s);         /* read s in case it was volatile */
1263       break;
1264
1265     case AOP_DIR:
1266       if (offset)
1267         sprintf (d, "(%s + %d)",
1268                  aop->aopu.aop_dir, offset);
1269       else
1270         sprintf (d, "%s", aop->aopu.aop_dir);
1271
1272       if (strcmp (d, s) ||
1273           bvolatile)
1274           emitcode ("mov", "%s,%s", d, s);
1275
1276       break;
1277
1278     case AOP_REG:
1279       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1280           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1281         {
1282           if (*s == '@' ||
1283               strcmp (s, "r0") == 0 ||
1284               strcmp (s, "r1") == 0 ||
1285               strcmp (s, "r2") == 0 ||
1286               strcmp (s, "r3") == 0 ||
1287               strcmp (s, "r4") == 0 ||
1288               strcmp (s, "r5") == 0 ||
1289               strcmp (s, "r6") == 0 ||
1290               strcmp (s, "r7") == 0)
1291             emitcode ("mov", "%s,%s",
1292                       aop->aopu.aop_reg[offset]->dname, s);
1293           else
1294             emitcode ("mov", "%s,%s",
1295                       aop->aopu.aop_reg[offset]->name, s);
1296         }
1297       break;
1298
1299     case AOP_DPTR:
1300       if (aop->code)
1301         {
1302           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1303                   "aopPut writing to code space");
1304           exit (1);
1305         }
1306
1307       while (offset > aop->coff)
1308         {
1309           aop->coff++;
1310           emitcode ("inc", "dptr");
1311         }
1312
1313       while (offset < aop->coff)
1314         {
1315           aop->coff--;
1316           emitcode ("lcall", "__decdptr");
1317         }
1318
1319       aop->coff = offset;
1320
1321       /* if not in accumulater */
1322       MOVA (s);
1323
1324       emitcode ("movx", "@dptr,a");
1325       break;
1326
1327     case AOP_R0:
1328     case AOP_R1:
1329       while (offset > aop->coff)
1330         {
1331           aop->coff++;
1332           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1333         }
1334       while (offset < aop->coff)
1335         {
1336           aop->coff--;
1337           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1338         }
1339       aop->coff = offset;
1340
1341       if (aop->paged)
1342         {
1343           MOVA (s);
1344           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1345
1346         }
1347       else if (*s == '@')
1348         {
1349           MOVA (s);
1350           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1351         }
1352       else if (strcmp (s, "r0") == 0 ||
1353                strcmp (s, "r1") == 0 ||
1354                strcmp (s, "r2") == 0 ||
1355                strcmp (s, "r3") == 0 ||
1356                strcmp (s, "r4") == 0 ||
1357                strcmp (s, "r5") == 0 ||
1358                strcmp (s, "r6") == 0 ||
1359                strcmp (s, "r7") == 0)
1360         {
1361           char buffer[10];
1362           sprintf (buffer, "a%s", s);
1363           emitcode ("mov", "@%s,%s",
1364                     aop->aopu.aop_ptr->name, buffer);
1365         }
1366       else
1367         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1368
1369       break;
1370
1371     case AOP_STK:
1372       if (strcmp (s, "a") == 0)
1373         emitcode ("push", "acc");
1374       else
1375         if (*s=='@') {
1376           MOVA(s);
1377           emitcode ("push", "acc");
1378         } else {
1379           emitcode ("push", s);
1380         }
1381
1382       break;
1383
1384     case AOP_CRY:
1385       /* if bit variable */
1386       if (!aop->aopu.aop_dir)
1387         {
1388           emitcode ("clr", "a");
1389           emitcode ("rlc", "a");
1390         }
1391       else
1392         {
1393           if (s == zero)
1394             emitcode ("clr", "%s", aop->aopu.aop_dir);
1395           else if (s == one)
1396             emitcode ("setb", "%s", aop->aopu.aop_dir);
1397           else if (!strcmp (s, "c"))
1398             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1399           else
1400             {
1401               if (strcmp (s, "a"))
1402                 {
1403                   MOVA (s);
1404                 }
1405               {
1406                 /* set C, if a >= 1 */
1407                 emitcode ("add", "a,#0xff");
1408                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1409               }
1410             }
1411         }
1412       break;
1413
1414     case AOP_STR:
1415       aop->coff = offset;
1416       if (strcmp (aop->aopu.aop_str[offset], s) ||
1417           bvolatile)
1418         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1419       break;
1420
1421     case AOP_ACC:
1422       aop->coff = offset;
1423       if (!offset && (strcmp (s, "acc") == 0) &&
1424           !bvolatile)
1425         break;
1426
1427       if (strcmp (aop->aopu.aop_str[offset], s) &&
1428           !bvolatile)
1429         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1430       break;
1431
1432     default:
1433       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1434               "aopPut got unsupported aop->type");
1435       exit (1);
1436     }
1437
1438 }
1439
1440
1441 #if 0
1442 /*-----------------------------------------------------------------*/
1443 /* pointToEnd :- points to the last byte of the operand            */
1444 /*-----------------------------------------------------------------*/
1445 static void
1446 pointToEnd (asmop * aop)
1447 {
1448   int count;
1449   if (!aop)
1450     return;
1451
1452   aop->coff = count = (aop->size - 1);
1453   switch (aop->type)
1454     {
1455     case AOP_R0:
1456     case AOP_R1:
1457       while (count--)
1458         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1459       break;
1460     case AOP_DPTR:
1461       while (count--)
1462         emitcode ("inc", "dptr");
1463       break;
1464     }
1465
1466 }
1467 #endif
1468
1469 /*-----------------------------------------------------------------*/
1470 /* reAdjustPreg - points a register back to where it should        */
1471 /*-----------------------------------------------------------------*/
1472 static void
1473 reAdjustPreg (asmop * aop)
1474 {
1475   if ((aop->coff==0) || aop->size <= 1)
1476     return;
1477
1478   switch (aop->type)
1479     {
1480     case AOP_R0:
1481     case AOP_R1:
1482       while (aop->coff--)
1483         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1484       break;
1485     case AOP_DPTR:
1486       while (aop->coff--)
1487         {
1488           emitcode ("lcall", "__decdptr");
1489         }
1490       break;
1491     }
1492   aop->coff = 0;
1493 }
1494
1495 #define AOP(op) op->aop
1496 #define AOP_TYPE(op) AOP(op)->type
1497 #define AOP_SIZE(op) AOP(op)->size
1498 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1499                        AOP_TYPE(x) == AOP_R0))
1500
1501 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1502                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
1503
1504 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1505                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
1506                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
1507
1508
1509 /*-----------------------------------------------------------------*/
1510 /* opIsGptr: returns non-zero if the passed operand is       */
1511 /* a generic pointer type.             */
1512 /*-----------------------------------------------------------------*/
1513 static int
1514 opIsGptr (operand * op)
1515 {
1516   sym_link *type = operandType (op);
1517
1518   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1519     {
1520       return 1;
1521     }
1522   return 0;
1523 }
1524
1525 /*-----------------------------------------------------------------*/
1526 /* getDataSize - get the operand data size                         */
1527 /*-----------------------------------------------------------------*/
1528 static int
1529 getDataSize (operand * op)
1530 {
1531   int size;
1532   size = AOP_SIZE (op);
1533   if (size == GPTRSIZE)
1534     {
1535       sym_link *type = operandType (op);
1536       if (IS_GENPTR (type))
1537         {
1538           /* generic pointer; arithmetic operations
1539            * should ignore the high byte (pointer type).
1540            */
1541           size--;
1542         }
1543     }
1544   return size;
1545 }
1546
1547 /*-----------------------------------------------------------------*/
1548 /* outAcc - output Acc                                             */
1549 /*-----------------------------------------------------------------*/
1550 static void
1551 outAcc (operand * result)
1552 {
1553   int size, offset;
1554   size = getDataSize (result);
1555   if (size)
1556     {
1557       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
1558       size--;
1559       offset = 1;
1560       /* unsigned or positive */
1561       while (size--)
1562         {
1563           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
1564         }
1565     }
1566 }
1567
1568 /*-----------------------------------------------------------------*/
1569 /* outBitC - output a bit C                                        */
1570 /*-----------------------------------------------------------------*/
1571 static void
1572 outBitC (operand * result)
1573 {
1574   /* if the result is bit */
1575   if (AOP_TYPE (result) == AOP_CRY)
1576     aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
1577   else
1578     {
1579       emitcode ("clr", "a");
1580       emitcode ("rlc", "a");
1581       outAcc (result);
1582     }
1583 }
1584
1585 /*-----------------------------------------------------------------*/
1586 /* toBoolean - emit code for orl a,operator(sizeop)                */
1587 /*-----------------------------------------------------------------*/
1588 static void
1589 toBoolean (operand * oper)
1590 {
1591   int size = AOP_SIZE (oper) - 1;
1592   int offset = 1;
1593   bool AccUsed = FALSE;
1594   bool pushedB;
1595
1596   while (!AccUsed && size--)
1597     {
1598       AccUsed |= aopGetUsesAcc(AOP (oper), offset++);
1599     }
1600
1601   size = AOP_SIZE (oper) - 1;
1602   offset = 1;
1603   MOVA (aopGet (AOP (oper), 0, FALSE, FALSE));
1604   if (AccUsed && (AOP (oper)->type != AOP_ACC))
1605     {
1606       pushedB = pushB ();
1607       emitcode("mov", "b,a");
1608       while (size--)
1609         {
1610           MOVA (aopGet (AOP (oper), offset++, FALSE, FALSE));
1611           emitcode ("orl", "b,a");
1612         }
1613       popB (pushedB);
1614     }
1615   else
1616     {
1617       while (size--)
1618         {
1619           emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE));
1620         }
1621     }
1622 }
1623
1624
1625 /*-----------------------------------------------------------------*/
1626 /* genNot - generate code for ! operation                          */
1627 /*-----------------------------------------------------------------*/
1628 static void
1629 genNot (iCode * ic)
1630 {
1631   symbol *tlbl;
1632
1633   D(emitcode (";     genNot",""));
1634
1635   /* assign asmOps to operand & result */
1636   aopOp (IC_LEFT (ic), ic, FALSE);
1637   aopOp (IC_RESULT (ic), ic, TRUE);
1638
1639   /* if in bit space then a special case */
1640   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1641     {
1642       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1643       emitcode ("cpl", "c");
1644       outBitC (IC_RESULT (ic));
1645       goto release;
1646     }
1647
1648   toBoolean (IC_LEFT (ic));
1649
1650   tlbl = newiTempLabel (NULL);
1651   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1652   emitcode ("", "%05d$:", tlbl->key + 100);
1653   outBitC (IC_RESULT (ic));
1654
1655 release:
1656   /* release the aops */
1657   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1658   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1659 }
1660
1661
1662 /*-----------------------------------------------------------------*/
1663 /* genCpl - generate code for complement                           */
1664 /*-----------------------------------------------------------------*/
1665 static void
1666 genCpl (iCode * ic)
1667 {
1668   int offset = 0;
1669   int size;
1670   symbol *tlbl;
1671
1672   D(emitcode (";     genCpl",""));
1673
1674   /* assign asmOps to operand & result */
1675   aopOp (IC_LEFT (ic), ic, FALSE);
1676   aopOp (IC_RESULT (ic), ic, TRUE);
1677
1678   /* special case if in bit space */
1679   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1680     {
1681       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1682         {
1683           /* promotion rules are responsible for this strange result: */
1684           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1685           goto release;
1686         }
1687
1688       tlbl=newiTempLabel(NULL);
1689       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC ||
1690           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1691           IS_AOP_PREG (IC_LEFT (ic)))
1692         {
1693           emitcode ("cjne", "%s,#0x01,%05d$",
1694                     aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE),
1695                     tlbl->key + 100);
1696         }
1697       else
1698         {
1699           char *l = aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE);
1700           MOVA (l);
1701           emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1702         }
1703       emitcode ("", "%05d$:", tlbl->key + 100);
1704       outBitC (IC_RESULT(ic));
1705       goto release;
1706     }
1707
1708   size = AOP_SIZE (IC_RESULT (ic));
1709   while (size--)
1710     {
1711       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1712       MOVA (l);
1713       emitcode ("cpl", "a");
1714       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1715     }
1716
1717
1718 release:
1719   /* release the aops */
1720   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1721   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1722 }
1723
1724 /*-----------------------------------------------------------------*/
1725 /* genUminusFloat - unary minus for floating points                */
1726 /*-----------------------------------------------------------------*/
1727 static void
1728 genUminusFloat (operand * op, operand * result)
1729 {
1730   int size, offset = 0;
1731   char *l;
1732
1733   D(emitcode (";     genUminusFloat",""));
1734
1735   /* for this we just copy and then flip the bit */
1736
1737   size = AOP_SIZE (op) - 1;
1738
1739   while (size--)
1740     {
1741       aopPut (AOP (result),
1742               aopGet (AOP (op), offset, FALSE, FALSE),
1743               offset,
1744               isOperandVolatile (result, FALSE));
1745       offset++;
1746     }
1747
1748   l = aopGet (AOP (op), offset, FALSE, FALSE);
1749
1750   MOVA (l);
1751
1752   emitcode ("cpl", "acc.7");
1753   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
1754 }
1755
1756 /*-----------------------------------------------------------------*/
1757 /* genUminus - unary minus code generation                         */
1758 /*-----------------------------------------------------------------*/
1759 static void
1760 genUminus (iCode * ic)
1761 {
1762   int offset, size;
1763   sym_link *optype, *rtype;
1764
1765
1766   D(emitcode (";     genUminus",""));
1767
1768   /* assign asmops */
1769   aopOp (IC_LEFT (ic), ic, FALSE);
1770   aopOp (IC_RESULT (ic), ic, TRUE);
1771
1772   /* if both in bit space then special
1773      case */
1774   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1775       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1776     {
1777
1778       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1779       emitcode ("cpl", "c");
1780       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1781       goto release;
1782     }
1783
1784   optype = operandType (IC_LEFT (ic));
1785   rtype = operandType (IC_RESULT (ic));
1786
1787   /* if float then do float stuff */
1788   if (IS_FLOAT (optype))
1789     {
1790       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1791       goto release;
1792     }
1793
1794   /* otherwise subtract from zero */
1795   size = AOP_SIZE (IC_LEFT (ic));
1796   offset = 0;
1797   //CLRC ;
1798   while (size--)
1799     {
1800       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1801       if (!strcmp (l, "a"))
1802         {
1803           if (offset == 0)
1804             SETC;
1805           emitcode ("cpl", "a");
1806           emitcode ("addc", "a,#0");
1807         }
1808       else
1809         {
1810           if (offset == 0)
1811             CLRC;
1812           emitcode ("clr", "a");
1813           emitcode ("subb", "a,%s", l);
1814         }
1815       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1816     }
1817
1818   /* if any remaining bytes in the result */
1819   /* we just need to propagate the sign   */
1820   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1821     {
1822       emitcode ("rlc", "a");
1823       emitcode ("subb", "a,acc");
1824       while (size--)
1825         aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1826     }
1827
1828 release:
1829   /* release the aops */
1830   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1831   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1832 }
1833
1834 /*-----------------------------------------------------------------*/
1835 /* saveRegisters - will look for a call and save the registers     */
1836 /*-----------------------------------------------------------------*/
1837 static void
1838 saveRegisters (iCode * lic)
1839 {
1840   int i;
1841   iCode *ic;
1842   bitVect *rsave;
1843
1844   /* look for call */
1845   for (ic = lic; ic; ic = ic->next)
1846     if (ic->op == CALL || ic->op == PCALL)
1847       break;
1848
1849   if (!ic)
1850     {
1851       fprintf (stderr, "found parameter push with no function call\n");
1852       return;
1853     }
1854
1855   /* if the registers have been saved already or don't need to be then
1856      do nothing */
1857   if (ic->regsSaved)
1858     return;
1859   if (IS_SYMOP(IC_LEFT(ic)) &&
1860       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1861        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1862     return;
1863
1864   /* save the registers in use at this time but skip the
1865      ones for the result */
1866   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1867                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1868
1869   ic->regsSaved = 1;
1870   if (options.useXstack)
1871     {
1872       if (bitVectBitValue (rsave, R0_IDX))
1873         {
1874           emitcode ("mov", "a,r0");
1875           emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1876         }
1877       emitcode ("mov", "r0,%s", spname);
1878       for (i = 0; i < mcs51_nRegs; i++)
1879         {
1880           if (bitVectBitValue (rsave, i))
1881             {
1882               if (i != R0_IDX)
1883                 emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1884               emitcode ("movx", "@r0,a");
1885               emitcode ("inc", "r0");
1886             }
1887         }
1888       emitcode ("mov", "%s,r0", spname);
1889       if (bitVectBitValue (rsave, R0_IDX))
1890         {
1891           emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
1892         }
1893     }
1894   else
1895     for (i = 0; i < mcs51_nRegs; i++)
1896       {
1897         if (bitVectBitValue (rsave, i))
1898           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1899       }
1900 }
1901
1902 /*-----------------------------------------------------------------*/
1903 /* unsaveRegisters - pop the pushed registers                      */
1904 /*-----------------------------------------------------------------*/
1905 static void
1906 unsaveRegisters (iCode * ic)
1907 {
1908   int i;
1909   bitVect *rsave;
1910
1911   /* restore the registers in use at this time but skip the
1912      ones for the result */
1913   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1914                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1915
1916   if (options.useXstack)
1917     {
1918       emitcode ("mov", "r0,%s", spname);
1919       for (i = mcs51_nRegs; i >= 0; i--)
1920         {
1921           if (bitVectBitValue (rsave, i))
1922             {
1923               emitcode ("dec", "r0");
1924               emitcode ("movx", "a,@r0");
1925               if (i != R0_IDX)
1926                 emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1927             }
1928
1929         }
1930       emitcode ("mov", "%s,r0", spname);
1931       if (bitVectBitValue (rsave, R0_IDX))
1932         {
1933           emitcode ("mov", "r0,a");
1934         }
1935     }
1936   else
1937     for (i = mcs51_nRegs; i >= 0; i--)
1938       {
1939         if (bitVectBitValue (rsave, i))
1940           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
1941       }
1942
1943 }
1944
1945
1946 /*-----------------------------------------------------------------*/
1947 /* pushSide -                */
1948 /*-----------------------------------------------------------------*/
1949 static void
1950 pushSide (operand * oper, int size)
1951 {
1952   int offset = 0;
1953   while (size--)
1954     {
1955       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE);
1956       if (AOP_TYPE (oper) != AOP_REG &&
1957           AOP_TYPE (oper) != AOP_DIR &&
1958           strcmp (l, "a"))
1959         {
1960           MOVA (l);
1961           emitcode ("push", "acc");
1962         }
1963       else
1964           emitcode ("push", "%s", l);
1965         }
1966     }
1967
1968 /*-----------------------------------------------------------------*/
1969 /* assignResultValue -               */
1970 /*-----------------------------------------------------------------*/
1971 static void
1972 assignResultValue (operand * oper)
1973 {
1974   int offset = 0;
1975   int size = AOP_SIZE (oper);
1976   while (size--)
1977     {
1978       aopPut (AOP (oper), fReturn[offset], offset, isOperandVolatile (oper, FALSE));
1979       offset++;
1980     }
1981 }
1982
1983
1984 /*-----------------------------------------------------------------*/
1985 /* genXpush - pushes onto the external stack                       */
1986 /*-----------------------------------------------------------------*/
1987 static void
1988 genXpush (iCode * ic)
1989 {
1990   asmop *aop = newAsmop (0);
1991   regs *r;
1992   int size, offset = 0;
1993
1994   D(emitcode (";     genXpush",""));
1995
1996   aopOp (IC_LEFT (ic), ic, FALSE);
1997   r = getFreePtr (ic, &aop, FALSE);
1998
1999
2000   emitcode ("mov", "%s,_spx", r->name);
2001
2002   size = AOP_SIZE (IC_LEFT (ic));
2003   while (size--)
2004     {
2005
2006       char *l = aopGet (AOP (IC_LEFT (ic)),
2007                         offset++, FALSE, FALSE);
2008       MOVA (l);
2009       emitcode ("movx", "@%s,a", r->name);
2010       emitcode ("inc", "%s", r->name);
2011
2012     }
2013
2014
2015   emitcode ("mov", "_spx,%s", r->name);
2016
2017   freeAsmop (NULL, aop, ic, TRUE);
2018   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2019 }
2020
2021 /*-----------------------------------------------------------------*/
2022 /* genIpush - genrate code for pushing this gets a little complex  */
2023 /*-----------------------------------------------------------------*/
2024 static void
2025 genIpush (iCode * ic)
2026 {
2027   int size, offset = 0;
2028   char *l;
2029
2030   D(emitcode (";     genIpush",""));
2031
2032   /* if this is not a parm push : ie. it is spill push
2033      and spill push is always done on the local stack */
2034   if (!ic->parmPush)
2035     {
2036
2037       /* and the item is spilt then do nothing */
2038       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2039         return;
2040
2041       aopOp (IC_LEFT (ic), ic, FALSE);
2042       size = AOP_SIZE (IC_LEFT (ic));
2043       /* push it on the stack */
2044       while (size--)
2045         {
2046           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2047           if (*l == '#')
2048             {
2049               MOVA (l);
2050               l = "acc";
2051             }
2052           emitcode ("push", "%s", l);
2053         }
2054       return;
2055     }
2056
2057   /* this is a paramter push: in this case we call
2058      the routine to find the call and save those
2059      registers that need to be saved */
2060   saveRegisters (ic);
2061
2062   /* if use external stack then call the external
2063      stack pushing routine */
2064   if (options.useXstack)
2065     {
2066       genXpush (ic);
2067       return;
2068     }
2069
2070   /* then do the push */
2071   aopOp (IC_LEFT (ic), ic, FALSE);
2072
2073
2074   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2075   size = AOP_SIZE (IC_LEFT (ic));
2076
2077   while (size--)
2078     {
2079       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2080       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2081           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2082           strcmp (l, "a"))
2083         {
2084           MOVA (l);
2085           emitcode ("push", "acc");
2086         }
2087       else
2088           emitcode ("push", "%s", l);
2089         }
2090
2091   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2092 }
2093
2094 /*-----------------------------------------------------------------*/
2095 /* genIpop - recover the registers: can happen only for spilling   */
2096 /*-----------------------------------------------------------------*/
2097 static void
2098 genIpop (iCode * ic)
2099 {
2100   int size, offset;
2101
2102   D(emitcode (";     genIpop",""));
2103
2104   /* if the temp was not pushed then */
2105   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2106     return;
2107
2108   aopOp (IC_LEFT (ic), ic, FALSE);
2109   size = AOP_SIZE (IC_LEFT (ic));
2110   offset = (size - 1);
2111   while (size--)
2112     emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2113                                    FALSE, TRUE));
2114
2115   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2116 }
2117
2118 /*-----------------------------------------------------------------*/
2119 /* unsaveRBank - restores the resgister bank from stack            */
2120 /*-----------------------------------------------------------------*/
2121 static void
2122 unsaveRBank (int bank, iCode * ic, bool popPsw)
2123 {
2124   int i;
2125   asmop *aop = NULL;
2126   regs *r = NULL;
2127
2128   if (options.useXstack)
2129   {
2130       if (!ic)
2131       {
2132           /* Assume r0 is available for use. */
2133           r = mcs51_regWithIdx (R0_IDX);;
2134       }
2135       else
2136       {
2137           aop = newAsmop (0);
2138           r = getFreePtr (ic, &aop, FALSE);
2139       }
2140       emitcode ("mov", "%s,_spx", r->name);
2141   }
2142
2143   if (popPsw)
2144     {
2145       if (options.useXstack)
2146       {
2147           emitcode ("movx", "a,@%s", r->name);
2148           emitcode ("mov", "psw,a");
2149           emitcode ("dec", "%s", r->name);
2150         }
2151       else
2152       {
2153         emitcode ("pop", "psw");
2154       }
2155     }
2156
2157   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2158     {
2159       if (options.useXstack)
2160         {
2161           emitcode ("movx", "a,@%s", r->name);
2162           emitcode ("mov", "(%s+%d),a",
2163                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2164           emitcode ("dec", "%s", r->name);
2165
2166         }
2167       else
2168         emitcode ("pop", "(%s+%d)",
2169                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2170     }
2171
2172   if (options.useXstack)
2173     {
2174       emitcode ("mov", "_spx,%s", r->name);
2175     }
2176
2177   if (aop)
2178   {
2179       freeAsmop (NULL, aop, ic, TRUE);
2180   }
2181 }
2182
2183 /*-----------------------------------------------------------------*/
2184 /* saveRBank - saves an entire register bank on the stack          */
2185 /*-----------------------------------------------------------------*/
2186 static void
2187 saveRBank (int bank, iCode * ic, bool pushPsw)
2188 {
2189   int i;
2190   asmop *aop = NULL;
2191   regs *r = NULL;
2192
2193   if (options.useXstack)
2194     {
2195       if (!ic)
2196       {
2197           /* Assume r0 is available for use. */
2198           r = mcs51_regWithIdx (R0_IDX);;
2199       }
2200       else
2201       {
2202           aop = newAsmop (0);
2203           r = getFreePtr (ic, &aop, FALSE);
2204       }
2205       emitcode ("mov", "%s,_spx", r->name);
2206     }
2207
2208   for (i = 0; i < mcs51_nRegs; i++)
2209     {
2210       if (options.useXstack)
2211         {
2212           emitcode ("inc", "%s", r->name);
2213           emitcode ("mov", "a,(%s+%d)",
2214                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2215           emitcode ("movx", "@%s,a", r->name);
2216         }
2217       else
2218         emitcode ("push", "(%s+%d)",
2219                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2220     }
2221
2222   if (pushPsw)
2223     {
2224       if (options.useXstack)
2225         {
2226           emitcode ("mov", "a,psw");
2227           emitcode ("movx", "@%s,a", r->name);
2228           emitcode ("inc", "%s", r->name);
2229           emitcode ("mov", "_spx,%s", r->name);
2230
2231         }
2232       else
2233       {
2234         emitcode ("push", "psw");
2235       }
2236
2237       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2238     }
2239
2240   if (aop)
2241     {
2242       freeAsmop (NULL, aop, ic, TRUE);
2243     }
2244
2245   if (ic)
2246   {
2247     ic->bankSaved = 1;
2248   }
2249 }
2250
2251 /*-----------------------------------------------------------------*/
2252 /* genSend - gen code for SEND                                     */
2253 /*-----------------------------------------------------------------*/
2254 static void genSend(set *sendSet)
2255 {
2256     iCode *sic;
2257     int rb1_count = 0 ;
2258
2259     for (sic = setFirstItem (sendSet); sic;
2260          sic = setNextItem (sendSet)) {
2261           int size, offset = 0;
2262           aopOp (IC_LEFT (sic), sic, FALSE);
2263           size = AOP_SIZE (IC_LEFT (sic));
2264
2265           if (sic->argreg == 1) {
2266               while (size--) {
2267                   char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2268                                     FALSE, FALSE);
2269                   if (strcmp (l, fReturn[offset]))
2270                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2271                   offset++;
2272               }
2273               rb1_count = 0;
2274           } else {
2275               while (size--) {
2276                   emitcode ("mov","b1_%d,%s",rb1_count++,
2277                             aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
2278               }
2279           }
2280           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2281     }
2282 }
2283
2284 /*-----------------------------------------------------------------*/
2285 /* genCall - generates a call statement                            */
2286 /*-----------------------------------------------------------------*/
2287 static void
2288 genCall (iCode * ic)
2289 {
2290   sym_link *dtype;
2291 //  bool restoreBank = FALSE;
2292   bool swapBanks = FALSE;
2293
2294   D(emitcode(";     genCall",""));
2295
2296   dtype = operandType (IC_LEFT (ic));
2297   /* if send set is not empty then assign */
2298   if (_G.sendSet)
2299     {
2300         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2301             genSend(reverseSet(_G.sendSet));
2302         } else {
2303             genSend(_G.sendSet);
2304         }
2305
2306       _G.sendSet = NULL;
2307     }
2308
2309   /* if we are calling a not _naked function that is not using
2310      the same register bank then we need to save the
2311      destination registers on the stack */
2312   dtype = operandType (IC_LEFT (ic));
2313   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2314       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2315        !IFFUNC_ISISR (dtype))
2316   {
2317       swapBanks = TRUE;
2318   }
2319
2320   /* if caller saves & we have not saved then */
2321   if (!ic->regsSaved)
2322       saveRegisters (ic);
2323
2324   if (swapBanks)
2325   {
2326         emitcode ("mov", "psw,#0x%02x",
2327            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2328   }
2329
2330   /* make the call */
2331   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2332                             OP_SYMBOL (IC_LEFT (ic))->rname :
2333                             OP_SYMBOL (IC_LEFT (ic))->name));
2334
2335   if (swapBanks)
2336   {
2337        emitcode ("mov", "psw,#0x%02x",
2338           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2339   }
2340
2341   /* if we need assign a result value */
2342   if ((IS_ITEMP (IC_RESULT (ic)) &&
2343        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2344         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2345         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2346       IS_TRUE_SYMOP (IC_RESULT (ic)))
2347     {
2348
2349       _G.accInUse++;
2350       aopOp (IC_RESULT (ic), ic, FALSE);
2351       _G.accInUse--;
2352
2353       assignResultValue (IC_RESULT (ic));
2354
2355       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2356     }
2357
2358   /* adjust the stack for parameters if
2359      required */
2360   if (ic->parmBytes)
2361     {
2362       int i;
2363       if (ic->parmBytes > 3)
2364         {
2365           emitcode ("mov", "a,%s", spname);
2366           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2367           emitcode ("mov", "%s,a", spname);
2368         }
2369       else
2370         for (i = 0; i < ic->parmBytes; i++)
2371           emitcode ("dec", "%s", spname);
2372     }
2373
2374   /* if we hade saved some registers then unsave them */
2375   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2376     unsaveRegisters (ic);
2377
2378 //  /* if register bank was saved then pop them */
2379 //  if (restoreBank)
2380 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2381 }
2382
2383 /*-----------------------------------------------------------------*/
2384 /* -10l - generates a call by pointer statement                */
2385 /*-----------------------------------------------------------------*/
2386 static void
2387 genPcall (iCode * ic)
2388 {
2389   sym_link *dtype;
2390   symbol *rlbl = newiTempLabel (NULL);
2391 //  bool restoreBank=FALSE;
2392   bool swapBanks = FALSE;
2393
2394   D(emitcode(";     genPCall",""));
2395
2396   /* if caller saves & we have not saved then */
2397   if (!ic->regsSaved)
2398     saveRegisters (ic);
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))->next;
2404   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2405       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2406       !IFFUNC_ISISR (dtype))
2407   {
2408 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2409 //    restoreBank=TRUE;
2410       swapBanks = TRUE;
2411       // need caution message to user here
2412   }
2413
2414   /* push the return address on to the stack */
2415   emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2416   emitcode ("push", "acc");
2417   emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2418   emitcode ("push", "acc");
2419
2420   /* now push the calling address */
2421   aopOp (IC_LEFT (ic), ic, FALSE);
2422
2423   pushSide (IC_LEFT (ic), FPTRSIZE);
2424
2425   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2426
2427   /* if send set is not empty the assign */
2428   if (_G.sendSet)
2429     {
2430         genSend(reverseSet(_G.sendSet));
2431         _G.sendSet = NULL;
2432     }
2433
2434   if (swapBanks)
2435   {
2436         emitcode ("mov", "psw,#0x%02x",
2437            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2438   }
2439
2440   /* make the call */
2441   emitcode ("ret", "");
2442   emitcode ("", "%05d$:", (rlbl->key + 100));
2443
2444
2445   if (swapBanks)
2446   {
2447        emitcode ("mov", "psw,#0x%02x",
2448           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2449   }
2450
2451   /* if we need assign a result value */
2452   if ((IS_ITEMP (IC_RESULT (ic)) &&
2453        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2454         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2455       IS_TRUE_SYMOP (IC_RESULT (ic)))
2456     {
2457
2458       _G.accInUse++;
2459       aopOp (IC_RESULT (ic), ic, FALSE);
2460       _G.accInUse--;
2461
2462       assignResultValue (IC_RESULT (ic));
2463
2464       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2465     }
2466
2467   /* adjust the stack for parameters if
2468      required */
2469   if (ic->parmBytes)
2470     {
2471       int i;
2472       if (ic->parmBytes > 3)
2473         {
2474           emitcode ("mov", "a,%s", spname);
2475           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2476           emitcode ("mov", "%s,a", spname);
2477         }
2478       else
2479         for (i = 0; i < ic->parmBytes; i++)
2480           emitcode ("dec", "%s", spname);
2481
2482     }
2483
2484 //  /* if register bank was saved then unsave them */
2485 //  if (restoreBank)
2486 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2487
2488   /* if we hade saved some registers then
2489      unsave them */
2490   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2491     unsaveRegisters (ic);
2492 }
2493
2494 /*-----------------------------------------------------------------*/
2495 /* resultRemat - result  is rematerializable                       */
2496 /*-----------------------------------------------------------------*/
2497 static int
2498 resultRemat (iCode * ic)
2499 {
2500   if (SKIP_IC (ic) || ic->op == IFX)
2501     return 0;
2502
2503   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2504     {
2505       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2506       if (sym->remat && !POINTER_SET (ic))
2507         return 1;
2508     }
2509
2510   return 0;
2511 }
2512
2513 #if defined(__BORLANDC__) || defined(_MSC_VER)
2514 #define STRCASECMP stricmp
2515 #else
2516 #define STRCASECMP strcasecmp
2517 #endif
2518
2519 /*-----------------------------------------------------------------*/
2520 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2521 /*-----------------------------------------------------------------*/
2522 static int
2523 regsCmp(void *p1, void *p2)
2524 {
2525   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2526 }
2527
2528 static bool
2529 inExcludeList (char *s)
2530 {
2531   const char *p = setFirstItem(options.excludeRegsSet);
2532
2533   if (p == NULL || STRCASECMP(p, "none") == 0)
2534     return FALSE;
2535
2536
2537   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2538 }
2539
2540 /*-----------------------------------------------------------------*/
2541 /* genFunction - generated code for function entry                 */
2542 /*-----------------------------------------------------------------*/
2543 static void
2544 genFunction (iCode * ic)
2545 {
2546   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2547   sym_link *ftype;
2548   bool   switchedPSW = FALSE;
2549   int calleesaves_saved_register = -1;
2550   int stackAdjust = sym->stack;
2551   int accIsFree = sym->recvSize < 4;
2552   iCode * ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2553
2554   _G.nRegsSaved = 0;
2555   /* create the function header */
2556   emitcode (";", "-----------------------------------------");
2557   emitcode (";", " function %s", sym->name);
2558   emitcode (";", "-----------------------------------------");
2559
2560   emitcode ("", "%s:", sym->rname);
2561   ftype = operandType (IC_LEFT (ic));
2562   _G.currentFunc = sym;
2563
2564   if (IFFUNC_ISNAKED(ftype))
2565   {
2566       emitcode(";", "naked function: no prologue.");
2567       return;
2568   }
2569
2570   /* here we need to generate the equates for the
2571      register bank if required */
2572   if (FUNC_REGBANK (ftype) != rbank)
2573     {
2574       int i;
2575
2576       rbank = FUNC_REGBANK (ftype);
2577       for (i = 0; i < mcs51_nRegs; i++)
2578         {
2579           if (strcmp (regs8051[i].base, "0") == 0)
2580             emitcode ("", "%s = 0x%02x",
2581                       regs8051[i].dname,
2582                       8 * rbank + regs8051[i].offset);
2583           else
2584             emitcode ("", "%s = %s + 0x%02x",
2585                       regs8051[i].dname,
2586                       regs8051[i].base,
2587                       8 * rbank + regs8051[i].offset);
2588         }
2589     }
2590
2591   /* if this is an interrupt service routine then
2592      save acc, b, dpl, dph  */
2593   if (IFFUNC_ISISR (sym->type))
2594     {
2595
2596       if (!inExcludeList ("acc"))
2597         emitcode ("push", "acc");
2598       if (!inExcludeList ("b"))
2599         emitcode ("push", "b");
2600       if (!inExcludeList ("dpl"))
2601         emitcode ("push", "dpl");
2602       if (!inExcludeList ("dph"))
2603         emitcode ("push", "dph");
2604       /* if this isr has no bank i.e. is going to
2605          run with bank 0 , then we need to save more
2606          registers :-) */
2607       if (!FUNC_REGBANK (sym->type))
2608         {
2609
2610           /* if this function does not call any other
2611              function then we can be economical and
2612              save only those registers that are used */
2613           if (!IFFUNC_HASFCALL(sym->type))
2614             {
2615               int i;
2616
2617               /* if any registers used */
2618               if (sym->regsUsed)
2619                 {
2620                   /* save the registers used */
2621                   for (i = 0; i < sym->regsUsed->size; i++)
2622                     {
2623                       if (bitVectBitValue (sym->regsUsed, i))
2624                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2625                     }
2626                 }
2627             }
2628           else
2629             {
2630
2631               /* this function has a function call. We cannot
2632                  determines register usage so we will have to push the
2633                  entire bank */
2634                 saveRBank (0, ic, FALSE);
2635                 if (options.parms_in_bank1) {
2636                     int i;
2637                     for (i=0; i < 8 ; i++ ) {
2638                         emitcode ("push","%s",rb1regs[i]);
2639                     }
2640                 }
2641             }
2642         }
2643         else
2644         {
2645             /* This ISR uses a non-zero bank.
2646              *
2647              * We assume that the bank is available for our
2648              * exclusive use.
2649              *
2650              * However, if this ISR calls a function which uses some
2651              * other bank, we must save that bank entirely.
2652              */
2653             unsigned long banksToSave = 0;
2654
2655             if (IFFUNC_HASFCALL(sym->type))
2656             {
2657
2658 #define MAX_REGISTER_BANKS 4
2659
2660                 iCode *i;
2661                 int ix;
2662
2663                 for (i = ic; i; i = i->next)
2664                 {
2665                     if (i->op == ENDFUNCTION)
2666                     {
2667                         /* we got to the end OK. */
2668                         break;
2669                     }
2670
2671                     if (i->op == CALL)
2672                     {
2673                         sym_link *dtype;
2674
2675                         dtype = operandType (IC_LEFT(i));
2676                         if (dtype
2677                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2678                         {
2679                              /* Mark this bank for saving. */
2680                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2681                              {
2682                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2683                              }
2684                              else
2685                              {
2686                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2687                              }
2688
2689                              /* And note that we don't need to do it in
2690                               * genCall.
2691                               */
2692                              i->bankSaved = 1;
2693                         }
2694                     }
2695                     if (i->op == PCALL)
2696                     {
2697                         /* This is a mess; we have no idea what
2698                          * register bank the called function might
2699                          * use.
2700                          *
2701                          * The only thing I can think of to do is
2702                          * throw a warning and hope.
2703                          */
2704                         werror(W_FUNCPTR_IN_USING_ISR);
2705                     }
2706                 }
2707
2708                 if (banksToSave && options.useXstack)
2709                 {
2710                     /* Since we aren't passing it an ic,
2711                      * saveRBank will assume r0 is available to abuse.
2712                      *
2713                      * So switch to our (trashable) bank now, so
2714                      * the caller's R0 isn't trashed.
2715                      */
2716                     emitcode ("push", "psw");
2717                     emitcode ("mov", "psw,#0x%02x",
2718                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2719                     switchedPSW = TRUE;
2720                 }
2721
2722                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2723                 {
2724                      if (banksToSave & (1 << ix))
2725                      {
2726                          saveRBank(ix, NULL, FALSE);
2727                      }
2728                 }
2729             }
2730             // TODO: this needs a closer look
2731             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2732         }
2733
2734       /* Set the register bank to the desired value if nothing else */
2735       /* has done so yet. */
2736       if (!switchedPSW)
2737         {
2738           emitcode ("push", "psw");
2739           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2740         }
2741     }
2742   else
2743     {
2744       /* This is a non-ISR function. The caller has already switched register */
2745       /* banks, if necessary, so just handle the callee-saves option. */
2746
2747       /* if callee-save to be used for this function
2748          then save the registers being used in this function */
2749       if (IFFUNC_CALLEESAVES(sym->type))
2750         {
2751           int i;
2752
2753           /* if any registers used */
2754           if (sym->regsUsed)
2755             {
2756               /* save the registers used */
2757               for (i = 0; i < sym->regsUsed->size; i++)
2758                 {
2759                   if (bitVectBitValue (sym->regsUsed, i))
2760                     {
2761                       /* remember one saved register for later usage */
2762                       if (calleesaves_saved_register < 0)
2763                         calleesaves_saved_register = i;
2764                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2765                       _G.nRegsSaved++;
2766                     }
2767                 }
2768             }
2769         }
2770     }
2771
2772
2773   if (reentrant)
2774     {
2775       if (options.useXstack)
2776         {
2777               emitcode ("inc", "%s", spname);
2778               emitcode ("mov", "r0,%s", spname);
2779               emitcode ("xch", "a,_bp");
2780               emitcode ("movx", "@r0,a");
2781               emitcode ("mov", "a,r0");
2782               emitcode ("xch", "a,_bp");
2783         }
2784       else
2785         {
2786           /* set up the stack */
2787           emitcode ("push", "_bp");     /* save the callers stack  */
2788           emitcode ("mov", "_bp,%s", spname);
2789         }
2790     }
2791
2792   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2793   /* before setting up the stack frame completely. */
2794   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2795     {
2796       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2797
2798       if (rsym->isitmp)
2799         {
2800           if (rsym && rsym->regType == REG_CND)
2801             rsym = NULL;
2802           if (rsym && (rsym->accuse || rsym->ruonly))
2803             rsym = NULL;
2804           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2805             rsym = rsym->usl.spillLoc;
2806         }
2807
2808       /* If the RECEIVE operand immediately spills to the first entry on the */
2809       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2810       /* rather than the usual @r0/r1 machinations. */
2811       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2812         {
2813           int ofs;
2814
2815           _G.current_iCode = ric;
2816           D(emitcode (";     genReceive",""));
2817           for (ofs=0; ofs < sym->recvSize; ofs++)
2818             {
2819               if (!strcmp (fReturn[ofs], "a"))
2820                 emitcode ("push", "acc");
2821               else
2822                 emitcode ("push", fReturn[ofs]);
2823             }
2824           stackAdjust -= sym->recvSize;
2825           if (stackAdjust<0)
2826             {
2827               assert (stackAdjust>=0);
2828               stackAdjust = 0;
2829             }
2830           _G.current_iCode = ic;
2831           ric->generated = 1;
2832           accIsFree = 1;
2833         }
2834       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2835       /* to free up the accumulator. */
2836       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2837         {
2838           int ofs;
2839
2840           _G.current_iCode = ric;
2841           D(emitcode (";     genReceive",""));
2842           for (ofs=0; ofs < sym->recvSize; ofs++)
2843             {
2844               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2845             }
2846           _G.current_iCode = ic;
2847           ric->generated = 1;
2848           accIsFree = 1;
2849         }
2850     }
2851
2852   /* adjust the stack for the function */
2853   if (stackAdjust)
2854     {
2855       int i = stackAdjust;
2856       if (i > 256)
2857         werror (W_STACK_OVERFLOW, sym->name);
2858
2859       if (i > 3 && accIsFree)
2860         {
2861
2862           emitcode ("mov", "a,sp");
2863           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2864           emitcode ("mov", "sp,a");
2865
2866         }
2867       else if (i > 5)
2868         {
2869           /* The accumulator is not free, so we will need another register */
2870           /* to clobber. No need to worry about a possible conflict with */
2871           /* the above early RECEIVE optimizations since they would have */
2872           /* freed the accumulator if they were generated. */
2873
2874           if (IFFUNC_CALLEESAVES(sym->type))
2875             {
2876               /* if it's a callee-saves function we need a saved register */
2877               if (calleesaves_saved_register >= 0)
2878                 {
2879                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2880                   emitcode ("mov", "a,sp");
2881                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2882                   emitcode ("mov", "sp,a");
2883                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2884                 }
2885               else
2886                 /* do it the hard way */
2887                 while (i--)
2888                   emitcode ("inc", "sp");
2889             }
2890           else
2891             {
2892               /* not callee-saves, we can clobber r0 */
2893               emitcode ("mov", "r0,a");
2894               emitcode ("mov", "a,sp");
2895               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2896               emitcode ("mov", "sp,a");
2897               emitcode ("mov", "a,r0");
2898             }
2899         }
2900       else
2901         while (i--)
2902           emitcode ("inc", "sp");
2903     }
2904
2905   if (sym->xstack)
2906     {
2907
2908       if (!accIsFree)
2909         emitcode ("push", "acc");
2910       emitcode ("mov", "a,_spx");
2911       emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
2912       emitcode ("mov", "_spx,a");
2913       if (!accIsFree)
2914         emitcode ("pop", "acc");
2915     }
2916
2917   /* if critical function then turn interrupts off */
2918   if (IFFUNC_ISCRITICAL (ftype))
2919     {
2920       symbol *tlbl = newiTempLabel (NULL);
2921       emitcode ("setb", "c");
2922       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
2923       emitcode ("clr", "c");
2924       emitcode ("", "%05d$:", (tlbl->key + 100));
2925       emitcode ("push", "psw"); /* save old ea via c in psw */
2926     }
2927 }
2928
2929 /*-----------------------------------------------------------------*/
2930 /* genEndFunction - generates epilogue for functions               */
2931 /*-----------------------------------------------------------------*/
2932 static void
2933 genEndFunction (iCode * ic)
2934 {
2935   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
2936   lineNode *lnp = lineCurr;
2937   bitVect  *regsUsed;
2938   bitVect  *regsUsedPrologue;
2939   bitVect  *regsUnneeded;
2940   int      accIsFree = sym->recvSize < 4;
2941   int      idx;
2942
2943   _G.currentFunc = NULL;
2944   if (IFFUNC_ISNAKED(sym->type))
2945   {
2946       emitcode(";", "naked function: no epilogue.");
2947       if (options.debug && currFunc)
2948         debugFile->writeEndFunction (currFunc, ic, 0);
2949       return;
2950   }
2951
2952   if (IFFUNC_ISCRITICAL (sym->type))
2953     {
2954       emitcode ("pop", "psw"); /* restore ea via c in psw */
2955       emitcode ("mov", "ea,c");
2956     }
2957
2958   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2959     {
2960       emitcode ("mov", "%s,_bp", spname);
2961     }
2962
2963   /* if use external stack but some variables were
2964      added to the local stack then decrement the
2965      local stack */
2966   if (options.useXstack && sym->stack)
2967     {
2968       if (!accIsFree)
2969         emitcode ("push", "acc");
2970       emitcode ("mov", "a,sp");
2971       emitcode ("add", "a,#0x%02x", ((char) -sym->stack) & 0xff);
2972       emitcode ("mov", "sp,a");
2973       if (!accIsFree)
2974         emitcode ("pop", "acc");
2975     }
2976
2977   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
2978     {
2979       if (options.useXstack)
2980         {
2981           emitcode ("xch", "a,_bp");
2982           emitcode ("mov", "r0,%s", spname);
2983           emitcode ("movx", "a,@r0");
2984           emitcode ("xch", "a,_bp");
2985           emitcode ("dec", "%s", spname); //read before freeing stack space (interrupts)
2986         }
2987       else
2988         {
2989           emitcode ("pop", "_bp");
2990         }
2991     }
2992
2993   /* restore the register bank  */
2994   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
2995   {
2996     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
2997      || !options.useXstack)
2998     {
2999         /* Special case of ISR using non-zero bank with useXstack
3000          * is handled below.
3001          */
3002         emitcode ("pop", "psw");
3003     }
3004   }
3005
3006   if (IFFUNC_ISISR (sym->type))
3007     {
3008
3009       /* now we need to restore the registers */
3010       /* if this isr has no bank i.e. is going to
3011          run with bank 0 , then we need to save more
3012          registers :-) */
3013       if (!FUNC_REGBANK (sym->type))
3014         {
3015           /* if this function does not call any other
3016              function then we can be economical and
3017              save only those registers that are used */
3018           if (!IFFUNC_HASFCALL(sym->type))
3019             {
3020               int i;
3021
3022               /* if any registers used */
3023               if (sym->regsUsed)
3024                 {
3025                   /* save the registers used */
3026                   for (i = sym->regsUsed->size; i >= 0; i--)
3027                     {
3028                       if (bitVectBitValue (sym->regsUsed, i))
3029                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3030                     }
3031                 }
3032             }
3033           else
3034             {
3035               if (options.parms_in_bank1) {
3036                   int i;
3037                   for (i = 7 ; i >= 0 ; i-- ) {
3038                       emitcode ("pop","%s",rb1regs[i]);
3039                   }
3040               }
3041               /* this function has  a function call cannot
3042                  determines register usage so we will have to pop the
3043                  entire bank */
3044               unsaveRBank (0, ic, FALSE);
3045             }
3046         }
3047         else
3048         {
3049             /* This ISR uses a non-zero bank.
3050              *
3051              * Restore any register banks saved by genFunction
3052              * in reverse order.
3053              */
3054             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3055             int ix;
3056
3057             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3058             {
3059                 if (savedBanks & (1 << ix))
3060                 {
3061                     unsaveRBank(ix, NULL, FALSE);
3062                 }
3063             }
3064
3065             if (options.useXstack)
3066             {
3067                 /* Restore bank AFTER calling unsaveRBank,
3068                  * since it can trash r0.
3069                  */
3070                 emitcode ("pop", "psw");
3071             }
3072         }
3073
3074       if (!inExcludeList ("dph"))
3075         emitcode ("pop", "dph");
3076       if (!inExcludeList ("dpl"))
3077         emitcode ("pop", "dpl");
3078       if (!inExcludeList ("b"))
3079         emitcode ("pop", "b");
3080       if (!inExcludeList ("acc"))
3081         emitcode ("pop", "acc");
3082
3083       /* if debug then send end of function */
3084       if (options.debug && currFunc)
3085         {
3086           debugFile->writeEndFunction (currFunc, ic, 1);
3087         }
3088
3089       emitcode ("reti", "");
3090     }
3091   else
3092     {
3093       if (IFFUNC_CALLEESAVES(sym->type))
3094         {
3095           int i;
3096
3097           /* if any registers used */
3098           if (sym->regsUsed)
3099             {
3100               /* save the registers used */
3101               for (i = sym->regsUsed->size; i >= 0; i--)
3102                 {
3103                   if (bitVectBitValue (sym->regsUsed, i) ||
3104                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3105                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3106                 }
3107             }
3108           else if (mcs51_ptrRegReq)
3109             {
3110               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3111               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3112             }
3113
3114         }
3115
3116       /* if debug then send end of function */
3117       if (options.debug && currFunc)
3118         {
3119           debugFile->writeEndFunction (currFunc, ic, 1);
3120         }
3121
3122       emitcode ("ret", "");
3123     }
3124
3125   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3126     return;
3127
3128   /* If this was an interrupt handler using bank 0 that called another */
3129   /* function, then all registers must be saved; nothing to optimized. */
3130   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3131       && !FUNC_REGBANK(sym->type))
3132     return;
3133
3134   /* There are no push/pops to optimize if not callee-saves or ISR */
3135   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3136     return;
3137
3138   /* If there were stack parameters, we cannot optimize without also    */
3139   /* fixing all of the stack offsets; this is too dificult to consider. */
3140   if (FUNC_HASSTACKPARM(sym->type))
3141     return;
3142
3143   /* Compute the registers actually used */
3144   regsUsed = newBitVect (mcs51_nRegs);
3145   regsUsedPrologue = newBitVect (mcs51_nRegs);
3146   while (lnp)
3147     {
3148       if (lnp->ic && lnp->ic->op == FUNCTION)
3149         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3150       else
3151         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3152
3153       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3154           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3155         break;
3156       if (!lnp->prev)
3157         break;
3158       lnp = lnp->prev;
3159     }
3160
3161   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3162       && !bitVectBitValue (regsUsed, CND_IDX))
3163     {
3164       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3165       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3166           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3167         bitVectUnSetBit (regsUsed, CND_IDX);
3168     }
3169   else
3170     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3171
3172   /* If this was an interrupt handler that called another function */
3173   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3174   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3175     {
3176       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3177       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3178       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3179       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3180       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3181     }
3182
3183   /* Remove the unneeded push/pops */
3184   regsUnneeded = newBitVect (mcs51_nRegs);
3185   while (lnp)
3186     {
3187       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3188         {
3189           if (!strncmp(lnp->line, "push", 4))
3190             {
3191               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3192               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3193                 {
3194                   connectLine (lnp->prev, lnp->next);
3195                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3196                 }
3197             }
3198           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3199             {
3200               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3201               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3202                 {
3203                   connectLine (lnp->prev, lnp->next);
3204                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3205                 }
3206             }
3207         }
3208       lnp = lnp->next;
3209     }
3210
3211   for (idx = 0; idx < regsUnneeded->size; idx++)
3212     if (bitVectBitValue (regsUnneeded, idx))
3213       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3214
3215   freeBitVect (regsUnneeded);
3216   freeBitVect (regsUsed);
3217   freeBitVect (regsUsedPrologue);
3218 }
3219
3220 /*-----------------------------------------------------------------*/
3221 /* genRet - generate code for return statement                     */
3222 /*-----------------------------------------------------------------*/
3223 static void
3224 genRet (iCode * ic)
3225 {
3226   int size, offset = 0, pushed = 0;
3227
3228   D(emitcode (";     genRet",""));
3229
3230   /* if we have no return value then
3231      just generate the "ret" */
3232   if (!IC_LEFT (ic))
3233     goto jumpret;
3234
3235   /* we have something to return then
3236      move the return value into place */
3237   aopOp (IC_LEFT (ic), ic, FALSE);
3238   size = AOP_SIZE (IC_LEFT (ic));
3239
3240   while (size--)
3241     {
3242       char *l;
3243       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3244         {
3245           /* #NOCHANGE */
3246           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3247                       FALSE, TRUE);
3248           emitcode ("push", "%s", l);
3249           pushed++;
3250         }
3251       else
3252         {
3253           l = aopGet (AOP (IC_LEFT (ic)), offset,
3254                       FALSE, FALSE);
3255           if (strcmp (fReturn[offset], l))
3256             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3257         }
3258     }
3259
3260   if (pushed)
3261     {
3262       while (pushed)
3263         {
3264           pushed--;
3265           if (strcmp (fReturn[pushed], "a"))
3266             emitcode ("pop", fReturn[pushed]);
3267           else
3268             emitcode ("pop", "acc");
3269         }
3270     }
3271   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3272
3273 jumpret:
3274   /* generate a jump to the return label
3275      if the next is not the return statement */
3276   if (!(ic->next && ic->next->op == LABEL &&
3277         IC_LABEL (ic->next) == returnLabel))
3278
3279     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3280
3281 }
3282
3283 /*-----------------------------------------------------------------*/
3284 /* genLabel - generates a label                                    */
3285 /*-----------------------------------------------------------------*/
3286 static void
3287 genLabel (iCode * ic)
3288 {
3289   /* special case never generate */
3290   if (IC_LABEL (ic) == entryLabel)
3291     return;
3292
3293   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3294 }
3295
3296 /*-----------------------------------------------------------------*/
3297 /* genGoto - generates a ljmp                                      */
3298 /*-----------------------------------------------------------------*/
3299 static void
3300 genGoto (iCode * ic)
3301 {
3302   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3303 }
3304
3305 /*-----------------------------------------------------------------*/
3306 /* findLabelBackwards: walks back through the iCode chain looking  */
3307 /* for the given label. Returns number of iCode instructions     */
3308 /* between that label and given ic.          */
3309 /* Returns zero if label not found.          */
3310 /*-----------------------------------------------------------------*/
3311 static int
3312 findLabelBackwards (iCode * ic, int key)
3313 {
3314   int count = 0;
3315
3316   while (ic->prev)
3317     {
3318       ic = ic->prev;
3319       count++;
3320
3321       /* If we have any pushes or pops, we cannot predict the distance.
3322          I don't like this at all, this should be dealt with in the
3323          back-end */
3324       if (ic->op == IPUSH || ic->op == IPOP) {
3325         return 0;
3326       }
3327
3328       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3329         {
3330           return count;
3331         }
3332     }
3333
3334   return 0;
3335 }
3336
3337 /*-----------------------------------------------------------------*/
3338 /* genPlusIncr :- does addition with increment if possible         */
3339 /*-----------------------------------------------------------------*/
3340 static bool
3341 genPlusIncr (iCode * ic)
3342 {
3343   unsigned int icount;
3344   unsigned int size = getDataSize (IC_RESULT (ic));
3345
3346   /* will try to generate an increment */
3347   /* if the right side is not a literal
3348      we cannot */
3349   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3350     return FALSE;
3351
3352   /* if the literal value of the right hand side
3353      is greater than 4 then it is not worth it */
3354   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3355     return FALSE;
3356
3357   D(emitcode (";     genPlusIncr",""));
3358
3359   /* if increment >=16 bits in register or direct space */
3360   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3361       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3362       (size > 1) &&
3363       (icount == 1))
3364     {
3365       symbol *tlbl;
3366       int emitTlbl;
3367       int labelRange;
3368
3369       /* If the next instruction is a goto and the goto target
3370        * is < 10 instructions previous to this, we can generate
3371        * jumps straight to that target.
3372        */
3373       if (ic->next && ic->next->op == GOTO
3374           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3375           && labelRange <= 10)
3376         {
3377           emitcode (";", "tail increment optimized");
3378           tlbl = IC_LABEL (ic->next);
3379           emitTlbl = 0;
3380         }
3381       else
3382         {
3383           tlbl = newiTempLabel (NULL);
3384           emitTlbl = 1;
3385         }
3386       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3387       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3388           IS_AOP_PREG (IC_RESULT (ic)))
3389         emitcode ("cjne", "%s,#0x00,%05d$",
3390                   aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3391                   tlbl->key + 100);
3392       else
3393         {
3394           emitcode ("clr", "a");
3395           emitcode ("cjne", "a,%s,%05d$",
3396                     aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3397                     tlbl->key + 100);
3398         }
3399
3400       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3401       if (size > 2)
3402         {
3403           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3404               IS_AOP_PREG (IC_RESULT (ic)))
3405             emitcode ("cjne", "%s,#0x00,%05d$",
3406                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3407                       tlbl->key + 100);
3408           else
3409             emitcode ("cjne", "a,%s,%05d$",
3410                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3411                       tlbl->key + 100);
3412
3413           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3414         }
3415       if (size > 3)
3416         {
3417           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3418               IS_AOP_PREG (IC_RESULT (ic)))
3419             emitcode ("cjne", "%s,#0x00,%05d$",
3420                       aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3421                       tlbl->key + 100);
3422           else
3423             {
3424               emitcode ("cjne", "a,%s,%05d$",
3425                         aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3426                         tlbl->key + 100);
3427             }
3428           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3429         }
3430
3431       if (emitTlbl)
3432         {
3433           emitcode ("", "%05d$:", tlbl->key + 100);
3434         }
3435       return TRUE;
3436     }
3437
3438   /* if the sizes are greater than 1 then we cannot */
3439   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3440       AOP_SIZE (IC_LEFT (ic)) > 1)
3441     return FALSE;
3442
3443   /* we can if the aops of the left & result match or
3444      if they are in registers and the registers are the
3445      same */
3446   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3447     {
3448
3449       if (icount > 3)
3450         {
3451           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3452           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3453           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3454         }
3455       else
3456         {
3457
3458           while (icount--)
3459             emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3460         }
3461
3462       return TRUE;
3463     }
3464
3465   return FALSE;
3466 }
3467
3468 /*-----------------------------------------------------------------*/
3469 /* outBitAcc - output a bit in acc                                 */
3470 /*-----------------------------------------------------------------*/
3471 static void
3472 outBitAcc (operand * result)
3473 {
3474   symbol *tlbl = newiTempLabel (NULL);
3475   /* if the result is a bit */
3476   if (AOP_TYPE (result) == AOP_CRY)
3477     {
3478       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3479     }
3480   else
3481     {
3482       emitcode ("jz", "%05d$", tlbl->key + 100);
3483       emitcode ("mov", "a,%s", one);
3484       emitcode ("", "%05d$:", tlbl->key + 100);
3485       outAcc (result);
3486     }
3487 }
3488
3489 /*-----------------------------------------------------------------*/
3490 /* genPlusBits - generates code for addition of two bits           */
3491 /*-----------------------------------------------------------------*/
3492 static void
3493 genPlusBits (iCode * ic)
3494 {
3495   D(emitcode (";     genPlusBits",""));
3496
3497   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3498     {
3499       symbol *lbl = newiTempLabel (NULL);
3500       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3501       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3502       emitcode ("cpl", "c");
3503       emitcode ("", "%05d$:", (lbl->key + 100));
3504       outBitC (IC_RESULT (ic));
3505     }
3506   else
3507     {
3508       emitcode ("clr", "a");
3509       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3510       emitcode ("rlc", "a");
3511       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3512       emitcode ("addc", "a,#0x00");
3513       outAcc (IC_RESULT (ic));
3514     }
3515 }
3516
3517 #if 0
3518 /* This is the original version of this code.
3519
3520  * This is being kept around for reference,
3521  * because I am not entirely sure I got it right...
3522  */
3523 static void
3524 adjustArithmeticResult (iCode * ic)
3525 {
3526   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3527       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3528       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3529     aopPut (AOP (IC_RESULT (ic)),
3530             aopGet (AOP (IC_LEFT (ic)), 2, FALSE, FALSE),
3531             2,
3532             isOperandVolatile (IC_RESULT (ic), FALSE));
3533
3534   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3535       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3536       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3537     aopPut (AOP (IC_RESULT (ic)),
3538             aopGet (AOP (IC_RIGHT (ic)), 2, FALSE, FALSE),
3539             2,
3540             isOperandVolatile (IC_RESULT (ic), FALSE));
3541
3542   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3543       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3544       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3545       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3546       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3547     {
3548       char buffer[5];
3549       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3550       aopPut (AOP (IC_RESULT (ic)), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3551     }
3552 }
3553 #else
3554 /* This is the pure and virtuous version of this code.
3555  * I'm pretty certain it's right, but not enough to toss the old
3556  * code just yet...
3557  */
3558 static void
3559 adjustArithmeticResult (iCode * ic)
3560 {
3561   if (opIsGptr (IC_RESULT (ic)) &&
3562       opIsGptr (IC_LEFT (ic)) &&
3563       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3564     {
3565       aopPut (AOP (IC_RESULT (ic)),
3566               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3567               GPTRSIZE - 1,
3568               isOperandVolatile (IC_RESULT (ic), FALSE));
3569     }
3570
3571   if (opIsGptr (IC_RESULT (ic)) &&
3572       opIsGptr (IC_RIGHT (ic)) &&
3573       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3574     {
3575       aopPut (AOP (IC_RESULT (ic)),
3576               aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3577               GPTRSIZE - 1,
3578               isOperandVolatile (IC_RESULT (ic), FALSE));
3579     }
3580
3581   if (opIsGptr (IC_RESULT (ic)) &&
3582       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3583       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3584       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3585       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3586     {
3587       char buffer[5];
3588       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3589       aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3590     }
3591 }
3592 #endif
3593
3594 /*-----------------------------------------------------------------*/
3595 /* genPlus - generates code for addition                           */
3596 /*-----------------------------------------------------------------*/
3597 static void
3598 genPlus (iCode * ic)
3599 {
3600   int size, offset = 0;
3601   int skip_bytes = 0;
3602   char *add = "add";
3603   asmop *leftOp, *rightOp;
3604   operand * op;
3605
3606   /* special cases :- */
3607
3608   D(emitcode (";     genPlus",""));
3609
3610   aopOp (IC_LEFT (ic), ic, FALSE);
3611   aopOp (IC_RIGHT (ic), ic, FALSE);
3612   aopOp (IC_RESULT (ic), ic, TRUE);
3613
3614   /* if literal, literal on the right or
3615      if left requires ACC or right is already
3616      in ACC */
3617   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3618       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3619       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3620     {
3621       operand *t = IC_RIGHT (ic);
3622       IC_RIGHT (ic) = IC_LEFT (ic);
3623       IC_LEFT (ic) = t;
3624     }
3625
3626   /* if both left & right are in bit
3627      space */
3628   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3629       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3630     {
3631       genPlusBits (ic);
3632       goto release;
3633     }
3634
3635   /* if left in bit space & right literal */
3636   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3637       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3638     {
3639       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3640       /* if result in bit space */
3641       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3642         {
3643           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3644             emitcode ("cpl", "c");
3645           outBitC (IC_RESULT (ic));
3646         }
3647       else
3648         {
3649           size = getDataSize (IC_RESULT (ic));
3650           while (size--)
3651             {
3652               MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE));
3653               emitcode ("addc", "a,#00");
3654               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3655             }
3656         }
3657       goto release;
3658     }
3659
3660   /* if I can do an increment instead
3661      of add then GOOD for ME */
3662   if (genPlusIncr (ic) == TRUE)
3663     goto release;
3664
3665   size = getDataSize (IC_RESULT (ic));
3666   leftOp = AOP(IC_LEFT(ic));
3667   rightOp = AOP(IC_RIGHT(ic));
3668   op=IC_LEFT(ic);
3669
3670   /* if this is an add for an array access
3671      at a 256 byte boundary */
3672   if ( 2 == size
3673        && AOP_TYPE (op) == AOP_IMMD
3674        && IS_SYMOP (op)
3675        && IS_SPEC (OP_SYM_ETYPE (op))
3676        && SPEC_ABSA (OP_SYM_ETYPE (op))
3677        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3678      )
3679     {
3680       D(emitcode (";     genPlus aligned array",""));
3681       aopPut (AOP (IC_RESULT (ic)),
3682               aopGet (rightOp, 0, FALSE, FALSE),
3683               0,
3684               isOperandVolatile (IC_RESULT (ic), FALSE));
3685
3686       if( 1 == getDataSize (IC_RIGHT (ic)) )
3687         {
3688           aopPut (AOP (IC_RESULT (ic)),
3689                   aopGet (leftOp, 1, FALSE, FALSE),
3690                   1,
3691                   isOperandVolatile (IC_RESULT (ic), FALSE));
3692         }
3693       else
3694         {
3695           MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
3696           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3697           aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3698         }
3699       goto release;
3700     }
3701
3702   /* if the lower bytes of a literal are zero skip the addition */
3703   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3704     {
3705        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3706               (skip_bytes+1 < size))
3707          {
3708            skip_bytes++;
3709          }
3710        if (skip_bytes)
3711          D(emitcode (";     genPlus shortcut",""));
3712     }
3713
3714   while (size--)
3715     {
3716       if( offset >= skip_bytes )
3717         {
3718           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3719             {
3720               bool pushedB;
3721               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3722               pushedB = pushB ();
3723               emitcode("xch", "a,b");
3724               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3725               emitcode (add, "a,b");
3726               popB (pushedB);
3727             }
3728           else if (aopGetUsesAcc (leftOp, offset))
3729             {
3730               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3731               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3732             }
3733           else
3734             {
3735               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3736               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3737             }
3738           aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3739           add = "addc";  /* further adds must propagate carry */
3740         }
3741       else
3742         {
3743           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3744               isOperandVolatile (IC_RESULT (ic), FALSE))
3745             {
3746               /* just move */
3747               aopPut (AOP (IC_RESULT (ic)),
3748                       aopGet (leftOp, offset, FALSE, FALSE),
3749                       offset,
3750                       isOperandVolatile (IC_RESULT (ic), FALSE));
3751             }
3752         }
3753       offset++;
3754     }
3755
3756   adjustArithmeticResult (ic);
3757
3758 release:
3759   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3760   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3761   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3762 }
3763
3764 /*-----------------------------------------------------------------*/
3765 /* genMinusDec :- does subtraction with deccrement if possible     */
3766 /*-----------------------------------------------------------------*/
3767 static bool
3768 genMinusDec (iCode * ic)
3769 {
3770   unsigned int icount;
3771   unsigned int size = getDataSize (IC_RESULT (ic));
3772
3773   /* will try to generate an increment */
3774   /* if the right side is not a literal
3775      we cannot */
3776   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3777     return FALSE;
3778
3779   /* if the literal value of the right hand side
3780      is greater than 4 then it is not worth it */
3781   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3782     return FALSE;
3783
3784   D(emitcode (";     genMinusDec",""));
3785
3786   /* if decrement >=16 bits in register or direct space */
3787   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3788       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3789       (size > 1) &&
3790       (icount == 1))
3791     {
3792       symbol *tlbl;
3793       int emitTlbl;
3794       int labelRange;
3795
3796       /* If the next instruction is a goto and the goto target
3797        * is <= 10 instructions previous to this, we can generate
3798        * jumps straight to that target.
3799        */
3800       if (ic->next && ic->next->op == GOTO
3801           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3802           && labelRange <= 10)
3803         {
3804           emitcode (";", "tail decrement optimized");
3805           tlbl = IC_LABEL (ic->next);
3806           emitTlbl = 0;
3807         }
3808       else
3809         {
3810           tlbl = newiTempLabel (NULL);
3811           emitTlbl = 1;
3812         }
3813
3814       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3815       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3816           IS_AOP_PREG (IC_RESULT (ic)))
3817         emitcode ("cjne", "%s,#0xff,%05d$"
3818                   ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3819                   ,tlbl->key + 100);
3820       else
3821         {
3822           emitcode ("mov", "a,#0xff");
3823           emitcode ("cjne", "a,%s,%05d$"
3824                     ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3825                     ,tlbl->key + 100);
3826         }
3827       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3828       if (size > 2)
3829         {
3830           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3831               IS_AOP_PREG (IC_RESULT (ic)))
3832             emitcode ("cjne", "%s,#0xff,%05d$"
3833                       ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3834                       ,tlbl->key + 100);
3835           else
3836             {
3837               emitcode ("cjne", "a,%s,%05d$"
3838                         ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3839                         ,tlbl->key + 100);
3840             }
3841           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3842         }
3843       if (size > 3)
3844         {
3845           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3846               IS_AOP_PREG (IC_RESULT (ic)))
3847             emitcode ("cjne", "%s,#0xff,%05d$"
3848                       ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3849                       ,tlbl->key + 100);
3850           else
3851             {
3852               emitcode ("cjne", "a,%s,%05d$"
3853                         ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3854                         ,tlbl->key + 100);
3855             }
3856           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3857         }
3858       if (emitTlbl)
3859         {
3860           emitcode ("", "%05d$:", tlbl->key + 100);
3861         }
3862       return TRUE;
3863     }
3864
3865   /* if the sizes are greater than 1 then we cannot */
3866   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3867       AOP_SIZE (IC_LEFT (ic)) > 1)
3868     return FALSE;
3869
3870   /* we can if the aops of the left & result match or
3871      if they are in registers and the registers are the
3872      same */
3873   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3874     {
3875
3876       while (icount--)
3877         emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
3878
3879       return TRUE;
3880     }
3881
3882   return FALSE;
3883 }
3884
3885 /*-----------------------------------------------------------------*/
3886 /* addSign - complete with sign                                    */
3887 /*-----------------------------------------------------------------*/
3888 static void
3889 addSign (operand * result, int offset, int sign)
3890 {
3891   int size = (getDataSize (result) - offset);
3892   if (size > 0)
3893     {
3894       if (sign)
3895         {
3896           emitcode ("rlc", "a");
3897           emitcode ("subb", "a,acc");
3898           while (size--)
3899             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
3900         }
3901       else
3902         while (size--)
3903           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
3904     }
3905 }
3906
3907 /*-----------------------------------------------------------------*/
3908 /* genMinusBits - generates code for subtraction  of two bits      */
3909 /*-----------------------------------------------------------------*/
3910 static void
3911 genMinusBits (iCode * ic)
3912 {
3913   symbol *lbl = newiTempLabel (NULL);
3914
3915   D(emitcode (";     genMinusBits",""));
3916
3917   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3918     {
3919       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3920       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3921       emitcode ("cpl", "c");
3922       emitcode ("", "%05d$:", (lbl->key + 100));
3923       outBitC (IC_RESULT (ic));
3924     }
3925   else
3926     {
3927       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3928       emitcode ("subb", "a,acc");
3929       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
3930       emitcode ("inc", "a");
3931       emitcode ("", "%05d$:", (lbl->key + 100));
3932       aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3933       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
3934     }
3935 }
3936
3937 /*-----------------------------------------------------------------*/
3938 /* genMinus - generates code for subtraction                       */
3939 /*-----------------------------------------------------------------*/
3940 static void
3941 genMinus (iCode * ic)
3942 {
3943   int size, offset = 0;
3944
3945   D(emitcode (";     genMinus",""));
3946
3947   aopOp (IC_LEFT (ic), ic, FALSE);
3948   aopOp (IC_RIGHT (ic), ic, FALSE);
3949   aopOp (IC_RESULT (ic), ic, TRUE);
3950
3951   /* special cases :- */
3952   /* if both left & right are in bit space */
3953   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3954       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3955     {
3956       genMinusBits (ic);
3957       goto release;
3958     }
3959
3960   /* if I can do an decrement instead
3961      of subtract then GOOD for ME */
3962   if (genMinusDec (ic) == TRUE)
3963     goto release;
3964
3965   size = getDataSize (IC_RESULT (ic));
3966
3967   /* if literal, add a,#-lit, else normal subb */
3968   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3969     {
3970       unsigned long lit = 0L;
3971
3972       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3973       lit = -(long) lit;
3974
3975       while (size--)
3976         {
3977           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE));
3978           /* first add without previous c */
3979           if (!offset) {
3980             if (!size && lit== (unsigned long) -1) {
3981               emitcode ("dec", "a");
3982             } else {
3983               emitcode ("add", "a,#0x%02x",
3984                         (unsigned int) (lit & 0x0FFL));
3985             }
3986           } else {
3987             emitcode ("addc", "a,#0x%02x",
3988                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3989           }
3990           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3991         }
3992     }
3993   else
3994     {
3995       asmop *leftOp, *rightOp;
3996
3997       leftOp = AOP(IC_LEFT(ic));
3998       rightOp = AOP(IC_RIGHT(ic));
3999
4000       while (size--)
4001         {
4002           if (aopGetUsesAcc(rightOp, offset)) {
4003             if (aopGetUsesAcc(leftOp, offset)) {
4004               bool pushedB;
4005
4006               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4007               pushedB = pushB ();
4008               emitcode ("mov", "b,a");
4009               if (offset == 0)
4010                 CLRC;
4011               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4012               emitcode ("subb", "a,b");
4013               popB (pushedB);
4014             } else {
4015               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4016               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4017               if (offset == 0) {
4018                 emitcode( "setb", "c");
4019               }
4020               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4021               emitcode("cpl", "a");
4022             }
4023           } else {
4024             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4025             if (offset == 0)
4026               CLRC;
4027             emitcode ("subb", "a,%s",
4028                       aopGet(rightOp, offset, FALSE, TRUE));
4029           }
4030
4031           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4032         }
4033     }
4034
4035
4036   adjustArithmeticResult (ic);
4037
4038 release:
4039   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4040   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4041   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4042 }
4043
4044
4045 /*-----------------------------------------------------------------*/
4046 /* genMultbits :- multiplication of bits                           */
4047 /*-----------------------------------------------------------------*/
4048 static void
4049 genMultbits (operand * left,
4050              operand * right,
4051              operand * result)
4052 {
4053   D(emitcode (";     genMultbits",""));
4054
4055   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4056   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4057   outBitC (result);
4058 }
4059
4060 /*-----------------------------------------------------------------*/
4061 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4062 /*-----------------------------------------------------------------*/
4063 static void
4064 genMultOneByte (operand * left,
4065                 operand * right,
4066                 operand * result)
4067 {
4068   symbol *lbl;
4069   int size = AOP_SIZE (result);
4070   bool runtimeSign, compiletimeSign;
4071   bool lUnsigned, rUnsigned, pushedB;
4072
4073   D(emitcode (";     genMultOneByte",""));
4074
4075   if (size < 1 || size > 2)
4076     {
4077       /* this should never happen */
4078       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4079                AOP_SIZE(result), __FILE__, lineno);
4080       exit (1);
4081     }
4082
4083   /* (if two literals: the value is computed before) */
4084   /* if one literal, literal on the right */
4085   if (AOP_TYPE (left) == AOP_LIT)
4086     {
4087       operand *t = right;
4088       right = left;
4089       left = t;
4090       /* emitcode (";", "swapped left and right"); */
4091     }
4092   /* if no literal, unsigned on the right: shorter code */
4093   if (   AOP_TYPE (right) != AOP_LIT
4094       && SPEC_USIGN (getSpec (operandType (left))))
4095     {
4096       operand *t = right;
4097       right = left;
4098       left = t;
4099     }
4100
4101   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4102   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4103
4104   pushedB = pushB ();
4105
4106   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4107                    no need to take care about the signedness! */
4108       || (lUnsigned && rUnsigned))
4109     {
4110       /* just an unsigned 8 * 8 = 8 multiply
4111          or 8u * 8u = 16u */
4112       /* emitcode (";","unsigned"); */
4113       /* TODO: check for accumulator clash between left & right aops? */
4114
4115       if (AOP_TYPE (right) == AOP_LIT)
4116         {
4117           /* moving to accumulator first helps peepholes */
4118           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4119           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4120         }
4121       else
4122         {
4123           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4124           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4125         }
4126
4127       emitcode ("mul", "ab");
4128       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4129       if (size == 2)
4130         aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4131
4132       popB (pushedB);
4133       return;
4134     }
4135
4136   /* we have to do a signed multiply */
4137   /* emitcode (";", "signed"); */
4138
4139   /* now sign adjust for both left & right */
4140
4141   /* let's see what's needed: */
4142   /* apply negative sign during runtime */
4143   runtimeSign = FALSE;
4144   /* negative sign from literals */
4145   compiletimeSign = FALSE;
4146
4147   if (!lUnsigned)
4148     {
4149       if (AOP_TYPE(left) == AOP_LIT)
4150         {
4151           /* signed literal */
4152           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4153           if (val < 0)
4154             compiletimeSign = TRUE;
4155         }
4156       else
4157         /* signed but not literal */
4158         runtimeSign = TRUE;
4159     }
4160
4161   if (!rUnsigned)
4162     {
4163       if (AOP_TYPE(right) == AOP_LIT)
4164         {
4165           /* signed literal */
4166           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4167           if (val < 0)
4168             compiletimeSign ^= TRUE;
4169         }
4170       else
4171         /* signed but not literal */
4172         runtimeSign = TRUE;
4173     }
4174
4175   /* initialize F0, which stores the runtime sign */
4176   if (runtimeSign)
4177     {
4178       if (compiletimeSign)
4179         emitcode ("setb", "F0"); /* set sign flag */
4180       else
4181         emitcode ("clr", "F0"); /* reset sign flag */
4182     }
4183
4184   /* save the signs of the operands */
4185   if (AOP_TYPE(right) == AOP_LIT)
4186     {
4187       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4188
4189       if (!rUnsigned && val < 0)
4190         emitcode ("mov", "b,#0x%02x", -val);
4191       else
4192         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4193     }
4194   else /* ! literal */
4195     {
4196       if (rUnsigned)  /* emitcode (";", "signed"); */
4197
4198         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4199       else
4200         {
4201           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4202           lbl = newiTempLabel (NULL);
4203           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4204           emitcode ("cpl", "F0"); /* complement sign flag */
4205           emitcode ("cpl", "a");  /* 2's complement */
4206           emitcode ("inc", "a");
4207           emitcode ("", "%05d$:", (lbl->key + 100));
4208           emitcode ("mov", "b,a");
4209         }
4210     }
4211
4212   if (AOP_TYPE(left) == AOP_LIT)
4213     {
4214       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4215
4216       if (!lUnsigned && val < 0)
4217         emitcode ("mov", "a,#0x%02x", -val);
4218       else
4219         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4220     }
4221   else /* ! literal */
4222     {
4223       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4224
4225       if (!lUnsigned)
4226         {
4227           lbl = newiTempLabel (NULL);
4228           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4229           emitcode ("cpl", "F0"); /* complement sign flag */
4230           emitcode ("cpl", "a"); /* 2's complement */
4231           emitcode ("inc", "a");
4232           emitcode ("", "%05d$:", (lbl->key + 100));
4233         }
4234     }
4235
4236   /* now the multiplication */
4237   emitcode ("mul", "ab");
4238   if (runtimeSign || compiletimeSign)
4239     {
4240       lbl = newiTempLabel (NULL);
4241       if (runtimeSign)
4242         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4243       emitcode ("cpl", "a"); /* lsb 2's complement */
4244       if (size != 2)
4245         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4246       else
4247         {
4248           emitcode ("add", "a,#1"); /* this sets carry flag */
4249           emitcode ("xch", "a,b");
4250           emitcode ("cpl", "a"); /* msb 2's complement */
4251           emitcode ("addc", "a,#0");
4252           emitcode ("xch", "a,b");
4253         }
4254       emitcode ("", "%05d$:", (lbl->key + 100));
4255     }
4256   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4257   if (size == 2)
4258     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4259
4260   popB (pushedB);
4261 }
4262
4263 /*-----------------------------------------------------------------*/
4264 /* genMult - generates code for multiplication                     */
4265 /*-----------------------------------------------------------------*/
4266 static void
4267 genMult (iCode * ic)
4268 {
4269   operand *left = IC_LEFT (ic);
4270   operand *right = IC_RIGHT (ic);
4271   operand *result = IC_RESULT (ic);
4272
4273   D(emitcode (";     genMult",""));
4274
4275   /* assign the amsops */
4276   aopOp (left, ic, FALSE);
4277   aopOp (right, ic, FALSE);
4278   aopOp (result, ic, TRUE);
4279
4280   /* special cases first */
4281   /* both are bits */
4282   if (AOP_TYPE (left) == AOP_CRY &&
4283       AOP_TYPE (right) == AOP_CRY)
4284     {
4285       genMultbits (left, right, result);
4286       goto release;
4287     }
4288
4289   /* if both are of size == 1 */
4290 #if 0 // one of them can be a sloc shared with the result
4291     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4292 #else
4293   if (getSize(operandType(left)) == 1 &&
4294       getSize(operandType(right)) == 1)
4295 #endif
4296     {
4297       genMultOneByte (left, right, result);
4298       goto release;
4299     }
4300
4301   /* should have been converted to function call */
4302     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4303              getSize(OP_SYMBOL(right)->type));
4304   assert (0);
4305
4306 release:
4307   freeAsmop (result, NULL, ic, TRUE);
4308   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4309   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4310 }
4311
4312 /*-----------------------------------------------------------------*/
4313 /* genDivbits :- division of bits                                  */
4314 /*-----------------------------------------------------------------*/
4315 static void
4316 genDivbits (operand * left,
4317             operand * right,
4318             operand * result)
4319 {
4320   char *l;
4321   bool pushedB;
4322
4323   D(emitcode (";     genDivbits",""));
4324
4325   pushedB = pushB ();
4326
4327   /* the result must be bit */
4328   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4329   l = aopGet (AOP (left), 0, FALSE, FALSE);
4330
4331   MOVA (l);
4332
4333   emitcode ("div", "ab");
4334   emitcode ("rrc", "a");
4335
4336   popB (pushedB);
4337
4338   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4339 }
4340
4341 /*-----------------------------------------------------------------*/
4342 /* genDivOneByte : 8 bit division                                  */
4343 /*-----------------------------------------------------------------*/
4344 static void
4345 genDivOneByte (operand * left,
4346                operand * right,
4347                operand * result)
4348 {
4349   bool lUnsigned, rUnsigned, pushedB;
4350   bool runtimeSign, compiletimeSign;
4351   symbol *lbl;
4352   int size, offset;
4353
4354   D(emitcode (";     genDivOneByte",""));
4355
4356   /* Why is it necessary that genDivOneByte() can return an int result?
4357      Have a look at:
4358
4359         volatile unsigned char uc;
4360         volatile signed char sc1, sc2;
4361         volatile int i;
4362
4363         uc  = 255;
4364         sc1 = -1;
4365         i = uc / sc1;
4366
4367      Or:
4368
4369         sc1 = -128;
4370         sc2 = -1;
4371         i = sc1 / sc2;
4372
4373      In all cases a one byte result would overflow, the following cast to int
4374      would return the wrong result.
4375
4376      Two possible solution:
4377         a) cast operands to int, if ((unsigned) / (signed)) or
4378            ((signed) / (signed))
4379         b) return an 16 bit signed int; this is what we're doing here!
4380   */
4381
4382   size = AOP_SIZE (result) - 1;
4383   offset = 1;
4384   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4385   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4386
4387   pushedB = pushB ();
4388
4389   /* signed or unsigned */
4390   if (lUnsigned && rUnsigned)
4391     {
4392       /* unsigned is easy */
4393       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4394       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4395       emitcode ("div", "ab");
4396       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4397       while (size--)
4398         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4399
4400       popB (pushedB);
4401       return;
4402     }
4403
4404   /* signed is a little bit more difficult */
4405
4406   /* now sign adjust for both left & right */
4407
4408   /* let's see what's needed: */
4409   /* apply negative sign during runtime */
4410   runtimeSign = FALSE;
4411   /* negative sign from literals */
4412   compiletimeSign = FALSE;
4413
4414   if (!lUnsigned)
4415     {
4416       if (AOP_TYPE(left) == AOP_LIT)
4417         {
4418           /* signed literal */
4419           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4420           if (val < 0)
4421             compiletimeSign = TRUE;
4422         }
4423       else
4424         /* signed but not literal */
4425         runtimeSign = TRUE;
4426     }
4427
4428   if (!rUnsigned)
4429     {
4430       if (AOP_TYPE(right) == AOP_LIT)
4431         {
4432           /* signed literal */
4433           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4434           if (val < 0)
4435             compiletimeSign ^= TRUE;
4436         }
4437       else
4438         /* signed but not literal */
4439         runtimeSign = TRUE;
4440     }
4441
4442   /* initialize F0, which stores the runtime sign */
4443   if (runtimeSign)
4444     {
4445       if (compiletimeSign)
4446         emitcode ("setb", "F0"); /* set sign flag */
4447       else
4448         emitcode ("clr", "F0"); /* reset sign flag */
4449     }
4450
4451   /* save the signs of the operands */
4452   if (AOP_TYPE(right) == AOP_LIT)
4453     {
4454       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4455
4456       if (!rUnsigned && val < 0)
4457         emitcode ("mov", "b,#0x%02x", -val);
4458       else
4459         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4460     }
4461   else /* ! literal */
4462     {
4463       if (rUnsigned)
4464         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4465       else
4466         {
4467           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4468           lbl = newiTempLabel (NULL);
4469           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4470           emitcode ("cpl", "F0"); /* complement sign flag */
4471           emitcode ("cpl", "a");  /* 2's complement */
4472           emitcode ("inc", "a");
4473           emitcode ("", "%05d$:", (lbl->key + 100));
4474           emitcode ("mov", "b,a");
4475         }
4476     }
4477
4478   if (AOP_TYPE(left) == AOP_LIT)
4479     {
4480       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4481
4482       if (!lUnsigned && val < 0)
4483         emitcode ("mov", "a,#0x%02x", -val);
4484       else
4485         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4486     }
4487   else /* ! literal */
4488     {
4489       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4490
4491       if (!lUnsigned)
4492         {
4493           lbl = newiTempLabel (NULL);
4494           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4495           emitcode ("cpl", "F0"); /* complement sign flag */
4496           emitcode ("cpl", "a");  /* 2's complement */
4497           emitcode ("inc", "a");
4498           emitcode ("", "%05d$:", (lbl->key + 100));
4499         }
4500     }
4501
4502   /* now the division */
4503   emitcode ("div", "ab");
4504
4505   if (runtimeSign || compiletimeSign)
4506     {
4507       lbl = newiTempLabel (NULL);
4508       if (runtimeSign)
4509         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4510       emitcode ("cpl", "a"); /* lsb 2's complement */
4511       emitcode ("inc", "a");
4512       emitcode ("", "%05d$:", (lbl->key + 100));
4513
4514       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4515       if (size > 0)
4516         {
4517           /* msb is 0x00 or 0xff depending on the sign */
4518           if (runtimeSign)
4519             {
4520               emitcode ("mov", "c,F0");
4521               emitcode ("subb", "a,acc");
4522               while (size--)
4523                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4524             }
4525           else /* compiletimeSign */
4526             while (size--)
4527               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4528         }
4529     }
4530   else
4531     {
4532       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4533       while (size--)
4534         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4535     }
4536
4537   popB (pushedB);
4538 }
4539
4540 /*-----------------------------------------------------------------*/
4541 /* genDiv - generates code for division                            */
4542 /*-----------------------------------------------------------------*/
4543 static void
4544 genDiv (iCode * ic)
4545 {
4546   operand *left = IC_LEFT (ic);
4547   operand *right = IC_RIGHT (ic);
4548   operand *result = IC_RESULT (ic);
4549
4550   D(emitcode (";     genDiv",""));
4551
4552   /* assign the amsops */
4553   aopOp (left, ic, FALSE);
4554   aopOp (right, ic, FALSE);
4555   aopOp (result, ic, TRUE);
4556
4557   /* special cases first */
4558   /* both are bits */
4559   if (AOP_TYPE (left) == AOP_CRY &&
4560       AOP_TYPE (right) == AOP_CRY)
4561     {
4562       genDivbits (left, right, result);
4563       goto release;
4564     }
4565
4566   /* if both are of size == 1 */
4567   if (AOP_SIZE (left) == 1 &&
4568       AOP_SIZE (right) == 1)
4569     {
4570       genDivOneByte (left, right, result);
4571       goto release;
4572     }
4573
4574   /* should have been converted to function call */
4575   assert (0);
4576 release:
4577   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4578   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4579   freeAsmop (result, NULL, ic, TRUE);
4580 }
4581
4582 /*-----------------------------------------------------------------*/
4583 /* genModbits :- modulus of bits                                   */
4584 /*-----------------------------------------------------------------*/
4585 static void
4586 genModbits (operand * left,
4587             operand * right,
4588             operand * result)
4589 {
4590   char *l;
4591   bool pushedB;
4592
4593   D(emitcode (";     genModbits",""));
4594
4595   pushedB = pushB ();
4596
4597   /* the result must be bit */
4598   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4599   l = aopGet (AOP (left), 0, FALSE, FALSE);
4600
4601   MOVA (l);
4602
4603   emitcode ("div", "ab");
4604   emitcode ("mov", "a,b");
4605   emitcode ("rrc", "a");
4606
4607   popB (pushedB);
4608
4609   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4610 }
4611
4612 /*-----------------------------------------------------------------*/
4613 /* genModOneByte : 8 bit modulus                                   */
4614 /*-----------------------------------------------------------------*/
4615 static void
4616 genModOneByte (operand * left,
4617                operand * right,
4618                operand * result)
4619 {
4620   bool lUnsigned, rUnsigned, pushedB;
4621   bool runtimeSign, compiletimeSign;
4622   symbol *lbl;
4623   int size, offset;
4624
4625   D(emitcode (";     genModOneByte",""));
4626
4627   size = AOP_SIZE (result) - 1;
4628   offset = 1;
4629   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4630   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4631
4632   pushedB = pushB ();
4633
4634   /* signed or unsigned */
4635   if (lUnsigned && rUnsigned)
4636     {
4637       /* unsigned is easy */
4638       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4639       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4640       emitcode ("div", "ab");
4641       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4642       while (size--)
4643         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4644
4645       popB (pushedB);
4646       return;
4647     }
4648
4649   /* signed is a little bit more difficult */
4650
4651   /* now sign adjust for both left & right */
4652
4653   /* modulus: sign of the right operand has no influence on the result! */
4654   if (AOP_TYPE(right) == AOP_LIT)
4655     {
4656       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4657
4658       if (!rUnsigned && val < 0)
4659         emitcode ("mov", "b,#0x%02x", -val);
4660       else
4661         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4662     }
4663   else /* not literal */
4664     {
4665       if (rUnsigned)
4666         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4667       else
4668         {
4669           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4670           lbl = newiTempLabel (NULL);
4671           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4672           emitcode ("cpl", "a"); /* 2's complement */
4673           emitcode ("inc", "a");
4674           emitcode ("", "%05d$:", (lbl->key + 100));
4675           emitcode ("mov", "b,a");
4676         }
4677     }
4678
4679   /* let's see what's needed: */
4680   /* apply negative sign during runtime */
4681   runtimeSign = FALSE;
4682   /* negative sign from literals */
4683   compiletimeSign = FALSE;
4684
4685   /* sign adjust left side */
4686   if (AOP_TYPE(left) == AOP_LIT)
4687     {
4688       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4689
4690       if (!lUnsigned && val < 0)
4691         {
4692           compiletimeSign = TRUE; /* set sign flag */
4693           emitcode ("mov", "a,#0x%02x", -val);
4694         }
4695       else
4696         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4697     }
4698   else /* ! literal */
4699     {
4700       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4701
4702       if (!lUnsigned)
4703         {
4704           runtimeSign = TRUE;
4705           emitcode ("clr", "F0"); /* clear sign flag */
4706
4707           lbl = newiTempLabel (NULL);
4708           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4709           emitcode ("setb", "F0"); /* set sign flag */
4710           emitcode ("cpl", "a");   /* 2's complement */
4711           emitcode ("inc", "a");
4712           emitcode ("", "%05d$:", (lbl->key + 100));
4713         }
4714     }
4715
4716   /* now the modulus */
4717   emitcode ("div", "ab");
4718
4719   if (runtimeSign || compiletimeSign)
4720     {
4721       emitcode ("mov", "a,b");
4722       lbl = newiTempLabel (NULL);
4723       if (runtimeSign)
4724         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4725       emitcode ("cpl", "a"); /* 2's complement */
4726       emitcode ("inc", "a");
4727       emitcode ("", "%05d$:", (lbl->key + 100));
4728
4729       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4730       if (size > 0)
4731         {
4732           /* msb is 0x00 or 0xff depending on the sign */
4733           if (runtimeSign)
4734             {
4735               emitcode ("mov", "c,F0");
4736               emitcode ("subb", "a,acc");
4737               while (size--)
4738                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4739             }
4740           else /* compiletimeSign */
4741             while (size--)
4742               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4743         }
4744     }
4745   else
4746     {
4747       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4748       while (size--)
4749         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4750     }
4751
4752   popB (pushedB);
4753 }
4754
4755 /*-----------------------------------------------------------------*/
4756 /* genMod - generates code for division                            */
4757 /*-----------------------------------------------------------------*/
4758 static void
4759 genMod (iCode * ic)
4760 {
4761   operand *left = IC_LEFT (ic);
4762   operand *right = IC_RIGHT (ic);
4763   operand *result = IC_RESULT (ic);
4764
4765   D(emitcode (";     genMod",""));
4766
4767   /* assign the amsops */
4768   aopOp (left, ic, FALSE);
4769   aopOp (right, ic, FALSE);
4770   aopOp (result, ic, TRUE);
4771
4772   /* special cases first */
4773   /* both are bits */
4774   if (AOP_TYPE (left) == AOP_CRY &&
4775       AOP_TYPE (right) == AOP_CRY)
4776     {
4777       genModbits (left, right, result);
4778       goto release;
4779     }
4780
4781   /* if both are of size == 1 */
4782   if (AOP_SIZE (left) == 1 &&
4783       AOP_SIZE (right) == 1)
4784     {
4785       genModOneByte (left, right, result);
4786       goto release;
4787     }
4788
4789   /* should have been converted to function call */
4790   assert (0);
4791
4792 release:
4793   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4794   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4795   freeAsmop (result, NULL, ic, TRUE);
4796 }
4797
4798 /*-----------------------------------------------------------------*/
4799 /* genIfxJump :- will create a jump depending on the ifx           */
4800 /*-----------------------------------------------------------------*/
4801 static void
4802 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
4803 {
4804   symbol *jlbl;
4805   symbol *tlbl = newiTempLabel (NULL);
4806   char *inst;
4807
4808   D(emitcode (";     genIfxJump",""));
4809
4810   /* if true label then we jump if condition
4811      supplied is true */
4812   if (IC_TRUE (ic))
4813     {
4814       jlbl = IC_TRUE (ic);
4815       inst = ((strcmp (jval, "a") == 0 ? "jz" :
4816                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
4817     }
4818   else
4819     {
4820       /* false label is present */
4821       jlbl = IC_FALSE (ic);
4822       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
4823                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
4824     }
4825   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
4826     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
4827   else
4828     emitcode (inst, "%05d$", tlbl->key + 100);
4829   freeForBranchAsmop (result);
4830   freeForBranchAsmop (right);
4831   freeForBranchAsmop (left);
4832   emitcode ("ljmp", "%05d$", jlbl->key + 100);
4833   emitcode ("", "%05d$:", tlbl->key + 100);
4834
4835   /* mark the icode as generated */
4836   ic->generated = 1;
4837 }
4838
4839 /*-----------------------------------------------------------------*/
4840 /* genCmp :- greater or less than comparison                       */
4841 /*-----------------------------------------------------------------*/
4842 static void
4843 genCmp (operand * left, operand * right,
4844         operand * result, iCode * ifx, int sign, iCode *ic)
4845 {
4846   int size, offset = 0;
4847   unsigned long lit = 0L;
4848   bool rightInB;
4849
4850   D(emitcode (";     genCmp",""));
4851
4852   /* if left & right are bit variables */
4853   if (AOP_TYPE (left) == AOP_CRY &&
4854       AOP_TYPE (right) == AOP_CRY)
4855     {
4856       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
4857       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
4858     }
4859   else
4860     {
4861       /* subtract right from left if at the
4862          end the carry flag is set then we know that
4863          left is greater than right */
4864       size = max (AOP_SIZE (left), AOP_SIZE (right));
4865
4866       /* if unsigned char cmp with lit, do cjne left,#right,zz */
4867       if ((size == 1) && !sign &&
4868           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4869         {
4870           symbol *lbl = newiTempLabel (NULL);
4871           emitcode ("cjne", "%s,%s,%05d$",
4872                     aopGet (AOP (left), offset, FALSE, FALSE),
4873                     aopGet (AOP (right), offset, FALSE, FALSE),
4874                     lbl->key + 100);
4875           emitcode ("", "%05d$:", lbl->key + 100);
4876         }
4877       else
4878         {
4879           if (AOP_TYPE (right) == AOP_LIT)
4880             {
4881               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4882               /* optimize if(x < 0) or if(x >= 0) */
4883               if (lit == 0L)
4884                 {
4885                   if (!sign)
4886                     {
4887                       CLRC;
4888                     }
4889                   else
4890                     {
4891                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
4892                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4893                         {
4894                           genIfxJump (ifx, "acc.7", left, right, result);
4895                           freeAsmop (right, NULL, ic, TRUE);
4896                           freeAsmop (left, NULL, ic, TRUE);
4897
4898                           return;
4899                         }
4900                       else
4901                         emitcode ("rlc", "a");
4902                     }
4903                   goto release;
4904                 }
4905             }
4906           CLRC;
4907           while (size--)
4908             {
4909               bool pushedB = FALSE;
4910               rightInB = aopGetUsesAcc(AOP (right), offset);
4911               if (rightInB)
4912                 {
4913                   pushedB = pushB ();
4914                   emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4915                 }
4916               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4917               if (sign && size == 0)
4918                 {
4919                   emitcode ("xrl", "a,#0x80");
4920                   if (AOP_TYPE (right) == AOP_LIT)
4921                     {
4922                       unsigned long lit = (unsigned long)
4923                       floatFromVal (AOP (right)->aopu.aop_lit);
4924                       emitcode ("subb", "a,#0x%02x",
4925                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4926                     }
4927                   else
4928                     {
4929                       if (!rightInB)
4930                         {
4931                           pushedB = pushB ();
4932                           rightInB++;
4933                           emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4934                         }
4935                       emitcode ("xrl", "b,#0x80");
4936                       emitcode ("subb", "a,b");
4937                     }
4938                 }
4939               else
4940                 {
4941                   if (rightInB)
4942                     emitcode ("subb", "a,b");
4943                   else
4944                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4945                 }
4946               if (rightInB)
4947                 popB (pushedB);
4948               offset++;
4949             }
4950         }
4951     }
4952
4953 release:
4954   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4955   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4956   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4957     {
4958       outBitC (result);
4959     }
4960   else
4961     {
4962       /* if the result is used in the next
4963          ifx conditional branch then generate
4964          code a little differently */
4965       if (ifx)
4966         genIfxJump (ifx, "c", NULL, NULL, result);
4967       else
4968         outBitC (result);
4969       /* leave the result in acc */
4970     }
4971 }
4972
4973 /*-----------------------------------------------------------------*/
4974 /* genCmpGt :- greater than comparison                             */
4975 /*-----------------------------------------------------------------*/
4976 static void
4977 genCmpGt (iCode * ic, iCode * ifx)
4978 {
4979   operand *left, *right, *result;
4980   sym_link *letype, *retype;
4981   int sign;
4982
4983   D(emitcode (";     genCmpGt",""));
4984
4985   left = IC_LEFT (ic);
4986   right = IC_RIGHT (ic);
4987   result = IC_RESULT (ic);
4988
4989   letype = getSpec (operandType (left));
4990   retype = getSpec (operandType (right));
4991   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4992            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4993   /* assign the amsops */
4994   aopOp (left, ic, FALSE);
4995   aopOp (right, ic, FALSE);
4996   aopOp (result, ic, TRUE);
4997
4998   genCmp (right, left, result, ifx, sign, ic);
4999
5000   freeAsmop (result, NULL, ic, TRUE);
5001 }
5002
5003 /*-----------------------------------------------------------------*/
5004 /* genCmpLt - less than comparisons                                */
5005 /*-----------------------------------------------------------------*/
5006 static void
5007 genCmpLt (iCode * ic, iCode * ifx)
5008 {
5009   operand *left, *right, *result;
5010   sym_link *letype, *retype;
5011   int sign;
5012
5013   D(emitcode (";     genCmpLt",""));
5014
5015   left = IC_LEFT (ic);
5016   right = IC_RIGHT (ic);
5017   result = IC_RESULT (ic);
5018
5019   letype = getSpec (operandType (left));
5020   retype = getSpec (operandType (right));
5021   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5022            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5023   /* assign the amsops */
5024   aopOp (left, ic, FALSE);
5025   aopOp (right, ic, FALSE);
5026   aopOp (result, ic, TRUE);
5027
5028   genCmp (left, right, result, ifx, sign,ic);
5029
5030   freeAsmop (result, NULL, ic, TRUE);
5031 }
5032
5033 /*-----------------------------------------------------------------*/
5034 /* gencjneshort - compare and jump if not equal                    */
5035 /*-----------------------------------------------------------------*/
5036 static void
5037 gencjneshort (operand * left, operand * right, symbol * lbl)
5038 {
5039   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5040   int offset = 0;
5041   unsigned long lit = 0L;
5042
5043   /* if the left side is a literal or
5044      if the right is in a pointer register and left
5045      is not */
5046   if ((AOP_TYPE (left) == AOP_LIT) ||
5047       (AOP_TYPE (left) == AOP_IMMD) ||
5048       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5049     {
5050       operand *t = right;
5051       right = left;
5052       left = t;
5053     }
5054
5055   if (AOP_TYPE (right) == AOP_LIT)
5056     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5057
5058   /* if the right side is a literal then anything goes */
5059   if (AOP_TYPE (right) == AOP_LIT &&
5060       AOP_TYPE (left) != AOP_DIR  &&
5061       AOP_TYPE (left) != AOP_IMMD)
5062     {
5063       while (size--)
5064         {
5065           emitcode ("cjne", "%s,%s,%05d$",
5066                     aopGet (AOP (left), offset, FALSE, FALSE),
5067                     aopGet (AOP (right), offset, FALSE, FALSE),
5068                     lbl->key + 100);
5069           offset++;
5070         }
5071     }
5072
5073   /* if the right side is in a register or in direct space or
5074      if the left is a pointer register & right is not */
5075   else if (AOP_TYPE (right) == AOP_REG ||
5076            AOP_TYPE (right) == AOP_DIR ||
5077            AOP_TYPE (right) == AOP_LIT ||
5078            AOP_TYPE (right) == AOP_IMMD ||
5079            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5080            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5081     {
5082       while (size--)
5083         {
5084           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5085           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5086               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5087             emitcode ("jnz", "%05d$", lbl->key + 100);
5088           else
5089             emitcode ("cjne", "a,%s,%05d$",
5090                       aopGet (AOP (right), offset, FALSE, TRUE),
5091                       lbl->key + 100);
5092           offset++;
5093         }
5094     }
5095   else
5096     {
5097       /* right is a pointer reg need both a & b */
5098       while (size--)
5099         {
5100           char *l;
5101           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5102           wassertl(!_G.BInUse, "B was in use");
5103           l = aopGet (AOP (left), offset, FALSE, FALSE);
5104           if (strcmp (l, "b"))
5105             emitcode ("mov", "b,%s", l);
5106           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5107           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5108           offset++;
5109         }
5110     }
5111 }
5112
5113 /*-----------------------------------------------------------------*/
5114 /* gencjne - compare and jump if not equal                         */
5115 /*-----------------------------------------------------------------*/
5116 static void
5117 gencjne (operand * left, operand * right, symbol * lbl)
5118 {
5119   symbol *tlbl = newiTempLabel (NULL);
5120
5121   gencjneshort (left, right, lbl);
5122
5123   emitcode ("mov", "a,%s", one);
5124   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5125   emitcode ("", "%05d$:", lbl->key + 100);
5126   emitcode ("clr", "a");
5127   emitcode ("", "%05d$:", tlbl->key + 100);
5128 }
5129
5130 /*-----------------------------------------------------------------*/
5131 /* genCmpEq - generates code for equal to                          */
5132 /*-----------------------------------------------------------------*/
5133 static void
5134 genCmpEq (iCode * ic, iCode * ifx)
5135 {
5136   operand *left, *right, *result;
5137
5138   D(emitcode (";     genCmpEq",""));
5139
5140   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5141   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5142   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5143
5144   /* if literal, literal on the right or
5145      if the right is in a pointer register and left
5146      is not */
5147   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5148       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5149     {
5150       operand *t = IC_RIGHT (ic);
5151       IC_RIGHT (ic) = IC_LEFT (ic);
5152       IC_LEFT (ic) = t;
5153     }
5154
5155   if (ifx && !AOP_SIZE (result))
5156     {
5157       symbol *tlbl;
5158       /* if they are both bit variables */
5159       if (AOP_TYPE (left) == AOP_CRY &&
5160           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5161         {
5162           if (AOP_TYPE (right) == AOP_LIT)
5163             {
5164               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5165               if (lit == 0L)
5166                 {
5167                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5168                   emitcode ("cpl", "c");
5169                 }
5170               else if (lit == 1L)
5171                 {
5172                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5173                 }
5174               else
5175                 {
5176                   emitcode ("clr", "c");
5177                 }
5178               /* AOP_TYPE(right) == AOP_CRY */
5179             }
5180           else
5181             {
5182               symbol *lbl = newiTempLabel (NULL);
5183               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5184               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5185               emitcode ("cpl", "c");
5186               emitcode ("", "%05d$:", (lbl->key + 100));
5187             }
5188           /* if true label then we jump if condition
5189              supplied is true */
5190           tlbl = newiTempLabel (NULL);
5191           if (IC_TRUE (ifx))
5192             {
5193               emitcode ("jnc", "%05d$", tlbl->key + 100);
5194               freeForBranchAsmop (result);
5195               freeForBranchAsmop (right);
5196               freeForBranchAsmop (left);
5197               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5198             }
5199           else
5200             {
5201               emitcode ("jc", "%05d$", tlbl->key + 100);
5202               freeForBranchAsmop (result);
5203               freeForBranchAsmop (right);
5204               freeForBranchAsmop (left);
5205               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5206             }
5207           emitcode ("", "%05d$:", tlbl->key + 100);
5208         }
5209       else
5210         {
5211           tlbl = newiTempLabel (NULL);
5212           gencjneshort (left, right, tlbl);
5213           if (IC_TRUE (ifx))
5214             {
5215               freeForBranchAsmop (result);
5216               freeForBranchAsmop (right);
5217               freeForBranchAsmop (left);
5218               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5219               emitcode ("", "%05d$:", tlbl->key + 100);
5220             }
5221           else
5222             {
5223               symbol *lbl = newiTempLabel (NULL);
5224               emitcode ("sjmp", "%05d$", lbl->key + 100);
5225               emitcode ("", "%05d$:", tlbl->key + 100);
5226               freeForBranchAsmop (result);
5227               freeForBranchAsmop (right);
5228               freeForBranchAsmop (left);
5229               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5230               emitcode ("", "%05d$:", lbl->key + 100);
5231             }
5232         }
5233       /* mark the icode as generated */
5234       ifx->generated = 1;
5235       goto release;
5236     }
5237
5238   /* if they are both bit variables */
5239   if (AOP_TYPE (left) == AOP_CRY &&
5240       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5241     {
5242       if (AOP_TYPE (right) == AOP_LIT)
5243         {
5244           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5245           if (lit == 0L)
5246             {
5247               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5248               emitcode ("cpl", "c");
5249             }
5250           else if (lit == 1L)
5251             {
5252               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5253             }
5254           else
5255             {
5256               emitcode ("clr", "c");
5257             }
5258           /* AOP_TYPE(right) == AOP_CRY */
5259         }
5260       else
5261         {
5262           symbol *lbl = newiTempLabel (NULL);
5263           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5264           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5265           emitcode ("cpl", "c");
5266           emitcode ("", "%05d$:", (lbl->key + 100));
5267         }
5268       /* c = 1 if egal */
5269       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5270         {
5271           outBitC (result);
5272           goto release;
5273         }
5274       if (ifx)
5275         {
5276           genIfxJump (ifx, "c", left, right, result);
5277           goto release;
5278         }
5279       /* if the result is used in an arithmetic operation
5280          then put the result in place */
5281       outBitC (result);
5282     }
5283   else
5284     {
5285       gencjne (left, right, newiTempLabel (NULL));
5286       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5287         {
5288           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5289           goto release;
5290         }
5291       if (ifx)
5292         {
5293           genIfxJump (ifx, "a", left, right, result);
5294           goto release;
5295         }
5296       /* if the result is used in an arithmetic operation
5297          then put the result in place */
5298       if (AOP_TYPE (result) != AOP_CRY)
5299         outAcc (result);
5300       /* leave the result in acc */
5301     }
5302
5303 release:
5304   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5305   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5306   freeAsmop (result, NULL, ic, TRUE);
5307 }
5308
5309 /*-----------------------------------------------------------------*/
5310 /* ifxForOp - returns the icode containing the ifx for operand     */
5311 /*-----------------------------------------------------------------*/
5312 static iCode *
5313 ifxForOp (operand * op, iCode * ic)
5314 {
5315   /* if true symbol then needs to be assigned */
5316   if (IS_TRUE_SYMOP (op))
5317     return NULL;
5318
5319   /* if this has register type condition and
5320      the next instruction is ifx with the same operand
5321      and live to of the operand is upto the ifx only then */
5322   if (ic->next &&
5323       ic->next->op == IFX &&
5324       IC_COND (ic->next)->key == op->key &&
5325       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5326     return ic->next;
5327
5328   return NULL;
5329 }
5330
5331 /*-----------------------------------------------------------------*/
5332 /* hasInc - operand is incremented before any other use            */
5333 /*-----------------------------------------------------------------*/
5334 static iCode *
5335 hasInc (operand *op, iCode *ic,int osize)
5336 {
5337   sym_link *type = operandType(op);
5338   sym_link *retype = getSpec (type);
5339   iCode *lic = ic->next;
5340   int isize ;
5341
5342   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5343   if (!IS_SYMOP(op)) return NULL;
5344
5345   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5346   if (IS_AGGREGATE(type->next)) return NULL;
5347   if (osize != (isize = getSize(type->next))) return NULL;
5348
5349   while (lic) {
5350     /* if operand of the form op = op + <sizeof *op> */
5351     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5352         isOperandEqual(IC_RESULT(lic),op) &&
5353         isOperandLiteral(IC_RIGHT(lic)) &&
5354         operandLitValue(IC_RIGHT(lic)) == isize) {
5355       return lic;
5356     }
5357     /* if the operand used or deffed */
5358     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5359       return NULL;
5360     }
5361     /* if GOTO or IFX */
5362     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5363     lic = lic->next;
5364   }
5365   return NULL;
5366 }
5367
5368 /*-----------------------------------------------------------------*/
5369 /* genAndOp - for && operation                                     */
5370 /*-----------------------------------------------------------------*/
5371 static void
5372 genAndOp (iCode * ic)
5373 {
5374   operand *left, *right, *result;
5375   symbol *tlbl;
5376
5377   D(emitcode (";     genAndOp",""));
5378
5379   /* note here that && operations that are in an
5380      if statement are taken away by backPatchLabels
5381      only those used in arthmetic operations remain */
5382   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5383   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5384   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5385
5386   /* if both are bit variables */
5387   if (AOP_TYPE (left) == AOP_CRY &&
5388       AOP_TYPE (right) == AOP_CRY)
5389     {
5390       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5391       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5392       outBitC (result);
5393     }
5394   else
5395     {
5396       tlbl = newiTempLabel (NULL);
5397       toBoolean (left);
5398       emitcode ("jz", "%05d$", tlbl->key + 100);
5399       toBoolean (right);
5400       emitcode ("", "%05d$:", tlbl->key + 100);
5401       outBitAcc (result);
5402     }
5403
5404   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5405   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5406   freeAsmop (result, NULL, ic, TRUE);
5407 }
5408
5409
5410 /*-----------------------------------------------------------------*/
5411 /* genOrOp - for || operation                                      */
5412 /*-----------------------------------------------------------------*/
5413 static void
5414 genOrOp (iCode * ic)
5415 {
5416   operand *left, *right, *result;
5417   symbol *tlbl;
5418
5419   D(emitcode (";     genOrOp",""));
5420
5421   /* note here that || operations that are in an
5422      if statement are taken away by backPatchLabels
5423      only those used in arthmetic operations remain */
5424   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5425   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5426   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5427
5428   /* if both are bit variables */
5429   if (AOP_TYPE (left) == AOP_CRY &&
5430       AOP_TYPE (right) == AOP_CRY)
5431     {
5432       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5433       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5434       outBitC (result);
5435     }
5436   else
5437     {
5438       tlbl = newiTempLabel (NULL);
5439       toBoolean (left);
5440       emitcode ("jnz", "%05d$", tlbl->key + 100);
5441       toBoolean (right);
5442       emitcode ("", "%05d$:", tlbl->key + 100);
5443       outBitAcc (result);
5444     }
5445
5446   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5447   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5448   freeAsmop (result, NULL, ic, TRUE);
5449 }
5450
5451 /*-----------------------------------------------------------------*/
5452 /* isLiteralBit - test if lit == 2^n                               */
5453 /*-----------------------------------------------------------------*/
5454 static int
5455 isLiteralBit (unsigned long lit)
5456 {
5457   unsigned long pw[32] =
5458   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5459    0x100L, 0x200L, 0x400L, 0x800L,
5460    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5461    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5462    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5463    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5464    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5465   int idx;
5466
5467   for (idx = 0; idx < 32; idx++)
5468     if (lit == pw[idx])
5469       return idx + 1;
5470   return 0;
5471 }
5472
5473 /*-----------------------------------------------------------------*/
5474 /* continueIfTrue -                                                */
5475 /*-----------------------------------------------------------------*/
5476 static void
5477 continueIfTrue (iCode * ic)
5478 {
5479   if (IC_TRUE (ic))
5480     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5481   ic->generated = 1;
5482 }
5483
5484 /*-----------------------------------------------------------------*/
5485 /* jmpIfTrue -                                                     */
5486 /*-----------------------------------------------------------------*/
5487 static void
5488 jumpIfTrue (iCode * ic)
5489 {
5490   if (!IC_TRUE (ic))
5491     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5492   ic->generated = 1;
5493 }
5494
5495 /*-----------------------------------------------------------------*/
5496 /* jmpTrueOrFalse -                                                */
5497 /*-----------------------------------------------------------------*/
5498 static void
5499 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5500 {
5501   // ugly but optimized by peephole
5502   if (IC_TRUE (ic))
5503     {
5504       symbol *nlbl = newiTempLabel (NULL);
5505       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5506       emitcode ("", "%05d$:", tlbl->key + 100);
5507       freeForBranchAsmop (result);
5508       freeForBranchAsmop (right);
5509       freeForBranchAsmop (left);
5510       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5511       emitcode ("", "%05d$:", nlbl->key + 100);
5512     }
5513   else
5514     {
5515       freeForBranchAsmop (result);
5516       freeForBranchAsmop (right);
5517       freeForBranchAsmop (left);
5518       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5519       emitcode ("", "%05d$:", tlbl->key + 100);
5520     }
5521   ic->generated = 1;
5522 }
5523
5524 /*-----------------------------------------------------------------*/
5525 /* genAnd  - code for and                                          */
5526 /*-----------------------------------------------------------------*/
5527 static void
5528 genAnd (iCode * ic, iCode * ifx)
5529 {
5530   operand *left, *right, *result;
5531   int size, offset = 0;
5532   unsigned long lit = 0L;
5533   int bytelit = 0;
5534   char buffer[10];
5535
5536   D(emitcode (";     genAnd",""));
5537
5538   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5539   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5540   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5541
5542 #ifdef DEBUG_TYPE
5543   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5544             AOP_TYPE (result),
5545             AOP_TYPE (left), AOP_TYPE (right));
5546   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5547             AOP_SIZE (result),
5548             AOP_SIZE (left), AOP_SIZE (right));
5549 #endif
5550
5551   /* if left is a literal & right is not then exchange them */
5552   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5553       AOP_NEEDSACC (left))
5554     {
5555       operand *tmp = right;
5556       right = left;
5557       left = tmp;
5558     }
5559
5560   /* if result = right then exchange left and right */
5561   if (sameRegs (AOP (result), AOP (right)))
5562     {
5563       operand *tmp = right;
5564       right = left;
5565       left = tmp;
5566     }
5567
5568   /* if right is bit then exchange them */
5569   if (AOP_TYPE (right) == AOP_CRY &&
5570       AOP_TYPE (left) != AOP_CRY)
5571     {
5572       operand *tmp = right;
5573       right = left;
5574       left = tmp;
5575     }
5576   if (AOP_TYPE (right) == AOP_LIT)
5577     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5578
5579   size = AOP_SIZE (result);
5580
5581   // if(bit & yy)
5582   // result = bit & yy;
5583   if (AOP_TYPE (left) == AOP_CRY)
5584     {
5585       // c = bit & literal;
5586       if (AOP_TYPE (right) == AOP_LIT)
5587         {
5588           if (lit & 1)
5589             {
5590               if (size && sameRegs (AOP (result), AOP (left)))
5591                 // no change
5592                 goto release;
5593               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5594             }
5595           else
5596             {
5597               // bit(result) = 0;
5598               if (size && (AOP_TYPE (result) == AOP_CRY))
5599                 {
5600                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5601                   goto release;
5602                 }
5603               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5604                 {
5605                   jumpIfTrue (ifx);
5606                   goto release;
5607                 }
5608               emitcode ("clr", "c");
5609             }
5610         }
5611       else
5612         {
5613           if (AOP_TYPE (right) == AOP_CRY)
5614             {
5615               // c = bit & bit;
5616               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5617               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5618             }
5619           else
5620             {
5621               // c = bit & val;
5622               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5623               // c = lsb
5624               emitcode ("rrc", "a");
5625               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5626             }
5627         }
5628       // bit = c
5629       // val = c
5630       if (size)
5631         outBitC (result);
5632       // if(bit & ...)
5633       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5634         genIfxJump (ifx, "c", left, right, result);
5635       goto release;
5636     }
5637
5638   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5639   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5640   if ((AOP_TYPE (right) == AOP_LIT) &&
5641       (AOP_TYPE (result) == AOP_CRY) &&
5642       (AOP_TYPE (left) != AOP_CRY))
5643     {
5644       int posbit = isLiteralBit (lit);
5645       /* left &  2^n */
5646       if (posbit)
5647         {
5648           posbit--;
5649           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5650           // bit = left & 2^n
5651           if (size)
5652             emitcode ("mov", "c,acc.%d", posbit & 0x07);
5653           // if(left &  2^n)
5654           else
5655             {
5656               if (ifx)
5657                 {
5658                   SNPRINTF (buffer, sizeof(buffer),
5659                             "acc.%d", posbit & 0x07);
5660                   genIfxJump (ifx, buffer, left, right, result);
5661                 }
5662               else
5663                 {// what is this case? just found it in ds390/gen.c
5664                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
5665                 }
5666               goto release;
5667             }
5668         }
5669       else
5670         {
5671           symbol *tlbl = newiTempLabel (NULL);
5672           int sizel = AOP_SIZE (left);
5673           if (size)
5674             emitcode ("setb", "c");
5675           while (sizel--)
5676             {
5677               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5678                 {
5679                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5680                   // byte ==  2^n ?
5681                   if ((posbit = isLiteralBit (bytelit)) != 0)
5682                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5683                   else
5684                     {
5685                       if (bytelit != 0x0FFL)
5686                         emitcode ("anl", "a,%s",
5687                                   aopGet (AOP (right), offset, FALSE, TRUE));
5688                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5689                     }
5690                 }
5691               offset++;
5692             }
5693           // bit = left & literal
5694           if (size)
5695             {
5696               emitcode ("clr", "c");
5697               emitcode ("", "%05d$:", tlbl->key + 100);
5698             }
5699           // if(left & literal)
5700           else
5701             {
5702               if (ifx)
5703                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5704               else
5705                 emitcode ("", "%05d$:", tlbl->key + 100);
5706               goto release;
5707             }
5708         }
5709       outBitC (result);
5710       goto release;
5711     }
5712
5713   /* if left is same as result */
5714   if (sameRegs (AOP (result), AOP (left)))
5715     {
5716       for (; size--; offset++)
5717         {
5718           if (AOP_TYPE (right) == AOP_LIT)
5719             {
5720               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5721               if (bytelit == 0x0FF)
5722                 {
5723                   /* dummy read of volatile operand */
5724                   if (isOperandVolatile (left, FALSE))
5725                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5726                   else
5727                     continue;
5728                 }
5729               else if (bytelit == 0)
5730                 {
5731                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5732                 }
5733               else if (IS_AOP_PREG (result))
5734                 {
5735                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5736                   emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5737                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5738                 }
5739               else
5740                 emitcode ("anl", "%s,%s",
5741                           aopGet (AOP (left), offset, FALSE, TRUE),
5742                           aopGet (AOP (right), offset, FALSE, FALSE));
5743             }
5744           else
5745             {
5746               if (AOP_TYPE (left) == AOP_ACC)
5747                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5748               else
5749                 {
5750                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5751                   if (IS_AOP_PREG (result))
5752                     {
5753                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5754                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5755                     }
5756                   else
5757                     emitcode ("anl", "%s,a",
5758                               aopGet (AOP (left), offset, FALSE, TRUE));
5759                 }
5760             }
5761         }
5762     }
5763   else
5764     {
5765       // left & result in different registers
5766       if (AOP_TYPE (result) == AOP_CRY)
5767         {
5768           // result = bit
5769           // if(size), result in bit
5770           // if(!size && ifx), conditional oper: if(left & right)
5771           symbol *tlbl = newiTempLabel (NULL);
5772           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5773           if (size)
5774             emitcode ("setb", "c");
5775           while (sizer--)
5776             {
5777               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5778                 emitcode ("anl", "a,%s",
5779                           aopGet (AOP (right), offset, FALSE, FALSE));
5780               } else {
5781                 if (AOP_TYPE(left)==AOP_ACC) {
5782                   bool pushedB = pushB ();
5783                   emitcode("mov", "b,a");
5784                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5785                   emitcode("anl", "a,b");
5786                   popB (pushedB);
5787                 }else {
5788                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5789                   emitcode ("anl", "a,%s",
5790                             aopGet (AOP (left), offset, FALSE, FALSE));
5791                 }
5792               }
5793               emitcode ("jnz", "%05d$", tlbl->key + 100);
5794               offset++;
5795             }
5796           if (size)
5797             {
5798               CLRC;
5799               emitcode ("", "%05d$:", tlbl->key + 100);
5800               outBitC (result);
5801             }
5802           else if (ifx)
5803             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5804           else
5805             emitcode ("", "%05d$:", tlbl->key + 100);
5806         }
5807       else
5808         {
5809           for (; (size--); offset++)
5810             {
5811               // normal case
5812               // result = left & right
5813               if (AOP_TYPE (right) == AOP_LIT)
5814                 {
5815                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
5816                   if (bytelit == 0x0FF)
5817                     {
5818                       aopPut (AOP (result),
5819                               aopGet (AOP (left), offset, FALSE, FALSE),
5820                               offset,
5821                               isOperandVolatile (result, FALSE));
5822                       continue;
5823                     }
5824                   else if (bytelit == 0)
5825                     {
5826                       /* dummy read of volatile operand */
5827                       if (isOperandVolatile (left, FALSE))
5828                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5829                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5830                       continue;
5831                     }
5832                 }
5833               // faster than result <- left, anl result,right
5834               // and better if result is SFR
5835               if (AOP_TYPE (left) == AOP_ACC)
5836                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5837               else
5838                 {
5839                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5840                   emitcode ("anl", "a,%s",
5841                             aopGet (AOP (left), offset, FALSE, FALSE));
5842                 }
5843               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5844             }
5845         }
5846     }
5847
5848 release:
5849   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5850   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5851   freeAsmop (result, NULL, ic, TRUE);
5852 }
5853
5854 /*-----------------------------------------------------------------*/
5855 /* genOr  - code for or                                            */
5856 /*-----------------------------------------------------------------*/
5857 static void
5858 genOr (iCode * ic, iCode * ifx)
5859 {
5860   operand *left, *right, *result;
5861   int size, offset = 0;
5862   unsigned long lit = 0L;
5863   int bytelit = 0;
5864
5865   D(emitcode (";     genOr",""));
5866
5867   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5868   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5869   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5870
5871 #ifdef DEBUG_TYPE
5872   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5873             AOP_TYPE (result),
5874             AOP_TYPE (left), AOP_TYPE (right));
5875   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5876             AOP_SIZE (result),
5877             AOP_SIZE (left), AOP_SIZE (right));
5878 #endif
5879
5880   /* if left is a literal & right is not then exchange them */
5881   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5882       AOP_NEEDSACC (left))
5883     {
5884       operand *tmp = right;
5885       right = left;
5886       left = tmp;
5887     }
5888
5889   /* if result = right then exchange them */
5890   if (sameRegs (AOP (result), AOP (right)))
5891     {
5892       operand *tmp = right;
5893       right = left;
5894       left = tmp;
5895     }
5896
5897   /* if right is bit then exchange them */
5898   if (AOP_TYPE (right) == AOP_CRY &&
5899       AOP_TYPE (left) != AOP_CRY)
5900     {
5901       operand *tmp = right;
5902       right = left;
5903       left = tmp;
5904     }
5905   if (AOP_TYPE (right) == AOP_LIT)
5906     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5907
5908   size = AOP_SIZE (result);
5909
5910   // if(bit | yy)
5911   // xx = bit | yy;
5912   if (AOP_TYPE (left) == AOP_CRY)
5913     {
5914       if (AOP_TYPE (right) == AOP_LIT)
5915         {
5916           // c = bit | literal;
5917           if (lit)
5918             {
5919               // lit != 0 => result = 1
5920               if (AOP_TYPE (result) == AOP_CRY)
5921                 {
5922                   if (size)
5923                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5924                   else if (ifx)
5925                     continueIfTrue (ifx);
5926                   goto release;
5927                 }
5928               emitcode ("setb", "c");
5929             }
5930           else
5931             {
5932               // lit == 0 => result = left
5933               if (size && sameRegs (AOP (result), AOP (left)))
5934                 goto release;
5935               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5936             }
5937         }
5938       else
5939         {
5940           if (AOP_TYPE (right) == AOP_CRY)
5941             {
5942               // c = bit | bit;
5943               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5944               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
5945             }
5946           else
5947             {
5948               // c = bit | val;
5949               symbol *tlbl = newiTempLabel (NULL);
5950               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
5951                 emitcode ("setb", "c");
5952               emitcode ("jb", "%s,%05d$",
5953                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
5954               toBoolean (right);
5955               emitcode ("jnz", "%05d$", tlbl->key + 100);
5956               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5957                 {
5958                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
5959                   goto release;
5960                 }
5961               else
5962                 {
5963                   CLRC;
5964                   emitcode ("", "%05d$:", tlbl->key + 100);
5965                 }
5966             }
5967         }
5968       // bit = c
5969       // val = c
5970       if (size)
5971         outBitC (result);
5972       // if(bit | ...)
5973       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5974         genIfxJump (ifx, "c", left, right, result);
5975       goto release;
5976     }
5977
5978   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5979   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5980   if ((AOP_TYPE (right) == AOP_LIT) &&
5981       (AOP_TYPE (result) == AOP_CRY) &&
5982       (AOP_TYPE (left) != AOP_CRY))
5983     {
5984       if (lit)
5985         {
5986           // result = 1
5987           if (size)
5988             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5989           else
5990             continueIfTrue (ifx);
5991           goto release;
5992         }
5993       else
5994         {
5995           // lit = 0, result = boolean(left)
5996           if (size)
5997             emitcode ("setb", "c");
5998           toBoolean (right);
5999           if (size)
6000             {
6001               symbol *tlbl = newiTempLabel (NULL);
6002               emitcode ("jnz", "%05d$", tlbl->key + 100);
6003               CLRC;
6004               emitcode ("", "%05d$:", tlbl->key + 100);
6005             }
6006           else
6007             {
6008               genIfxJump (ifx, "a", left, right, result);
6009               goto release;
6010             }
6011         }
6012       outBitC (result);
6013       goto release;
6014     }
6015
6016   /* if left is same as result */
6017   if (sameRegs (AOP (result), AOP (left)))
6018     {
6019       for (; size--; offset++)
6020         {
6021           if (AOP_TYPE (right) == AOP_LIT)
6022             {
6023               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6024               if (bytelit == 0)
6025                 {
6026                   /* dummy read of volatile operand */
6027                   if (isOperandVolatile (left, FALSE))
6028                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6029                   else
6030                     continue;
6031                 }
6032               else if (bytelit == 0x0FF)
6033                 {
6034                   aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6035                 }
6036               else if (IS_AOP_PREG (left))
6037                 {
6038                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6039                   emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6040                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6041                 }
6042               else
6043                 {
6044                   emitcode ("orl", "%s,%s",
6045                             aopGet (AOP (left), offset, FALSE, TRUE),
6046                             aopGet (AOP (right), offset, FALSE, FALSE));
6047                 }
6048             }
6049           else
6050             {
6051               if (AOP_TYPE (left) == AOP_ACC)
6052                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6053               else
6054                 {
6055                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6056                   if (IS_AOP_PREG (left))
6057                     {
6058                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6059                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6060                     }
6061                   else
6062                     {
6063                       emitcode ("orl", "%s,a",
6064                                 aopGet (AOP (left), offset, FALSE, TRUE));
6065                     }
6066                 }
6067             }
6068         }
6069     }
6070   else
6071     {
6072       // left & result in different registers
6073       if (AOP_TYPE (result) == AOP_CRY)
6074         {
6075           // result = bit
6076           // if(size), result in bit
6077           // if(!size && ifx), conditional oper: if(left | right)
6078           symbol *tlbl = newiTempLabel (NULL);
6079           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6080           if (size)
6081             emitcode ("setb", "c");
6082           while (sizer--)
6083             {
6084               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6085                 emitcode ("orl", "a,%s",
6086                           aopGet (AOP (right), offset, FALSE, FALSE));
6087               } else {
6088                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6089                 emitcode ("orl", "a,%s",
6090                           aopGet (AOP (left), offset, FALSE, FALSE));
6091               }
6092               emitcode ("jnz", "%05d$", tlbl->key + 100);
6093               offset++;
6094             }
6095           if (size)
6096             {
6097               CLRC;
6098               emitcode ("", "%05d$:", tlbl->key + 100);
6099               outBitC (result);
6100             }
6101           else if (ifx)
6102             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6103           else
6104             emitcode ("", "%05d$:", tlbl->key + 100);
6105         }
6106       else
6107         {
6108           for (; (size--); offset++)
6109             {
6110               // normal case
6111               // result = left | right
6112               if (AOP_TYPE (right) == AOP_LIT)
6113                 {
6114                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6115                   if (bytelit == 0)
6116                     {
6117                       aopPut (AOP (result),
6118                               aopGet (AOP (left), offset, FALSE, FALSE),
6119                               offset,
6120                               isOperandVolatile (result, FALSE));
6121                       continue;
6122                     }
6123                   else if (bytelit == 0x0FF)
6124                     {
6125                       /* dummy read of volatile operand */
6126                       if (isOperandVolatile (left, FALSE))
6127                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6128                       aopPut (AOP (result), "#0xFF", offset, isOperandVolatile (result, FALSE));
6129                       continue;
6130                     }
6131                 }
6132               // faster than result <- left, anl result,right
6133               // and better if result is SFR
6134               if (AOP_TYPE (left) == AOP_ACC)
6135                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6136               else
6137                 {
6138                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6139                   emitcode ("orl", "a,%s",
6140                             aopGet (AOP (left), offset, FALSE, FALSE));
6141                 }
6142               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6143             }
6144         }
6145     }
6146
6147 release:
6148   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6149   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6150   freeAsmop (result, NULL, ic, TRUE);
6151 }
6152
6153 /*-----------------------------------------------------------------*/
6154 /* genXor - code for xclusive or                                   */
6155 /*-----------------------------------------------------------------*/
6156 static void
6157 genXor (iCode * ic, iCode * ifx)
6158 {
6159   operand *left, *right, *result;
6160   int size, offset = 0;
6161   unsigned long lit = 0L;
6162   int bytelit = 0;
6163
6164   D(emitcode (";     genXor",""));
6165
6166   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6167   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6168   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6169
6170 #ifdef DEBUG_TYPE
6171   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6172             AOP_TYPE (result),
6173             AOP_TYPE (left), AOP_TYPE (right));
6174   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6175             AOP_SIZE (result),
6176             AOP_SIZE (left), AOP_SIZE (right));
6177 #endif
6178
6179   /* if left is a literal & right is not ||
6180      if left needs acc & right does not */
6181   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6182       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6183     {
6184       operand *tmp = right;
6185       right = left;
6186       left = tmp;
6187     }
6188
6189   /* if result = right then exchange them */
6190   if (sameRegs (AOP (result), AOP (right)))
6191     {
6192       operand *tmp = right;
6193       right = left;
6194       left = tmp;
6195     }
6196
6197   /* if right is bit then exchange them */
6198   if (AOP_TYPE (right) == AOP_CRY &&
6199       AOP_TYPE (left) != AOP_CRY)
6200     {
6201       operand *tmp = right;
6202       right = left;
6203       left = tmp;
6204     }
6205   if (AOP_TYPE (right) == AOP_LIT)
6206     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6207
6208   size = AOP_SIZE (result);
6209
6210   // if(bit ^ yy)
6211   // xx = bit ^ yy;
6212   if (AOP_TYPE (left) == AOP_CRY)
6213     {
6214       if (AOP_TYPE (right) == AOP_LIT)
6215         {
6216           // c = bit & literal;
6217           if (lit >> 1)
6218             {
6219               // lit>>1  != 0 => result = 1
6220               if (AOP_TYPE (result) == AOP_CRY)
6221                 {
6222                   if (size)
6223                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6224                   else if (ifx)
6225                     continueIfTrue (ifx);
6226                   goto release;
6227                 }
6228               emitcode ("setb", "c");
6229             }
6230           else
6231             {
6232               // lit == (0 or 1)
6233               if (lit == 0)
6234                 {
6235                   // lit == 0, result = left
6236                   if (size && sameRegs (AOP (result), AOP (left)))
6237                     goto release;
6238                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6239                 }
6240               else
6241                 {
6242                   // lit == 1, result = not(left)
6243                   if (size && sameRegs (AOP (result), AOP (left)))
6244                     {
6245                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6246                       goto release;
6247                     }
6248                   else
6249                     {
6250                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6251                       emitcode ("cpl", "c");
6252                     }
6253                 }
6254             }
6255
6256         }
6257       else
6258         {
6259           // right != literal
6260           symbol *tlbl = newiTempLabel (NULL);
6261           if (AOP_TYPE (right) == AOP_CRY)
6262             {
6263               // c = bit ^ bit;
6264               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6265             }
6266           else
6267             {
6268               int sizer = AOP_SIZE (right);
6269               // c = bit ^ val
6270               // if val>>1 != 0, result = 1
6271               emitcode ("setb", "c");
6272               while (sizer)
6273                 {
6274                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6275                   if (sizer == 1)
6276                     // test the msb of the lsb
6277                     emitcode ("anl", "a,#0xfe");
6278                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6279                   sizer--;
6280                 }
6281               // val = (0,1)
6282               emitcode ("rrc", "a");
6283             }
6284           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6285           emitcode ("cpl", "c");
6286           emitcode ("", "%05d$:", (tlbl->key + 100));
6287         }
6288       // bit = c
6289       // val = c
6290       if (size)
6291         outBitC (result);
6292       // if(bit | ...)
6293       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6294         genIfxJump (ifx, "c", left, right, result);
6295       goto release;
6296     }
6297
6298   /* if left is same as result */
6299   if (sameRegs (AOP (result), AOP (left)))
6300     {
6301       for (; size--; offset++)
6302         {
6303           if (AOP_TYPE (right) == AOP_LIT)
6304             {
6305               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6306               if (bytelit == 0)
6307                 {
6308                   /* dummy read of volatile operand */
6309                   if (isOperandVolatile (left, FALSE))
6310                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6311                   else
6312                     continue;
6313                 }
6314               else if (IS_AOP_PREG (left))
6315                 {
6316                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6317                   emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6318                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6319                 }
6320               else
6321                 {
6322                   emitcode ("xrl", "%s,%s",
6323                             aopGet (AOP (left), offset, FALSE, TRUE),
6324                             aopGet (AOP (right), offset, FALSE, FALSE));
6325                 }
6326             }
6327           else
6328             {
6329               if (AOP_TYPE (left) == AOP_ACC)
6330                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6331               else
6332                 {
6333                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6334                   if (IS_AOP_PREG (left))
6335                     {
6336                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6337                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6338                     }
6339                   else
6340                     emitcode ("xrl", "%s,a",
6341                               aopGet (AOP (left), offset, FALSE, TRUE));
6342                 }
6343             }
6344         }
6345     }
6346   else
6347     {
6348       // left & result in different registers
6349       if (AOP_TYPE (result) == AOP_CRY)
6350         {
6351           // result = bit
6352           // if(size), result in bit
6353           // if(!size && ifx), conditional oper: if(left ^ right)
6354           symbol *tlbl = newiTempLabel (NULL);
6355           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6356           if (size)
6357             emitcode ("setb", "c");
6358           while (sizer--)
6359             {
6360               if ((AOP_TYPE (right) == AOP_LIT) &&
6361                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6362                 {
6363                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6364                 }
6365               else
6366                 {
6367                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6368                     emitcode ("xrl", "a,%s",
6369                               aopGet (AOP (right), offset, FALSE, FALSE));
6370                   } else {
6371                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6372                     emitcode ("xrl", "a,%s",
6373                               aopGet (AOP (left), offset, FALSE, FALSE));
6374                   }
6375                 }
6376               emitcode ("jnz", "%05d$", tlbl->key + 100);
6377               offset++;
6378             }
6379           if (size)
6380             {
6381               CLRC;
6382               emitcode ("", "%05d$:", tlbl->key + 100);
6383               outBitC (result);
6384             }
6385           else if (ifx)
6386             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6387         }
6388       else
6389         {
6390           for (; (size--); offset++)
6391             {
6392               // normal case
6393               // result = left & right
6394               if (AOP_TYPE (right) == AOP_LIT)
6395                 {
6396                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6397                   if (bytelit == 0)
6398                     {
6399                       aopPut (AOP (result),
6400                               aopGet (AOP (left), offset, FALSE, FALSE),
6401                               offset,
6402                               isOperandVolatile (result, FALSE));
6403                       continue;
6404                     }
6405                 }
6406               // faster than result <- left, anl result,right
6407               // and better if result is SFR
6408               if (AOP_TYPE (left) == AOP_ACC)
6409                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6410               else
6411                 {
6412                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6413                   emitcode ("xrl", "a,%s",
6414                             aopGet (AOP (left), offset, FALSE, TRUE));
6415                 }
6416               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6417             }
6418         }
6419     }
6420
6421 release:
6422   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6423   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6424   freeAsmop (result, NULL, ic, TRUE);
6425 }
6426
6427 /*-----------------------------------------------------------------*/
6428 /* genInline - write the inline code out                           */
6429 /*-----------------------------------------------------------------*/
6430 static void
6431 genInline (iCode * ic)
6432 {
6433   char *buffer, *bp, *bp1;
6434
6435   D(emitcode (";     genInline",""));
6436
6437   _G.inLine += (!options.asmpeep);
6438
6439   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6440   strcpy (buffer, IC_INLINE (ic));
6441
6442   /* emit each line as a code */
6443   while (*bp)
6444     {
6445       if (*bp == '\n')
6446         {
6447           *bp++ = '\0';
6448           emitcode (bp1, "");
6449           bp1 = bp;
6450         }
6451       else
6452         {
6453           /* Add \n for labels, not dirs such as c:\mydir */
6454           if ( (*bp == ':') && (isspace(bp[1])) )
6455             {
6456               bp++;
6457               *bp = '\0';
6458               bp++;
6459               emitcode (bp1, "");
6460               bp1 = bp;
6461             }
6462           else
6463             bp++;
6464         }
6465     }
6466   if (bp1 != bp)
6467     emitcode (bp1, "");
6468   /*     emitcode("",buffer); */
6469   _G.inLine -= (!options.asmpeep);
6470 }
6471
6472 /*-----------------------------------------------------------------*/
6473 /* genRRC - rotate right with carry                                */
6474 /*-----------------------------------------------------------------*/
6475 static void
6476 genRRC (iCode * ic)
6477 {
6478   operand *left, *result;
6479   int size, offset = 0;
6480   char *l;
6481
6482   D(emitcode (";     genRRC",""));
6483
6484   /* rotate right with carry */
6485   left = IC_LEFT (ic);
6486   result = IC_RESULT (ic);
6487   aopOp (left, ic, FALSE);
6488   aopOp (result, ic, FALSE);
6489
6490   /* move it to the result */
6491   size = AOP_SIZE (result);
6492   offset = size - 1;
6493   if (size == 1) { /* special case for 1 byte */
6494       l = aopGet (AOP (left), offset, FALSE, FALSE);
6495       MOVA (l);
6496       emitcode ("rr", "a");
6497       goto release;
6498   }
6499   CLRC;
6500   while (size--)
6501     {
6502       l = aopGet (AOP (left), offset, FALSE, FALSE);
6503       MOVA (l);
6504       emitcode ("rrc", "a");
6505       if (AOP_SIZE (result) > 1)
6506         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6507     }
6508   /* now we need to put the carry into the
6509      highest order byte of the result */
6510   if (AOP_SIZE (result) > 1)
6511     {
6512       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6513       MOVA (l);
6514     }
6515   emitcode ("mov", "acc.7,c");
6516  release:
6517   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6518   freeAsmop (left, NULL, ic, TRUE);
6519   freeAsmop (result, NULL, ic, TRUE);
6520 }
6521
6522 /*-----------------------------------------------------------------*/
6523 /* genRLC - generate code for rotate left with carry               */
6524 /*-----------------------------------------------------------------*/
6525 static void
6526 genRLC (iCode * ic)
6527 {
6528   operand *left, *result;
6529   int size, offset = 0;
6530   char *l;
6531
6532   D(emitcode (";     genRLC",""));
6533
6534   /* rotate right with carry */
6535   left = IC_LEFT (ic);
6536   result = IC_RESULT (ic);
6537   aopOp (left, ic, FALSE);
6538   aopOp (result, ic, FALSE);
6539
6540   /* move it to the result */
6541   size = AOP_SIZE (result);
6542   offset = 0;
6543   if (size--)
6544     {
6545       l = aopGet (AOP (left), offset, FALSE, FALSE);
6546       MOVA (l);
6547       if (size == 0) { /* special case for 1 byte */
6548               emitcode("rl","a");
6549               goto release;
6550       }
6551       emitcode ("add", "a,acc");
6552       if (AOP_SIZE (result) > 1)
6553         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6554       while (size--)
6555         {
6556           l = aopGet (AOP (left), offset, FALSE, FALSE);
6557           MOVA (l);
6558           emitcode ("rlc", "a");
6559           if (AOP_SIZE (result) > 1)
6560             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6561         }
6562     }
6563   /* now we need to put the carry into the
6564      highest order byte of the result */
6565   if (AOP_SIZE (result) > 1)
6566     {
6567       l = aopGet (AOP (result), 0, FALSE, FALSE);
6568       MOVA (l);
6569     }
6570   emitcode ("mov", "acc.0,c");
6571  release:
6572   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6573   freeAsmop (left, NULL, ic, TRUE);
6574   freeAsmop (result, NULL, ic, TRUE);
6575 }
6576
6577 /*-----------------------------------------------------------------*/
6578 /* genGetHbit - generates code get highest order bit               */
6579 /*-----------------------------------------------------------------*/
6580 static void
6581 genGetHbit (iCode * ic)
6582 {
6583   operand *left, *result;
6584
6585   D(emitcode (";     genGetHbit",""));
6586
6587   left = IC_LEFT (ic);
6588   result = IC_RESULT (ic);
6589   aopOp (left, ic, FALSE);
6590   aopOp (result, ic, FALSE);
6591
6592   /* get the highest order byte into a */
6593   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6594   if (AOP_TYPE (result) == AOP_CRY)
6595     {
6596       emitcode ("rlc", "a");
6597       outBitC (result);
6598     }
6599   else
6600     {
6601       emitcode ("rl", "a");
6602       emitcode ("anl", "a,#0x01");
6603       outAcc (result);
6604     }
6605
6606
6607   freeAsmop (left, NULL, ic, TRUE);
6608   freeAsmop (result, NULL, ic, TRUE);
6609 }
6610
6611 /*-----------------------------------------------------------------*/
6612 /* genSwap - generates code to swap nibbles or bytes               */
6613 /*-----------------------------------------------------------------*/
6614 static void
6615 genSwap (iCode * ic)
6616 {
6617   operand *left, *result;
6618
6619   D(emitcode (";     genSwap",""));
6620
6621   left = IC_LEFT (ic);
6622   result = IC_RESULT (ic);
6623   aopOp (left, ic, FALSE);
6624   aopOp (result, ic, FALSE);
6625
6626   switch (AOP_SIZE (left))
6627     {
6628     case 1: /* swap nibbles in byte */
6629       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6630       emitcode ("swap", "a");
6631       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6632       break;
6633     case 2: /* swap bytes in word */
6634       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6635         {
6636           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6637           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6638                   0, isOperandVolatile (result, FALSE));
6639           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6640         }
6641       else if (operandsEqu (left, result))
6642         {
6643           char * reg = "a";
6644           bool pushedB = FALSE, leftInB = FALSE;
6645
6646           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6647           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6648             {
6649               pushedB = pushB ();
6650               emitcode ("mov", "b,a");
6651               reg = "b";
6652               leftInB = TRUE;
6653             }
6654           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6655                   0, isOperandVolatile (result, FALSE));
6656           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6657
6658           if (leftInB)
6659             popB (pushedB);
6660         }
6661       else
6662         {
6663           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6664                   0, isOperandVolatile (result, FALSE));
6665           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6666                   1, isOperandVolatile (result, FALSE));
6667         }
6668       break;
6669     default:
6670       wassertl(FALSE, "unsupported SWAP operand size");
6671     }
6672
6673   freeAsmop (left, NULL, ic, TRUE);
6674   freeAsmop (result, NULL, ic, TRUE);
6675 }
6676
6677
6678 /*-----------------------------------------------------------------*/
6679 /* AccRol - rotate left accumulator by known count                 */
6680 /*-----------------------------------------------------------------*/
6681 static void
6682 AccRol (int shCount)
6683 {
6684   shCount &= 0x0007;            // shCount : 0..7
6685
6686   switch (shCount)
6687     {
6688     case 0:
6689       break;
6690     case 1:
6691       emitcode ("rl", "a");
6692       break;
6693     case 2:
6694       emitcode ("rl", "a");
6695       emitcode ("rl", "a");
6696       break;
6697     case 3:
6698       emitcode ("swap", "a");
6699       emitcode ("rr", "a");
6700       break;
6701     case 4:
6702       emitcode ("swap", "a");
6703       break;
6704     case 5:
6705       emitcode ("swap", "a");
6706       emitcode ("rl", "a");
6707       break;
6708     case 6:
6709       emitcode ("rr", "a");
6710       emitcode ("rr", "a");
6711       break;
6712     case 7:
6713       emitcode ("rr", "a");
6714       break;
6715     }
6716 }
6717
6718 /*-----------------------------------------------------------------*/
6719 /* AccLsh - left shift accumulator by known count                  */
6720 /*-----------------------------------------------------------------*/
6721 static void
6722 AccLsh (int shCount)
6723 {
6724   if (shCount != 0)
6725     {
6726       if (shCount == 1)
6727         emitcode ("add", "a,acc");
6728       else if (shCount == 2)
6729         {
6730           emitcode ("add", "a,acc");
6731           emitcode ("add", "a,acc");
6732         }
6733       else
6734         {
6735           /* rotate left accumulator */
6736           AccRol (shCount);
6737           /* and kill the lower order bits */
6738           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6739         }
6740     }
6741 }
6742
6743 /*-----------------------------------------------------------------*/
6744 /* AccRsh - right shift accumulator by known count                 */
6745 /*-----------------------------------------------------------------*/
6746 static void
6747 AccRsh (int shCount)
6748 {
6749   if (shCount != 0)
6750     {
6751       if (shCount == 1)
6752         {
6753           CLRC;
6754           emitcode ("rrc", "a");
6755         }
6756       else
6757         {
6758           /* rotate right accumulator */
6759           AccRol (8 - shCount);
6760           /* and kill the higher order bits */
6761           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6762         }
6763     }
6764 }
6765
6766 /*-----------------------------------------------------------------*/
6767 /* AccSRsh - signed right shift accumulator by known count                 */
6768 /*-----------------------------------------------------------------*/
6769 static void
6770 AccSRsh (int shCount)
6771 {
6772   symbol *tlbl;
6773   if (shCount != 0)
6774     {
6775       if (shCount == 1)
6776         {
6777           emitcode ("mov", "c,acc.7");
6778           emitcode ("rrc", "a");
6779         }
6780       else if (shCount == 2)
6781         {
6782           emitcode ("mov", "c,acc.7");
6783           emitcode ("rrc", "a");
6784           emitcode ("mov", "c,acc.7");
6785           emitcode ("rrc", "a");
6786         }
6787       else
6788         {
6789           tlbl = newiTempLabel (NULL);
6790           /* rotate right accumulator */
6791           AccRol (8 - shCount);
6792           /* and kill the higher order bits */
6793           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6794           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6795           emitcode ("orl", "a,#0x%02x",
6796                     (unsigned char) ~SRMask[shCount]);
6797           emitcode ("", "%05d$:", tlbl->key + 100);
6798         }
6799     }
6800 }
6801
6802 /*-----------------------------------------------------------------*/
6803 /* shiftR1Left2Result - shift right one byte from left to result   */
6804 /*-----------------------------------------------------------------*/
6805 static void
6806 shiftR1Left2Result (operand * left, int offl,
6807                     operand * result, int offr,
6808                     int shCount, int sign)
6809 {
6810   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6811   /* shift right accumulator */
6812   if (sign)
6813     AccSRsh (shCount);
6814   else
6815     AccRsh (shCount);
6816   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6817 }
6818
6819 /*-----------------------------------------------------------------*/
6820 /* shiftL1Left2Result - shift left one byte from left to result    */
6821 /*-----------------------------------------------------------------*/
6822 static void
6823 shiftL1Left2Result (operand * left, int offl,
6824                     operand * result, int offr, int shCount)
6825 {
6826   char *l;
6827   l = aopGet (AOP (left), offl, FALSE, FALSE);
6828   MOVA (l);
6829   /* shift left accumulator */
6830   AccLsh (shCount);
6831   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6832 }
6833
6834 /*-----------------------------------------------------------------*/
6835 /* movLeft2Result - move byte from left to result                  */
6836 /*-----------------------------------------------------------------*/
6837 static void
6838 movLeft2Result (operand * left, int offl,
6839                 operand * result, int offr, int sign)
6840 {
6841   char *l;
6842   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
6843     {
6844       l = aopGet (AOP (left), offl, FALSE, FALSE);
6845
6846       if (*l == '@' && (IS_AOP_PREG (result)))
6847         {
6848           emitcode ("mov", "a,%s", l);
6849           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6850         }
6851       else
6852         {
6853           if (!sign)
6854             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
6855           else
6856             {
6857               /* MSB sign in acc.7 ! */
6858               if (getDataSize (left) == offl + 1)
6859                 {
6860                   emitcode ("mov", "a,%s", l);
6861                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6862                 }
6863             }
6864         }
6865     }
6866 }
6867
6868 /*-----------------------------------------------------------------*/
6869 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
6870 /*-----------------------------------------------------------------*/
6871 static void
6872 AccAXRrl1 (char *x)
6873 {
6874   emitcode ("rrc", "a");
6875   emitcode ("xch", "a,%s", x);
6876   emitcode ("rrc", "a");
6877   emitcode ("xch", "a,%s", x);
6878 }
6879
6880 /*-----------------------------------------------------------------*/
6881 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
6882 /*-----------------------------------------------------------------*/
6883 static void
6884 AccAXLrl1 (char *x)
6885 {
6886   emitcode ("xch", "a,%s", x);
6887   emitcode ("rlc", "a");
6888   emitcode ("xch", "a,%s", x);
6889   emitcode ("rlc", "a");
6890 }
6891
6892 /*-----------------------------------------------------------------*/
6893 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
6894 /*-----------------------------------------------------------------*/
6895 static void
6896 AccAXLsh1 (char *x)
6897 {
6898   emitcode ("xch", "a,%s", x);
6899   emitcode ("add", "a,acc");
6900   emitcode ("xch", "a,%s", x);
6901   emitcode ("rlc", "a");
6902 }
6903
6904 /*-----------------------------------------------------------------*/
6905 /* AccAXLsh - left shift a:x by known count (0..7)                 */
6906 /*-----------------------------------------------------------------*/
6907 static void
6908 AccAXLsh (char *x, int shCount)
6909 {
6910   switch (shCount)
6911     {
6912     case 0:
6913       break;
6914     case 1:
6915       AccAXLsh1 (x);
6916       break;
6917     case 2:
6918       AccAXLsh1 (x);
6919       AccAXLsh1 (x);
6920       break;
6921     case 3:
6922     case 4:
6923     case 5:                     // AAAAABBB:CCCCCDDD
6924
6925       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
6926
6927       emitcode ("anl", "a,#0x%02x",
6928                 SLMask[shCount]);       // BBB00000:CCCCCDDD
6929
6930       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
6931
6932       AccRol (shCount);         // DDDCCCCC:BBB00000
6933
6934       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
6935
6936       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
6937
6938       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
6939
6940       emitcode ("anl", "a,#0x%02x",
6941                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
6942
6943       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
6944
6945       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
6946
6947       break;
6948     case 6:                     // AAAAAABB:CCCCCCDD
6949       emitcode ("anl", "a,#0x%02x",
6950                 SRMask[shCount]);       // 000000BB:CCCCCCDD
6951       emitcode ("mov", "c,acc.0");      // c = B
6952       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
6953 #if 0 // REMOVE ME
6954       AccAXRrl1 (x);            // BCCCCCCD:D000000B
6955       AccAXRrl1 (x);            // BBCCCCCC:DD000000
6956 #else
6957       emitcode("rrc","a");
6958       emitcode("xch","a,%s", x);
6959       emitcode("rrc","a");
6960       emitcode("mov","c,acc.0"); //<< get correct bit
6961       emitcode("xch","a,%s", x);
6962
6963       emitcode("rrc","a");
6964       emitcode("xch","a,%s", x);
6965       emitcode("rrc","a");
6966       emitcode("xch","a,%s", x);
6967 #endif
6968       break;
6969     case 7:                     // a:x <<= 7
6970
6971       emitcode ("anl", "a,#0x%02x",
6972                 SRMask[shCount]);       // 0000000B:CCCCCCCD
6973
6974       emitcode ("mov", "c,acc.0");      // c = B
6975
6976       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
6977
6978       AccAXRrl1 (x);            // BCCCCCCC:D0000000
6979
6980       break;
6981     default:
6982       break;
6983     }
6984 }
6985
6986 /*-----------------------------------------------------------------*/
6987 /* AccAXRsh - right shift a:x known count (0..7)                   */
6988 /*-----------------------------------------------------------------*/
6989 static void
6990 AccAXRsh (char *x, int shCount)
6991 {
6992   switch (shCount)
6993     {
6994     case 0:
6995       break;
6996     case 1:
6997       CLRC;
6998       AccAXRrl1 (x);            // 0->a:x
6999
7000       break;
7001     case 2:
7002       CLRC;
7003       AccAXRrl1 (x);            // 0->a:x
7004
7005       CLRC;
7006       AccAXRrl1 (x);            // 0->a:x
7007
7008       break;
7009     case 3:
7010     case 4:
7011     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7012
7013       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7014
7015       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7016
7017       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7018
7019       emitcode ("anl", "a,#0x%02x",
7020                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7021
7022       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7023
7024       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7025
7026       emitcode ("anl", "a,#0x%02x",
7027                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7028
7029       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7030
7031       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7032
7033       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7034
7035       break;
7036     case 6:                     // AABBBBBB:CCDDDDDD
7037
7038       emitcode ("mov", "c,acc.7");
7039       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7040
7041       emitcode ("mov", "c,acc.7");
7042       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7043
7044       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7045
7046       emitcode ("anl", "a,#0x%02x",
7047                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7048
7049       break;
7050     case 7:                     // ABBBBBBB:CDDDDDDD
7051
7052       emitcode ("mov", "c,acc.7");      // c = A
7053
7054       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7055
7056       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7057
7058       emitcode ("anl", "a,#0x%02x",
7059                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7060
7061       break;
7062     default:
7063       break;
7064     }
7065 }
7066
7067 /*-----------------------------------------------------------------*/
7068 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7069 /*-----------------------------------------------------------------*/
7070 static void
7071 AccAXRshS (char *x, int shCount)
7072 {
7073   symbol *tlbl;
7074   switch (shCount)
7075     {
7076     case 0:
7077       break;
7078     case 1:
7079       emitcode ("mov", "c,acc.7");
7080       AccAXRrl1 (x);            // s->a:x
7081
7082       break;
7083     case 2:
7084       emitcode ("mov", "c,acc.7");
7085       AccAXRrl1 (x);            // s->a:x
7086
7087       emitcode ("mov", "c,acc.7");
7088       AccAXRrl1 (x);            // s->a:x
7089
7090       break;
7091     case 3:
7092     case 4:
7093     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7094
7095       tlbl = newiTempLabel (NULL);
7096       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7097
7098       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7099
7100       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7101
7102       emitcode ("anl", "a,#0x%02x",
7103                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7104
7105       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7106
7107       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7108
7109       emitcode ("anl", "a,#0x%02x",
7110                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7111
7112       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7113
7114       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7115
7116       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7117
7118       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7119       emitcode ("orl", "a,#0x%02x",
7120                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7121
7122       emitcode ("", "%05d$:", tlbl->key + 100);
7123       break;                    // SSSSAAAA:BBBCCCCC
7124
7125     case 6:                     // AABBBBBB:CCDDDDDD
7126
7127       tlbl = newiTempLabel (NULL);
7128       emitcode ("mov", "c,acc.7");
7129       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7130
7131       emitcode ("mov", "c,acc.7");
7132       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7133
7134       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7135
7136       emitcode ("anl", "a,#0x%02x",
7137                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7138
7139       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7140       emitcode ("orl", "a,#0x%02x",
7141                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7142
7143       emitcode ("", "%05d$:", tlbl->key + 100);
7144       break;
7145     case 7:                     // ABBBBBBB:CDDDDDDD
7146
7147       tlbl = newiTempLabel (NULL);
7148       emitcode ("mov", "c,acc.7");      // c = A
7149
7150       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7151
7152       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7153
7154       emitcode ("anl", "a,#0x%02x",
7155                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7156
7157       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7158       emitcode ("orl", "a,#0x%02x",
7159                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7160
7161       emitcode ("", "%05d$:", tlbl->key + 100);
7162       break;
7163     default:
7164       break;
7165     }
7166 }
7167
7168 /*-----------------------------------------------------------------*/
7169 /* shiftL2Left2Result - shift left two bytes from left to result   */
7170 /*-----------------------------------------------------------------*/
7171 static void
7172 shiftL2Left2Result (operand * left, int offl,
7173                     operand * result, int offr, int shCount)
7174 {
7175   if (sameRegs (AOP (result), AOP (left)) &&
7176       ((offl + MSB16) == offr))
7177     {
7178       /* don't crash result[offr] */
7179       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7180       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7181     }
7182   else
7183     {
7184       movLeft2Result (left, offl, result, offr, 0);
7185       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7186     }
7187   /* ax << shCount (x = lsb(result)) */
7188   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7189   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7190 }
7191
7192
7193 /*-----------------------------------------------------------------*/
7194 /* shiftR2Left2Result - shift right two bytes from left to result  */
7195 /*-----------------------------------------------------------------*/
7196 static void
7197 shiftR2Left2Result (operand * left, int offl,
7198                     operand * result, int offr,
7199                     int shCount, int sign)
7200 {
7201   if (sameRegs (AOP (result), AOP (left)) &&
7202       ((offl + MSB16) == offr))
7203     {
7204       /* don't crash result[offr] */
7205       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7206       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7207     }
7208   else
7209     {
7210       movLeft2Result (left, offl, result, offr, 0);
7211       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7212     }
7213   /* a:x >> shCount (x = lsb(result)) */
7214   if (sign)
7215     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7216   else
7217     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7218   if (getDataSize (result) > 1)
7219     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7220 }
7221
7222 /*-----------------------------------------------------------------*/
7223 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7224 /*-----------------------------------------------------------------*/
7225 static void
7226 shiftLLeftOrResult (operand * left, int offl,
7227                     operand * result, int offr, int shCount)
7228 {
7229   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7230   /* shift left accumulator */
7231   AccLsh (shCount);
7232   /* or with result */
7233   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7234   /* back to result */
7235   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7236 }
7237
7238 /*-----------------------------------------------------------------*/
7239 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7240 /*-----------------------------------------------------------------*/
7241 static void
7242 shiftRLeftOrResult (operand * left, int offl,
7243                     operand * result, int offr, int shCount)
7244 {
7245   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7246   /* shift right accumulator */
7247   AccRsh (shCount);
7248   /* or with result */
7249   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7250   /* back to result */
7251   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7252 }
7253
7254 /*-----------------------------------------------------------------*/
7255 /* genlshOne - left shift a one byte quantity by known count       */
7256 /*-----------------------------------------------------------------*/
7257 static void
7258 genlshOne (operand * result, operand * left, int shCount)
7259 {
7260   D(emitcode (";     genlshOne",""));
7261
7262   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7263 }
7264
7265 /*-----------------------------------------------------------------*/
7266 /* genlshTwo - left shift two bytes by known amount != 0           */
7267 /*-----------------------------------------------------------------*/
7268 static void
7269 genlshTwo (operand * result, operand * left, int shCount)
7270 {
7271   int size;
7272
7273   D(emitcode (";     genlshTwo",""));
7274
7275   size = getDataSize (result);
7276
7277   /* if shCount >= 8 */
7278   if (shCount >= 8)
7279     {
7280       shCount -= 8;
7281
7282       if (size > 1)
7283         {
7284           if (shCount)
7285             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7286           else
7287             movLeft2Result (left, LSB, result, MSB16, 0);
7288         }
7289       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7290     }
7291
7292   /*  1 <= shCount <= 7 */
7293   else
7294     {
7295       if (size == 1)
7296         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7297       else
7298         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7299     }
7300 }
7301
7302 /*-----------------------------------------------------------------*/
7303 /* shiftLLong - shift left one long from left to result            */
7304 /* offl = LSB or MSB16                                             */
7305 /*-----------------------------------------------------------------*/
7306 static void
7307 shiftLLong (operand * left, operand * result, int offr)
7308 {
7309   char *l;
7310   int size = AOP_SIZE (result);
7311
7312   if (size >= LSB + offr)
7313     {
7314       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7315       MOVA (l);
7316       emitcode ("add", "a,acc");
7317       if (sameRegs (AOP (left), AOP (result)) &&
7318           size >= MSB16 + offr && offr != LSB)
7319         emitcode ("xch", "a,%s",
7320                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7321       else
7322         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7323     }
7324
7325   if (size >= MSB16 + offr)
7326     {
7327       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7328         {
7329           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7330           MOVA (l);
7331         }
7332       emitcode ("rlc", "a");
7333       if (sameRegs (AOP (left), AOP (result)) &&
7334           size >= MSB24 + offr && offr != LSB)
7335         emitcode ("xch", "a,%s",
7336                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7337       else
7338         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7339     }
7340
7341   if (size >= MSB24 + offr)
7342     {
7343       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7344         {
7345           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7346           MOVA (l);
7347         }
7348       emitcode ("rlc", "a");
7349       if (sameRegs (AOP (left), AOP (result)) &&
7350           size >= MSB32 + offr && offr != LSB)
7351         emitcode ("xch", "a,%s",
7352                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7353       else
7354         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7355     }
7356
7357   if (size > MSB32 + offr)
7358     {
7359       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7360         {
7361           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7362           MOVA (l);
7363         }
7364       emitcode ("rlc", "a");
7365       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7366     }
7367   if (offr != LSB)
7368     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7369 }
7370
7371 /*-----------------------------------------------------------------*/
7372 /* genlshFour - shift four byte by a known amount != 0             */
7373 /*-----------------------------------------------------------------*/
7374 static void
7375 genlshFour (operand * result, operand * left, int shCount)
7376 {
7377   int size;
7378
7379   D(emitcode (";     genlshFour",""));
7380
7381   size = AOP_SIZE (result);
7382
7383   /* if shifting more that 3 bytes */
7384   if (shCount >= 24)
7385     {
7386       shCount -= 24;
7387       if (shCount)
7388         /* lowest order of left goes to the highest
7389            order of the destination */
7390         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7391       else
7392         movLeft2Result (left, LSB, result, MSB32, 0);
7393       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7394       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7395       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7396       return;
7397     }
7398
7399   /* more than two bytes */
7400   else if (shCount >= 16)
7401     {
7402       /* lower order two bytes goes to higher order two bytes */
7403       shCount -= 16;
7404       /* if some more remaining */
7405       if (shCount)
7406         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7407       else
7408         {
7409           movLeft2Result (left, MSB16, result, MSB32, 0);
7410           movLeft2Result (left, LSB, result, MSB24, 0);
7411         }
7412       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7413       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7414       return;
7415     }
7416
7417   /* if more than 1 byte */
7418   else if (shCount >= 8)
7419     {
7420       /* lower order three bytes goes to higher order  three bytes */
7421       shCount -= 8;
7422       if (size == 2)
7423         {
7424           if (shCount)
7425             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7426           else
7427             movLeft2Result (left, LSB, result, MSB16, 0);
7428         }
7429       else
7430         {                       /* size = 4 */
7431           if (shCount == 0)
7432             {
7433               movLeft2Result (left, MSB24, result, MSB32, 0);
7434               movLeft2Result (left, MSB16, result, MSB24, 0);
7435               movLeft2Result (left, LSB, result, MSB16, 0);
7436               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7437             }
7438           else if (shCount == 1)
7439             shiftLLong (left, result, MSB16);
7440           else
7441             {
7442               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7443               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7444               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7445               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7446             }
7447         }
7448     }
7449
7450   /* 1 <= shCount <= 7 */
7451   else if (shCount <= 2)
7452     {
7453       shiftLLong (left, result, LSB);
7454       if (shCount == 2)
7455         shiftLLong (result, result, LSB);
7456     }
7457   /* 3 <= shCount <= 7, optimize */
7458   else
7459     {
7460       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7461       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7462       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7463     }
7464 }
7465
7466 /*-----------------------------------------------------------------*/
7467 /* genLeftShiftLiteral - left shifting by known count              */
7468 /*-----------------------------------------------------------------*/
7469 static void
7470 genLeftShiftLiteral (operand * left,
7471                      operand * right,
7472                      operand * result,
7473                      iCode * ic)
7474 {
7475   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7476   int size;
7477
7478   D(emitcode (";     genLeftShiftLiteral",""));
7479
7480   freeAsmop (right, NULL, ic, TRUE);
7481
7482   aopOp (left, ic, FALSE);
7483   aopOp (result, ic, FALSE);
7484
7485   size = getSize (operandType (result));
7486
7487 #if VIEW_SIZE
7488   emitcode ("; shift left ", "result %d, left %d", size,
7489             AOP_SIZE (left));
7490 #endif
7491
7492   /* I suppose that the left size >= result size */
7493   if (shCount == 0)
7494     {
7495       while (size--)
7496         {
7497           movLeft2Result (left, size, result, size, 0);
7498         }
7499     }
7500
7501   else if (shCount >= (size * 8))
7502     while (size--)
7503       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7504   else
7505     {
7506       switch (size)
7507         {
7508         case 1:
7509           genlshOne (result, left, shCount);
7510           break;
7511
7512         case 2:
7513           genlshTwo (result, left, shCount);
7514           break;
7515
7516         case 4:
7517           genlshFour (result, left, shCount);
7518           break;
7519         default:
7520           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7521                   "*** ack! mystery literal shift!\n");
7522           break;
7523         }
7524     }
7525   freeAsmop (left, NULL, ic, TRUE);
7526   freeAsmop (result, NULL, ic, TRUE);
7527 }
7528
7529 /*-----------------------------------------------------------------*/
7530 /* genLeftShift - generates code for left shifting                 */
7531 /*-----------------------------------------------------------------*/
7532 static void
7533 genLeftShift (iCode * ic)
7534 {
7535   operand *left, *right, *result;
7536   int size, offset;
7537   char *l;
7538   symbol *tlbl, *tlbl1;
7539   bool pushedB;
7540
7541   D(emitcode (";     genLeftShift",""));
7542
7543   right = IC_RIGHT (ic);
7544   left = IC_LEFT (ic);
7545   result = IC_RESULT (ic);
7546
7547   aopOp (right, ic, FALSE);
7548
7549   /* if the shift count is known then do it
7550      as efficiently as possible */
7551   if (AOP_TYPE (right) == AOP_LIT)
7552     {
7553       genLeftShiftLiteral (left, right, result, ic);
7554       return;
7555     }
7556
7557   /* shift count is unknown then we have to form
7558      a loop get the loop count in B : Note: we take
7559      only the lower order byte since shifting
7560      more that 32 bits make no sense anyway, ( the
7561      largest size of an object can be only 32 bits ) */
7562
7563   pushedB = pushB ();
7564   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7565   emitcode ("inc", "b");
7566   freeAsmop (right, NULL, ic, TRUE);
7567   aopOp (left, ic, FALSE);
7568   aopOp (result, ic, FALSE);
7569
7570   /* now move the left to the result if they are not the same */
7571   if (!sameRegs (AOP (left), AOP (result)) &&
7572       AOP_SIZE (result) > 1)
7573     {
7574
7575       size = AOP_SIZE (result);
7576       offset = 0;
7577       while (size--)
7578         {
7579           l = aopGet (AOP (left), offset, FALSE, TRUE);
7580           if (*l == '@' && (IS_AOP_PREG (result)))
7581             {
7582
7583               emitcode ("mov", "a,%s", l);
7584               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7585             }
7586           else
7587             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7588           offset++;
7589         }
7590     }
7591
7592   tlbl = newiTempLabel (NULL);
7593   size = AOP_SIZE (result);
7594   offset = 0;
7595   tlbl1 = newiTempLabel (NULL);
7596
7597   /* if it is only one byte then */
7598   if (size == 1)
7599     {
7600       symbol *tlbl1 = newiTempLabel (NULL);
7601
7602       l = aopGet (AOP (left), 0, FALSE, FALSE);
7603       MOVA (l);
7604       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7605       emitcode ("", "%05d$:", tlbl->key + 100);
7606       emitcode ("add", "a,acc");
7607       emitcode ("", "%05d$:", tlbl1->key + 100);
7608       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7609       popB (pushedB);
7610       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7611       goto release;
7612     }
7613
7614   reAdjustPreg (AOP (result));
7615
7616   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7617   emitcode ("", "%05d$:", tlbl->key + 100);
7618   l = aopGet (AOP (result), offset, FALSE, FALSE);
7619   MOVA (l);
7620   emitcode ("add", "a,acc");
7621   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7622   while (--size)
7623     {
7624       l = aopGet (AOP (result), offset, FALSE, FALSE);
7625       MOVA (l);
7626       emitcode ("rlc", "a");
7627       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7628     }
7629   reAdjustPreg (AOP (result));
7630
7631   emitcode ("", "%05d$:", tlbl1->key + 100);
7632   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7633   popB (pushedB);
7634 release:
7635   freeAsmop (left, NULL, ic, TRUE);
7636   freeAsmop (result, NULL, ic, TRUE);
7637 }
7638
7639 /*-----------------------------------------------------------------*/
7640 /* genrshOne - right shift a one byte quantity by known count      */
7641 /*-----------------------------------------------------------------*/
7642 static void
7643 genrshOne (operand * result, operand * left,
7644            int shCount, int sign)
7645 {
7646   D(emitcode (";     genrshOne",""));
7647
7648   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7649 }
7650
7651 /*-----------------------------------------------------------------*/
7652 /* genrshTwo - right shift two bytes by known amount != 0          */
7653 /*-----------------------------------------------------------------*/
7654 static void
7655 genrshTwo (operand * result, operand * left,
7656            int shCount, int sign)
7657 {
7658   D(emitcode (";     genrshTwo",""));
7659
7660   /* if shCount >= 8 */
7661   if (shCount >= 8)
7662     {
7663       shCount -= 8;
7664       if (shCount)
7665         shiftR1Left2Result (left, MSB16, result, LSB,
7666                             shCount, sign);
7667       else
7668         movLeft2Result (left, MSB16, result, LSB, sign);
7669       addSign (result, MSB16, sign);
7670     }
7671
7672   /*  1 <= shCount <= 7 */
7673   else
7674     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7675 }
7676
7677 /*-----------------------------------------------------------------*/
7678 /* shiftRLong - shift right one long from left to result           */
7679 /* offl = LSB or MSB16                                             */
7680 /*-----------------------------------------------------------------*/
7681 static void
7682 shiftRLong (operand * left, int offl,
7683             operand * result, int sign)
7684 {
7685   int isSameRegs=sameRegs(AOP(left),AOP(result));
7686
7687   if (isSameRegs && offl>1) {
7688     // we are in big trouble, but this shouldn't happen
7689     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7690   }
7691
7692   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7693
7694   if (offl==MSB16) {
7695     // shift is > 8
7696     if (sign) {
7697       emitcode ("rlc", "a");
7698       emitcode ("subb", "a,acc");
7699       if (isSameRegs)
7700         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7701       else {
7702         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7703         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7704       }
7705     } else {
7706       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7707     }
7708   }
7709
7710   if (!sign) {
7711     emitcode ("clr", "c");
7712   } else {
7713     emitcode ("mov", "c,acc.7");
7714   }
7715
7716   emitcode ("rrc", "a");
7717
7718   if (isSameRegs && offl==MSB16) {
7719     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7720   } else {
7721     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7722     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7723   }
7724
7725   emitcode ("rrc", "a");
7726   if (isSameRegs && offl==1) {
7727     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7728   } else {
7729     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7730     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7731   }
7732   emitcode ("rrc", "a");
7733   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7734
7735   if (offl == LSB)
7736     {
7737       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7738       emitcode ("rrc", "a");
7739       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7740     }
7741 }
7742
7743 /*-----------------------------------------------------------------*/
7744 /* genrshFour - shift four byte by a known amount != 0             */
7745 /*-----------------------------------------------------------------*/
7746 static void
7747 genrshFour (operand * result, operand * left,
7748             int shCount, int sign)
7749 {
7750   D(emitcode (";     genrshFour",""));
7751
7752   /* if shifting more that 3 bytes */
7753   if (shCount >= 24)
7754     {
7755       shCount -= 24;
7756       if (shCount)
7757         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7758       else
7759         movLeft2Result (left, MSB32, result, LSB, sign);
7760       addSign (result, MSB16, sign);
7761     }
7762   else if (shCount >= 16)
7763     {
7764       shCount -= 16;
7765       if (shCount)
7766         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7767       else
7768         {
7769           movLeft2Result (left, MSB24, result, LSB, 0);
7770           movLeft2Result (left, MSB32, result, MSB16, sign);
7771         }
7772       addSign (result, MSB24, sign);
7773     }
7774   else if (shCount >= 8)
7775     {
7776       shCount -= 8;
7777       if (shCount == 1)
7778         shiftRLong (left, MSB16, result, sign);
7779       else if (shCount == 0)
7780         {
7781           movLeft2Result (left, MSB16, result, LSB, 0);
7782           movLeft2Result (left, MSB24, result, MSB16, 0);
7783           movLeft2Result (left, MSB32, result, MSB24, sign);
7784           addSign (result, MSB32, sign);
7785         }
7786       else
7787         {
7788           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7789           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7790           /* the last shift is signed */
7791           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7792           addSign (result, MSB32, sign);
7793         }
7794     }
7795   else
7796     {                           /* 1 <= shCount <= 7 */
7797       if (shCount <= 2)
7798         {
7799           shiftRLong (left, LSB, result, sign);
7800           if (shCount == 2)
7801             shiftRLong (result, LSB, result, sign);
7802         }
7803       else
7804         {
7805           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7806           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7807           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7808         }
7809     }
7810 }
7811
7812 /*-----------------------------------------------------------------*/
7813 /* genRightShiftLiteral - right shifting by known count            */
7814 /*-----------------------------------------------------------------*/
7815 static void
7816 genRightShiftLiteral (operand * left,
7817                       operand * right,
7818                       operand * result,
7819                       iCode * ic,
7820                       int sign)
7821 {
7822   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7823   int size;
7824
7825   D(emitcode (";     genRightShiftLiteral",""));
7826
7827   freeAsmop (right, NULL, ic, TRUE);
7828
7829   aopOp (left, ic, FALSE);
7830   aopOp (result, ic, FALSE);
7831
7832 #if VIEW_SIZE
7833   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
7834             AOP_SIZE (left));
7835 #endif
7836
7837   size = getDataSize (left);
7838   /* test the LEFT size !!! */
7839
7840   /* I suppose that the left size >= result size */
7841   if (shCount == 0)
7842     {
7843       size = getDataSize (result);
7844       while (size--)
7845         movLeft2Result (left, size, result, size, 0);
7846     }
7847
7848   else if (shCount >= (size * 8))
7849     {
7850       if (sign) {
7851         /* get sign in acc.7 */
7852         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
7853       }
7854       addSign (result, LSB, sign);
7855     }
7856   else
7857     {
7858       switch (size)
7859         {
7860         case 1:
7861           genrshOne (result, left, shCount, sign);
7862           break;
7863
7864         case 2:
7865           genrshTwo (result, left, shCount, sign);
7866           break;
7867
7868         case 4:
7869           genrshFour (result, left, shCount, sign);
7870           break;
7871         default:
7872           break;
7873         }
7874     }
7875   freeAsmop (left, NULL, ic, TRUE);
7876   freeAsmop (result, NULL, ic, TRUE);
7877 }
7878
7879 /*-----------------------------------------------------------------*/
7880 /* genSignedRightShift - right shift of signed number              */
7881 /*-----------------------------------------------------------------*/
7882 static void
7883 genSignedRightShift (iCode * ic)
7884 {
7885   operand *right, *left, *result;
7886   int size, offset;
7887   char *l;
7888   symbol *tlbl, *tlbl1;
7889   bool pushedB;
7890
7891   D(emitcode (";     genSignedRightShift",""));
7892
7893   /* we do it the hard way put the shift count in b
7894      and loop thru preserving the sign */
7895
7896   right = IC_RIGHT (ic);
7897   left = IC_LEFT (ic);
7898   result = IC_RESULT (ic);
7899
7900   aopOp (right, ic, FALSE);
7901
7902
7903   if (AOP_TYPE (right) == AOP_LIT)
7904     {
7905       genRightShiftLiteral (left, right, result, ic, 1);
7906       return;
7907     }
7908   /* shift count is unknown then we have to form
7909      a loop get the loop count in B : Note: we take
7910      only the lower order byte since shifting
7911      more that 32 bits make no sense anyway, ( the
7912      largest size of an object can be only 32 bits ) */
7913
7914   pushedB = pushB ();
7915   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7916   emitcode ("inc", "b");
7917   freeAsmop (right, NULL, ic, TRUE);
7918   aopOp (left, ic, FALSE);
7919   aopOp (result, ic, FALSE);
7920
7921   /* now move the left to the result if they are not the
7922      same */
7923   if (!sameRegs (AOP (left), AOP (result)) &&
7924       AOP_SIZE (result) > 1)
7925     {
7926
7927       size = AOP_SIZE (result);
7928       offset = 0;
7929       while (size--)
7930         {
7931           l = aopGet (AOP (left), offset, FALSE, TRUE);
7932           if (*l == '@' && IS_AOP_PREG (result))
7933             {
7934
7935               emitcode ("mov", "a,%s", l);
7936               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7937             }
7938           else
7939             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7940           offset++;
7941         }
7942     }
7943
7944   /* mov the highest order bit to OVR */
7945   tlbl = newiTempLabel (NULL);
7946   tlbl1 = newiTempLabel (NULL);
7947
7948   size = AOP_SIZE (result);
7949   offset = size - 1;
7950   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
7951   emitcode ("rlc", "a");
7952   emitcode ("mov", "ov,c");
7953   /* if it is only one byte then */
7954   if (size == 1)
7955     {
7956       l = aopGet (AOP (left), 0, FALSE, FALSE);
7957       MOVA (l);
7958       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7959       emitcode ("", "%05d$:", tlbl->key + 100);
7960       emitcode ("mov", "c,ov");
7961       emitcode ("rrc", "a");
7962       emitcode ("", "%05d$:", tlbl1->key + 100);
7963       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7964       popB (pushedB);
7965       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7966       goto release;
7967     }
7968
7969   reAdjustPreg (AOP (result));
7970   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7971   emitcode ("", "%05d$:", tlbl->key + 100);
7972   emitcode ("mov", "c,ov");
7973   while (size--)
7974     {
7975       l = aopGet (AOP (result), offset, FALSE, FALSE);
7976       MOVA (l);
7977       emitcode ("rrc", "a");
7978       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7979     }
7980   reAdjustPreg (AOP (result));
7981   emitcode ("", "%05d$:", tlbl1->key + 100);
7982   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7983   popB (pushedB);
7984
7985 release:
7986   freeAsmop (left, NULL, ic, TRUE);
7987   freeAsmop (result, NULL, ic, TRUE);
7988 }
7989
7990 /*-----------------------------------------------------------------*/
7991 /* genRightShift - generate code for right shifting                */
7992 /*-----------------------------------------------------------------*/
7993 static void
7994 genRightShift (iCode * ic)
7995 {
7996   operand *right, *left, *result;
7997   sym_link *letype;
7998   int size, offset;
7999   char *l;
8000   symbol *tlbl, *tlbl1;
8001   bool pushedB;
8002
8003   D(emitcode (";     genRightShift",""));
8004
8005   /* if signed then we do it the hard way preserve the
8006      sign bit moving it inwards */
8007   letype = getSpec (operandType (IC_LEFT (ic)));
8008
8009   if (!SPEC_USIGN (letype))
8010     {
8011       genSignedRightShift (ic);
8012       return;
8013     }
8014
8015   /* signed & unsigned types are treated the same : i.e. the
8016      signed is NOT propagated inwards : quoting from the
8017      ANSI - standard : "for E1 >> E2, is equivalent to division
8018      by 2**E2 if unsigned or if it has a non-negative value,
8019      otherwise the result is implementation defined ", MY definition
8020      is that the sign does not get propagated */
8021
8022   right = IC_RIGHT (ic);
8023   left = IC_LEFT (ic);
8024   result = IC_RESULT (ic);
8025
8026   aopOp (right, ic, FALSE);
8027
8028   /* if the shift count is known then do it
8029      as efficiently as possible */
8030   if (AOP_TYPE (right) == AOP_LIT)
8031     {
8032       genRightShiftLiteral (left, right, result, ic, 0);
8033       return;
8034     }
8035
8036   /* shift count is unknown then we have to form
8037      a loop get the loop count in B : Note: we take
8038      only the lower order byte since shifting
8039      more that 32 bits make no sense anyway, ( the
8040      largest size of an object can be only 32 bits ) */
8041
8042   pushedB = pushB ();
8043   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
8044   emitcode ("inc", "b");
8045   freeAsmop (right, NULL, ic, TRUE);
8046   aopOp (left, ic, FALSE);
8047   aopOp (result, ic, FALSE);
8048
8049   /* now move the left to the result if they are not the
8050      same */
8051   if (!sameRegs (AOP (left), AOP (result)) &&
8052       AOP_SIZE (result) > 1)
8053     {
8054
8055       size = AOP_SIZE (result);
8056       offset = 0;
8057       while (size--)
8058         {
8059           l = aopGet (AOP (left), offset, FALSE, TRUE);
8060           if (*l == '@' && IS_AOP_PREG (result))
8061             {
8062
8063               emitcode ("mov", "a,%s", l);
8064               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8065             }
8066           else
8067             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
8068           offset++;
8069         }
8070     }
8071
8072   tlbl = newiTempLabel (NULL);
8073   tlbl1 = newiTempLabel (NULL);
8074   size = AOP_SIZE (result);
8075   offset = size - 1;
8076
8077   /* if it is only one byte then */
8078   if (size == 1)
8079     {
8080       l = aopGet (AOP (left), 0, FALSE, FALSE);
8081       MOVA (l);
8082       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8083       emitcode ("", "%05d$:", tlbl->key + 100);
8084       CLRC;
8085       emitcode ("rrc", "a");
8086       emitcode ("", "%05d$:", tlbl1->key + 100);
8087       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8088       popB (pushedB);
8089       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
8090       goto release;
8091     }
8092
8093   reAdjustPreg (AOP (result));
8094   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8095   emitcode ("", "%05d$:", tlbl->key + 100);
8096   CLRC;
8097   while (size--)
8098     {
8099       l = aopGet (AOP (result), offset, FALSE, FALSE);
8100       MOVA (l);
8101       emitcode ("rrc", "a");
8102       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
8103     }
8104   reAdjustPreg (AOP (result));
8105
8106   emitcode ("", "%05d$:", tlbl1->key + 100);
8107   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8108   popB (pushedB);
8109
8110 release:
8111   freeAsmop (left, NULL, ic, TRUE);
8112   freeAsmop (result, NULL, ic, TRUE);
8113 }
8114
8115 /*-----------------------------------------------------------------*/
8116 /* emitPtrByteGet - emits code to get a byte into A through a      */
8117 /*                  pointer register (R0, R1, or DPTR). The        */
8118 /*                  original value of A can be preserved in B.     */
8119 /*-----------------------------------------------------------------*/
8120 static void
8121 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8122 {
8123   switch (p_type)
8124     {
8125     case IPOINTER:
8126     case POINTER:
8127       if (preserveAinB)
8128         emitcode ("mov", "b,a");
8129       emitcode ("mov", "a,@%s", rname);
8130       break;
8131
8132     case PPOINTER:
8133       if (preserveAinB)
8134         emitcode ("mov", "b,a");
8135       emitcode ("movx", "a,@%s", rname);
8136       break;
8137
8138     case FPOINTER:
8139       if (preserveAinB)
8140         emitcode ("mov", "b,a");
8141       emitcode ("movx", "a,@dptr");
8142       break;
8143
8144     case CPOINTER:
8145       if (preserveAinB)
8146         emitcode ("mov", "b,a");
8147       emitcode ("clr", "a");
8148       emitcode ("movc", "a,@a+dptr");
8149       break;
8150
8151     case GPOINTER:
8152       if (preserveAinB)
8153         {
8154           emitcode ("push", "b");
8155           emitcode ("push", "acc");
8156         }
8157       emitcode ("lcall", "__gptrget");
8158       if (preserveAinB)
8159         emitcode ("pop", "b");
8160       break;
8161     }
8162 }
8163
8164 /*-----------------------------------------------------------------*/
8165 /* emitPtrByteSet - emits code to set a byte from src through a    */
8166 /*                  pointer register (R0, R1, or DPTR).            */
8167 /*-----------------------------------------------------------------*/
8168 static void
8169 emitPtrByteSet (char *rname, int p_type, char *src)
8170 {
8171   switch (p_type)
8172     {
8173     case IPOINTER:
8174     case POINTER:
8175       if (*src=='@')
8176         {
8177           MOVA (src);
8178           emitcode ("mov", "@%s,a", rname);
8179         }
8180       else
8181         emitcode ("mov", "@%s,%s", rname, src);
8182       break;
8183
8184     case PPOINTER:
8185       MOVA (src);
8186       emitcode ("movx", "@%s,a", rname);
8187       break;
8188
8189     case FPOINTER:
8190       MOVA (src);
8191       emitcode ("movx", "@dptr,a");
8192       break;
8193
8194     case GPOINTER:
8195       MOVA (src);
8196       emitcode ("lcall", "__gptrput");
8197       break;
8198     }
8199 }
8200
8201 /*-----------------------------------------------------------------*/
8202 /* genUnpackBits - generates code for unpacking bits               */
8203 /*-----------------------------------------------------------------*/
8204 static void
8205 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
8206 {
8207   int offset = 0;       /* result byte offset */
8208   int rsize;            /* result size */
8209   int rlen = 0;         /* remaining bitfield length */
8210   sym_link *etype;      /* bitfield type information */
8211   int blen;             /* bitfield length */
8212   int bstr;             /* bitfield starting bit within byte */
8213   char buffer[10];
8214
8215   D(emitcode (";     genUnpackBits",""));
8216
8217   etype = getSpec (operandType (result));
8218   rsize = getSize (operandType (result));
8219   blen = SPEC_BLEN (etype);
8220   bstr = SPEC_BSTR (etype);
8221
8222   if (ifx && blen <= 8)
8223     {
8224       emitPtrByteGet (rname, ptype, FALSE);
8225       if (blen == 1)
8226         {
8227           SNPRINTF (buffer, sizeof(buffer),
8228                     "acc.%d", bstr);
8229           genIfxJump (ifx, buffer, NULL, NULL, NULL);
8230         }
8231       else
8232         {
8233           if (blen < 8)
8234             emitcode ("anl", "a,#0x%02x",
8235                       (((unsigned char) -1) >> (8 - blen)) << bstr);
8236           genIfxJump (ifx, "a", NULL, NULL, NULL);
8237         }
8238       return;
8239     }
8240   wassert (!ifx);
8241
8242   /* If the bitfield length is less than a byte */
8243   if (blen < 8)
8244     {
8245       emitPtrByteGet (rname, ptype, FALSE);
8246       AccRsh (bstr);
8247       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8248       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8249       goto finish;
8250     }
8251
8252   /* Bit field did not fit in a byte. Copy all
8253      but the partial byte at the end.  */
8254   for (rlen=blen;rlen>=8;rlen-=8)
8255     {
8256       emitPtrByteGet (rname, ptype, FALSE);
8257       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8258       if (rlen>8)
8259         emitcode ("inc", "%s", rname);
8260     }
8261
8262   /* Handle the partial byte at the end */
8263   if (rlen)
8264     {
8265       emitPtrByteGet (rname, ptype, FALSE);
8266       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8267       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8268     }
8269
8270 finish:
8271   if (offset < rsize)
8272     {
8273       rsize -= offset;
8274       while (rsize--)
8275         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8276     }
8277 }
8278
8279
8280 /*-----------------------------------------------------------------*/
8281 /* genDataPointerGet - generates code when ptr offset is known     */
8282 /*-----------------------------------------------------------------*/
8283 static void
8284 genDataPointerGet (operand * left,
8285                    operand * result,
8286                    iCode * ic)
8287 {
8288   char *l;
8289   char buffer[256];
8290   int size, offset = 0;
8291
8292   D(emitcode (";     genDataPointerGet",""));
8293
8294   aopOp (result, ic, TRUE);
8295
8296   /* get the string representation of the name */
8297   l = aopGet (AOP (left), 0, FALSE, TRUE);
8298   size = AOP_SIZE (result);
8299   while (size--)
8300     {
8301       if (offset)
8302         sprintf (buffer, "(%s + %d)", l + 1, offset);
8303       else
8304         sprintf (buffer, "%s", l + 1);
8305       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8306     }
8307
8308   freeAsmop (left, NULL, ic, TRUE);
8309   freeAsmop (result, NULL, ic, TRUE);
8310 }
8311
8312 /*-----------------------------------------------------------------*/
8313 /* genNearPointerGet - emitcode for near pointer fetch             */
8314 /*-----------------------------------------------------------------*/
8315 static void
8316 genNearPointerGet (operand * left,
8317                    operand * result,
8318                    iCode * ic,
8319                    iCode * pi,
8320                    iCode * ifx)
8321 {
8322   asmop *aop = NULL;
8323   regs *preg = NULL;
8324   char *rname;
8325   sym_link *rtype, *retype;
8326   sym_link *ltype = operandType (left);
8327   char buffer[80];
8328
8329   D(emitcode (";     genNearPointerGet",""));
8330
8331   rtype = operandType (result);
8332   retype = getSpec (rtype);
8333
8334   aopOp (left, ic, FALSE);
8335
8336   /* if left is rematerialisable and
8337      result is not bitfield variable type and
8338      the left is pointer to data space i.e
8339      lower 128 bytes of space */
8340   if (AOP_TYPE (left) == AOP_IMMD &&
8341       !IS_BITFIELD (retype) &&
8342       DCL_TYPE (ltype) == POINTER)
8343     {
8344       genDataPointerGet (left, result, ic);
8345       return;
8346     }
8347
8348  /* if the value is already in a pointer register
8349      then don't need anything more */
8350   if (!AOP_INPREG (AOP (left)))
8351     {
8352       if (IS_AOP_PREG (left))
8353         {
8354           // Aha, it is a pointer, just in disguise.
8355           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8356           if (*rname != '@')
8357             {
8358               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8359                       __FILE__, __LINE__);
8360             }
8361           else
8362             {
8363               // Expected case.
8364               emitcode ("mov", "a%s,%s", rname + 1, rname);
8365               rname++;  // skip the '@'.
8366             }
8367         }
8368       else
8369         {
8370           /* otherwise get a free pointer register */
8371           aop = newAsmop (0);
8372           preg = getFreePtr (ic, &aop, FALSE);
8373           emitcode ("mov", "%s,%s",
8374                     preg->name,
8375                     aopGet (AOP (left), 0, FALSE, TRUE));
8376           rname = preg->name;
8377         }
8378     }
8379   else
8380     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8381
8382   //aopOp (result, ic, FALSE);
8383   aopOp (result, ic, result?TRUE:FALSE);
8384
8385   /* if bitfield then unpack the bits */
8386   if (IS_BITFIELD (retype))
8387     genUnpackBits (result, rname, POINTER, ifx);
8388   else
8389     {
8390       /* we have can just get the values */
8391       int size = AOP_SIZE (result);
8392       int offset = 0;
8393
8394       while (size--)
8395         {
8396           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8397             {
8398
8399               emitcode ("mov", "a,@%s", rname);
8400               if (!ifx)
8401               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8402             }
8403           else
8404             {
8405               sprintf (buffer, "@%s", rname);
8406               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8407             }
8408           offset++;
8409           if (size || pi)
8410             emitcode ("inc", "%s", rname);
8411         }
8412     }
8413
8414   /* now some housekeeping stuff */
8415   if (aop)       /* we had to allocate for this iCode */
8416     {
8417       if (pi) { /* post increment present */
8418         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8419       }
8420       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8421     }
8422   else
8423     {
8424       /* we did not allocate which means left
8425          already in a pointer register, then
8426          if size > 0 && this could be used again
8427          we have to point it back to where it
8428          belongs */
8429       if ((AOP_SIZE (result) > 1 &&
8430            !OP_SYMBOL (left)->remat &&
8431            (OP_SYMBOL (left)->liveTo > ic->seq ||
8432             ic->depth)) &&
8433           !pi)
8434         {
8435           int size = AOP_SIZE (result) - 1;
8436           while (size--)
8437             emitcode ("dec", "%s", rname);
8438         }
8439     }
8440
8441   if (ifx && !ifx->generated)
8442     {
8443       genIfxJump (ifx, "a", left, NULL, result);
8444     }
8445
8446   /* done */
8447   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8448   freeAsmop (left, NULL, ic, TRUE);
8449   if (pi) pi->generated = 1;
8450 }
8451
8452 /*-----------------------------------------------------------------*/
8453 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8454 /*-----------------------------------------------------------------*/
8455 static void
8456 genPagedPointerGet (operand * left,
8457                     operand * result,
8458                     iCode * ic,
8459                     iCode *pi,
8460                     iCode *ifx)
8461 {
8462   asmop *aop = NULL;
8463   regs *preg = NULL;
8464   char *rname;
8465   sym_link *rtype, *retype;
8466
8467   D(emitcode (";     genPagedPointerGet",""));
8468
8469   rtype = operandType (result);
8470   retype = getSpec (rtype);
8471
8472   aopOp (left, ic, FALSE);
8473
8474   /* if the value is already in a pointer register
8475      then don't need anything more */
8476   if (!AOP_INPREG (AOP (left)))
8477     {
8478       /* otherwise get a free pointer register */
8479       aop = newAsmop (0);
8480       preg = getFreePtr (ic, &aop, FALSE);
8481       emitcode ("mov", "%s,%s",
8482                 preg->name,
8483                 aopGet (AOP (left), 0, FALSE, TRUE));
8484       rname = preg->name;
8485     }
8486   else
8487     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8488
8489   aopOp (result, ic, FALSE);
8490
8491   /* if bitfield then unpack the bits */
8492   if (IS_BITFIELD (retype))
8493     genUnpackBits (result, rname, PPOINTER, ifx);
8494   else
8495     {
8496       /* we have can just get the values */
8497       int size = AOP_SIZE (result);
8498       int offset = 0;
8499
8500       while (size--)
8501         {
8502
8503           emitcode ("movx", "a,@%s", rname);
8504           if (!ifx)
8505           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8506
8507           offset++;
8508
8509           if (size || pi)
8510             emitcode ("inc", "%s", rname);
8511         }
8512     }
8513
8514   /* now some housekeeping stuff */
8515   if (aop) /* we had to allocate for this iCode */
8516     {
8517       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8518       freeAsmop (NULL, aop, ic, TRUE);
8519     }
8520   else
8521     {
8522       /* we did not allocate which means left
8523          already in a pointer register, then
8524          if size > 0 && this could be used again
8525          we have to point it back to where it
8526          belongs */
8527       if ((AOP_SIZE (result) > 1 &&
8528            !OP_SYMBOL (left)->remat &&
8529            (OP_SYMBOL (left)->liveTo > ic->seq ||
8530             ic->depth)) &&
8531           !pi)
8532         {
8533           int size = AOP_SIZE (result) - 1;
8534           while (size--)
8535             emitcode ("dec", "%s", rname);
8536         }
8537     }
8538
8539   if (ifx && !ifx->generated)
8540     {
8541       genIfxJump (ifx, "a", left, NULL, result);
8542     }
8543
8544   /* done */
8545   freeAsmop (left, NULL, ic, TRUE);
8546   freeAsmop (result, NULL, ic, TRUE);
8547   if (pi) pi->generated = 1;
8548
8549 }
8550
8551 /*--------------------------------------------------------------------*/
8552 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8553 /*--------------------------------------------------------------------*/
8554 static void
8555 loadDptrFromOperand (operand *op, bool loadBToo)
8556 {
8557   if (AOP_TYPE (op) != AOP_STR)
8558     {
8559       /* if this is rematerializable */
8560       if (AOP_TYPE (op) == AOP_IMMD)
8561         {
8562           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8563           if (loadBToo)
8564             {
8565               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8566                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8567               else
8568                 {
8569                   wassertl(FALSE, "need pointerCode");
8570                   emitcode ("", "; mov b,???");
8571                   /* genPointerGet and genPointerSet originally did different
8572                   ** things for this case. Both seem wrong.
8573                   ** from genPointerGet:
8574                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8575                   ** from genPointerSet:
8576                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8577                   */
8578                 }
8579             }
8580         }
8581       else if (AOP_TYPE (op) == AOP_DPTR)
8582         {
8583           if (loadBToo)
8584             {
8585               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8586               emitcode ("push", "acc");
8587               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8588               emitcode ("push", "acc");
8589               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8590               emitcode ("pop", "dph");
8591               emitcode ("pop", "dpl");
8592             }
8593           else
8594             {
8595               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8596               emitcode ("push", "acc");
8597               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8598               emitcode ("pop", "dpl");
8599             }
8600         }
8601       else
8602         {                       /* we need to get it byte by byte */
8603           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8604           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8605           if (loadBToo)
8606             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8607         }
8608     }
8609 }
8610
8611 /*-----------------------------------------------------------------*/
8612 /* genFarPointerGet - gget value from far space                    */
8613 /*-----------------------------------------------------------------*/
8614 static void
8615 genFarPointerGet (operand * left,
8616                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
8617 {
8618   int size, offset;
8619   sym_link *retype = getSpec (operandType (result));
8620
8621   D(emitcode (";     genFarPointerGet",""));
8622
8623   aopOp (left, ic, FALSE);
8624   loadDptrFromOperand (left, FALSE);
8625
8626   /* so dptr now contains the address */
8627   aopOp (result, ic, FALSE);
8628
8629   /* if bit then unpack */
8630   if (IS_BITFIELD (retype))
8631     genUnpackBits (result, "dptr", FPOINTER, ifx);
8632   else
8633     {
8634       size = AOP_SIZE (result);
8635       offset = 0;
8636
8637       while (size--)
8638         {
8639           emitcode ("movx", "a,@dptr");
8640           if (!ifx)
8641             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8642           if (size || pi)
8643             emitcode ("inc", "dptr");
8644         }
8645     }
8646
8647   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8648     {
8649     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8650     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8651     pi->generated = 1;
8652   }
8653
8654   if (ifx && !ifx->generated)
8655     {
8656       genIfxJump (ifx, "a", left, NULL, result);
8657     }
8658
8659   freeAsmop (left, NULL, ic, TRUE);
8660   freeAsmop (result, NULL, ic, TRUE);
8661 }
8662
8663 /*-----------------------------------------------------------------*/
8664 /* genCodePointerGet - gget value from code space                  */
8665 /*-----------------------------------------------------------------*/
8666 static void
8667 genCodePointerGet (operand * left,
8668                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
8669 {
8670   int size, offset;
8671   sym_link *retype = getSpec (operandType (result));
8672
8673   D(emitcode (";     genCodePointerGet",""));
8674
8675   aopOp (left, ic, FALSE);
8676   loadDptrFromOperand (left, FALSE);
8677
8678   /* so dptr now contains the address */
8679   aopOp (result, ic, FALSE);
8680
8681   /* if bit then unpack */
8682   if (IS_BITFIELD (retype))
8683     genUnpackBits (result, "dptr", CPOINTER, ifx);
8684   else
8685     {
8686       size = AOP_SIZE (result);
8687       offset = 0;
8688
8689       while (size--)
8690         {
8691           if (pi)
8692             {
8693               emitcode ("clr", "a");
8694               emitcode ("movc", "a,@a+dptr");
8695               if (!ifx)
8696               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8697               emitcode ("inc", "dptr");
8698             }
8699           else
8700             {
8701               emitcode ("mov", "a,#0x%02x", offset);
8702               emitcode ("movc", "a,@a+dptr");
8703               if (!ifx)
8704               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8705             }
8706         }
8707     }
8708
8709   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8710     {
8711     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8712     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8713     pi->generated = 1;
8714   }
8715
8716   if (ifx && !ifx->generated)
8717     {
8718       genIfxJump (ifx, "a", left, NULL, result);
8719     }
8720
8721   freeAsmop (left, NULL, ic, TRUE);
8722   freeAsmop (result, NULL, ic, TRUE);
8723 }
8724
8725 /*-----------------------------------------------------------------*/
8726 /* genGenPointerGet - gget value from generic pointer space        */
8727 /*-----------------------------------------------------------------*/
8728 static void
8729 genGenPointerGet (operand * left,
8730                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
8731 {
8732   int size, offset;
8733   sym_link *retype = getSpec (operandType (result));
8734
8735   D(emitcode (";     genGenPointerGet",""));
8736
8737   aopOp (left, ic, FALSE);
8738   loadDptrFromOperand (left, TRUE);
8739
8740   /* so dptr know contains the address */
8741   aopOp (result, ic, FALSE);
8742
8743   /* if bit then unpack */
8744   if (IS_BITFIELD (retype))
8745     genUnpackBits (result, "dptr", GPOINTER, ifx);
8746   else
8747     {
8748       size = AOP_SIZE (result);
8749       offset = 0;
8750
8751       while (size--)
8752         {
8753           emitcode ("lcall", "__gptrget");
8754           if (!ifx)
8755           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8756           if (size || pi)
8757             emitcode ("inc", "dptr");
8758         }
8759     }
8760
8761   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
8762     {
8763     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8764     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8765     pi->generated = 1;
8766   }
8767
8768   if (ifx && !ifx->generated)
8769     {
8770       genIfxJump (ifx, "a", left, NULL, result);
8771     }
8772
8773
8774   freeAsmop (left, NULL, ic, TRUE);
8775   freeAsmop (result, NULL, ic, TRUE);
8776 }
8777
8778 /*-----------------------------------------------------------------*/
8779 /* genPointerGet - generate code for pointer get                   */
8780 /*-----------------------------------------------------------------*/
8781 static void
8782 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
8783 {
8784   operand *left, *result;
8785   sym_link *type, *etype;
8786   int p_type;
8787
8788   D(emitcode (";     genPointerGet",""));
8789
8790   left = IC_LEFT (ic);
8791   result = IC_RESULT (ic);
8792
8793   if (getSize (operandType (result))>1)
8794     ifx = NULL;
8795
8796   /* depending on the type of pointer we need to
8797      move it to the correct pointer register */
8798   type = operandType (left);
8799   etype = getSpec (type);
8800   /* if left is of type of pointer then it is simple */
8801   if (IS_PTR (type) && !IS_FUNC (type->next))
8802     p_type = DCL_TYPE (type);
8803   else
8804     {
8805       /* we have to go by the storage class */
8806       p_type = PTR_TYPE (SPEC_OCLS (etype));
8807     }
8808
8809   /* special case when cast remat */
8810   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8811       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8812           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8813           type = operandType (left);
8814           p_type = DCL_TYPE (type);
8815   }
8816   /* now that we have the pointer type we assign
8817      the pointer values */
8818   switch (p_type)
8819     {
8820
8821     case POINTER:
8822     case IPOINTER:
8823       genNearPointerGet (left, result, ic, pi, ifx);
8824       break;
8825
8826     case PPOINTER:
8827       genPagedPointerGet (left, result, ic, pi, ifx);
8828       break;
8829
8830     case FPOINTER:
8831       genFarPointerGet (left, result, ic, pi, ifx);
8832       break;
8833
8834     case CPOINTER:
8835       genCodePointerGet (left, result, ic, pi, ifx);
8836       break;
8837
8838     case GPOINTER:
8839       genGenPointerGet (left, result, ic, pi, ifx);
8840       break;
8841     }
8842
8843 }
8844
8845
8846
8847 /*-----------------------------------------------------------------*/
8848 /* genPackBits - generates code for packed bit storage             */
8849 /*-----------------------------------------------------------------*/
8850 static void
8851 genPackBits (sym_link * etype,
8852              operand * right,
8853              char *rname, int p_type)
8854 {
8855   int offset = 0;       /* source byte offset */
8856   int rlen = 0;         /* remaining bitfield length */
8857   int blen;             /* bitfield length */
8858   int bstr;             /* bitfield starting bit within byte */
8859   int litval;           /* source literal value (if AOP_LIT) */
8860   unsigned char mask;   /* bitmask within current byte */
8861
8862   D(emitcode (";     genPackBits",""));
8863
8864   blen = SPEC_BLEN (etype);
8865   bstr = SPEC_BSTR (etype);
8866
8867   /* If the bitfield length is less than a byte */
8868   if (blen < 8)
8869     {
8870       mask = ((unsigned char) (0xFF << (blen + bstr)) |
8871               (unsigned char) (0xFF >> (8 - bstr)));
8872
8873       if (AOP_TYPE (right) == AOP_LIT)
8874         {
8875           /* Case with a bitfield length <8 and literal source
8876           */
8877           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8878           litval <<= bstr;
8879           litval &= (~mask) & 0xff;
8880           emitPtrByteGet (rname, p_type, FALSE);
8881           if ((mask|litval)!=0xff)
8882             emitcode ("anl","a,#0x%02x", mask);
8883           if (litval)
8884             emitcode ("orl","a,#0x%02x", litval);
8885         }
8886       else
8887         {
8888           if ((blen==1) && (p_type!=GPOINTER))
8889             {
8890               /* Case with a bitfield length == 1 and no generic pointer
8891               */
8892               if (AOP_TYPE (right) == AOP_CRY)
8893                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
8894               else
8895                 {
8896                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8897                   emitcode ("rrc","a");
8898                 }
8899               emitPtrByteGet (rname, p_type, FALSE);
8900               emitcode ("mov","acc.%d,c",bstr);
8901             }
8902           else
8903             {
8904               bool pushedB;
8905               /* Case with a bitfield length < 8 and arbitrary source
8906               */
8907               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8908               /* shift and mask source value */
8909               AccLsh (bstr);
8910               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8911
8912               pushedB = pushB ();
8913               /* transfer A to B and get next byte */
8914               emitPtrByteGet (rname, p_type, TRUE);
8915
8916               emitcode ("anl", "a,#0x%02x", mask);
8917               emitcode ("orl", "a,b");
8918               if (p_type == GPOINTER)
8919                 emitcode ("pop", "b");
8920
8921               popB (pushedB);
8922            }
8923         }
8924
8925       emitPtrByteSet (rname, p_type, "a");
8926       return;
8927     }
8928
8929   /* Bit length is greater than 7 bits. In this case, copy  */
8930   /* all except the partial byte at the end                 */
8931   for (rlen=blen;rlen>=8;rlen-=8)
8932     {
8933       emitPtrByteSet (rname, p_type,
8934                       aopGet (AOP (right), offset++, FALSE, TRUE) );
8935       if (rlen>8)
8936         emitcode ("inc", "%s", rname);
8937     }
8938
8939   /* If there was a partial byte at the end */
8940   if (rlen)
8941     {
8942       mask = (((unsigned char) -1 << rlen) & 0xff);
8943
8944       if (AOP_TYPE (right) == AOP_LIT)
8945         {
8946           /* Case with partial byte and literal source
8947           */
8948           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8949           litval >>= (blen-rlen);
8950           litval &= (~mask) & 0xff;
8951           emitPtrByteGet (rname, p_type, FALSE);
8952           if ((mask|litval)!=0xff)
8953             emitcode ("anl","a,#0x%02x", mask);
8954           if (litval)
8955             emitcode ("orl","a,#0x%02x", litval);
8956         }
8957       else
8958         {
8959           bool pushedB;
8960           /* Case with partial byte and arbitrary source
8961           */
8962           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
8963           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8964
8965           pushedB = pushB ();
8966           /* transfer A to B and get next byte */
8967           emitPtrByteGet (rname, p_type, TRUE);
8968
8969           emitcode ("anl", "a,#0x%02x", mask);
8970           emitcode ("orl", "a,b");
8971           if (p_type == GPOINTER)
8972             emitcode ("pop", "b");
8973
8974           popB (pushedB);
8975         }
8976       emitPtrByteSet (rname, p_type, "a");
8977     }
8978
8979 }
8980
8981
8982 /*-----------------------------------------------------------------*/
8983 /* genDataPointerSet - remat pointer to data space                 */
8984 /*-----------------------------------------------------------------*/
8985 static void
8986 genDataPointerSet (operand * right,
8987                    operand * result,
8988                    iCode * ic)
8989 {
8990   int size, offset = 0;
8991   char *l, buffer[256];
8992
8993   D(emitcode (";     genDataPointerSet",""));
8994
8995   aopOp (right, ic, FALSE);
8996
8997   l = aopGet (AOP (result), 0, FALSE, TRUE);
8998   size = AOP_SIZE (right);
8999   while (size--)
9000     {
9001       if (offset)
9002         sprintf (buffer, "(%s + %d)", l + 1, offset);
9003       else
9004         sprintf (buffer, "%s", l + 1);
9005       emitcode ("mov", "%s,%s", buffer,
9006                 aopGet (AOP (right), offset++, FALSE, FALSE));
9007     }
9008
9009   freeAsmop (right, NULL, ic, TRUE);
9010   freeAsmop (result, NULL, ic, TRUE);
9011 }
9012
9013 /*-----------------------------------------------------------------*/
9014 /* genNearPointerSet - emitcode for near pointer put                */
9015 /*-----------------------------------------------------------------*/
9016 static void
9017 genNearPointerSet (operand * right,
9018                    operand * result,
9019                    iCode * ic,
9020                    iCode * pi)
9021 {
9022   asmop *aop = NULL;
9023   regs *preg = NULL;
9024   char *rname, *l;
9025   sym_link *retype, *letype;
9026   sym_link *ptype = operandType (result);
9027
9028   D(emitcode (";     genNearPointerSet",""));
9029
9030   retype = getSpec (operandType (right));
9031   letype = getSpec (ptype);
9032   aopOp (result, ic, FALSE);
9033
9034   /* if the result is rematerializable &
9035      in data space & not a bit variable */
9036   if (AOP_TYPE (result) == AOP_IMMD &&
9037       DCL_TYPE (ptype) == POINTER &&
9038       !IS_BITVAR (retype) &&
9039       !IS_BITVAR (letype))
9040     {
9041       genDataPointerSet (right, result, ic);
9042       return;
9043     }
9044
9045   /* if the value is already in a pointer register
9046      then don't need anything more */
9047   if (!AOP_INPREG (AOP (result)))
9048     {
9049         if (
9050             //AOP_TYPE (result) == AOP_STK
9051             IS_AOP_PREG(result)
9052             )
9053         {
9054             // Aha, it is a pointer, just in disguise.
9055             rname = aopGet (AOP (result), 0, FALSE, FALSE);
9056             if (*rname != '@')
9057             {
9058                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9059                         __FILE__, __LINE__);
9060             }
9061             else
9062             {
9063                 // Expected case.
9064                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9065                 rname++;  // skip the '@'.
9066             }
9067         }
9068         else
9069         {
9070             /* otherwise get a free pointer register */
9071             aop = newAsmop (0);
9072             preg = getFreePtr (ic, &aop, FALSE);
9073             emitcode ("mov", "%s,%s",
9074                       preg->name,
9075                       aopGet (AOP (result), 0, FALSE, TRUE));
9076             rname = preg->name;
9077         }
9078     }
9079     else
9080     {
9081         rname = aopGet (AOP (result), 0, FALSE, FALSE);
9082     }
9083
9084   aopOp (right, ic, FALSE);
9085
9086   /* if bitfield then unpack the bits */
9087   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9088     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9089   else
9090     {
9091       /* we have can just get the values */
9092       int size = AOP_SIZE (right);
9093       int offset = 0;
9094
9095       while (size--)
9096         {
9097           l = aopGet (AOP (right), offset, FALSE, TRUE);
9098           if (*l == '@')
9099             {
9100               MOVA (l);
9101               emitcode ("mov", "@%s,a", rname);
9102             }
9103           else
9104             emitcode ("mov", "@%s,%s", rname, l);
9105           if (size || pi)
9106             emitcode ("inc", "%s", rname);
9107           offset++;
9108         }
9109     }
9110
9111   /* now some housekeeping stuff */
9112   if (aop) /* we had to allocate for this iCode */
9113     {
9114       if (pi)
9115         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9116       freeAsmop (NULL, aop, ic, TRUE);
9117     }
9118   else
9119     {
9120       /* we did not allocate which means left
9121          already in a pointer register, then
9122          if size > 0 && this could be used again
9123          we have to point it back to where it
9124          belongs */
9125       if ((AOP_SIZE (right) > 1 &&
9126            !OP_SYMBOL (result)->remat &&
9127            (OP_SYMBOL (result)->liveTo > ic->seq ||
9128             ic->depth)) &&
9129           !pi)
9130         {
9131           int size = AOP_SIZE (right) - 1;
9132           while (size--)
9133             emitcode ("dec", "%s", rname);
9134         }
9135     }
9136
9137   /* done */
9138   if (pi) pi->generated = 1;
9139   freeAsmop (result, NULL, ic, TRUE);
9140   freeAsmop (right, NULL, ic, TRUE);
9141 }
9142
9143 /*-----------------------------------------------------------------*/
9144 /* genPagedPointerSet - emitcode for Paged pointer put             */
9145 /*-----------------------------------------------------------------*/
9146 static void
9147 genPagedPointerSet (operand * right,
9148                     operand * result,
9149                     iCode * ic,
9150                     iCode * pi)
9151 {
9152   asmop *aop = NULL;
9153   regs *preg = NULL;
9154   char *rname, *l;
9155   sym_link *retype, *letype;
9156
9157   D(emitcode (";     genPagedPointerSet",""));
9158
9159   retype = getSpec (operandType (right));
9160   letype = getSpec (operandType (result));
9161
9162   aopOp (result, ic, FALSE);
9163
9164   /* if the value is already in a pointer register
9165      then don't need anything more */
9166   if (!AOP_INPREG (AOP (result)))
9167     {
9168       /* otherwise get a free pointer register */
9169       aop = newAsmop (0);
9170       preg = getFreePtr (ic, &aop, FALSE);
9171       emitcode ("mov", "%s,%s",
9172                 preg->name,
9173                 aopGet (AOP (result), 0, FALSE, TRUE));
9174       rname = preg->name;
9175     }
9176   else
9177     rname = aopGet (AOP (result), 0, FALSE, FALSE);
9178
9179   aopOp (right, ic, FALSE);
9180
9181   /* if bitfield then unpack the bits */
9182   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9183     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
9184   else
9185     {
9186       /* we have can just get the values */
9187       int size = AOP_SIZE (right);
9188       int offset = 0;
9189
9190       while (size--)
9191         {
9192           l = aopGet (AOP (right), offset, FALSE, TRUE);
9193
9194           MOVA (l);
9195           emitcode ("movx", "@%s,a", rname);
9196
9197           if (size || pi)
9198             emitcode ("inc", "%s", rname);
9199
9200           offset++;
9201         }
9202     }
9203
9204   /* now some housekeeping stuff */
9205   if (aop) /* we had to allocate for this iCode */
9206     {
9207       if (pi)
9208         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
9209       freeAsmop (NULL, aop, ic, TRUE);
9210     }
9211   else
9212     {
9213       /* we did not allocate which means left
9214          already in a pointer register, then
9215          if size > 0 && this could be used again
9216          we have to point it back to where it
9217          belongs */
9218       if (AOP_SIZE (right) > 1 &&
9219           !OP_SYMBOL (result)->remat &&
9220           (OP_SYMBOL (result)->liveTo > ic->seq ||
9221            ic->depth))
9222         {
9223           int size = AOP_SIZE (right) - 1;
9224           while (size--)
9225             emitcode ("dec", "%s", rname);
9226         }
9227     }
9228
9229   /* done */
9230   if (pi) pi->generated = 1;
9231   freeAsmop (result, NULL, ic, TRUE);
9232   freeAsmop (right, NULL, ic, TRUE);
9233
9234
9235 }
9236
9237 /*-----------------------------------------------------------------*/
9238 /* genFarPointerSet - set value from far space                     */
9239 /*-----------------------------------------------------------------*/
9240 static void
9241 genFarPointerSet (operand * right,
9242                   operand * result, iCode * ic, iCode * pi)
9243 {
9244   int size, offset;
9245   sym_link *retype = getSpec (operandType (right));
9246   sym_link *letype = getSpec (operandType (result));
9247
9248   D(emitcode (";     genFarPointerSet",""));
9249
9250   aopOp (result, ic, FALSE);
9251   loadDptrFromOperand (result, FALSE);
9252
9253   /* so dptr know contains the address */
9254   aopOp (right, ic, FALSE);
9255
9256   /* if bit then unpack */
9257   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9258     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
9259   else
9260     {
9261       size = AOP_SIZE (right);
9262       offset = 0;
9263
9264       while (size--)
9265         {
9266           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9267           MOVA (l);
9268           emitcode ("movx", "@dptr,a");
9269           if (size || pi)
9270             emitcode ("inc", "dptr");
9271         }
9272     }
9273   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9274     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9275     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9276     pi->generated=1;
9277   }
9278   freeAsmop (result, NULL, ic, TRUE);
9279   freeAsmop (right, NULL, ic, TRUE);
9280 }
9281
9282 /*-----------------------------------------------------------------*/
9283 /* genGenPointerSet - set value from generic pointer space         */
9284 /*-----------------------------------------------------------------*/
9285 static void
9286 genGenPointerSet (operand * right,
9287                   operand * result, iCode * ic, iCode * pi)
9288 {
9289   int size, offset;
9290   sym_link *retype = getSpec (operandType (right));
9291   sym_link *letype = getSpec (operandType (result));
9292
9293   D(emitcode (";     genGenPointerSet",""));
9294
9295   aopOp (result, ic, FALSE);
9296   loadDptrFromOperand (result, TRUE);
9297
9298   /* so dptr know contains the address */
9299   aopOp (right, ic, FALSE);
9300
9301   /* if bit then unpack */
9302   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9303     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9304   else
9305     {
9306       size = AOP_SIZE (right);
9307       offset = 0;
9308
9309       while (size--)
9310         {
9311           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9312           MOVA (l);
9313           emitcode ("lcall", "__gptrput");
9314           if (size || pi)
9315             emitcode ("inc", "dptr");
9316         }
9317     }
9318
9319   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9320     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9321     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9322     pi->generated=1;
9323   }
9324   freeAsmop (result, NULL, ic, TRUE);
9325   freeAsmop (right, NULL, ic, TRUE);
9326 }
9327
9328 /*-----------------------------------------------------------------*/
9329 /* genPointerSet - stores the value into a pointer location        */
9330 /*-----------------------------------------------------------------*/
9331 static void
9332 genPointerSet (iCode * ic, iCode *pi)
9333 {
9334   operand *right, *result;
9335   sym_link *type, *etype;
9336   int p_type;
9337
9338   D(emitcode (";     genPointerSet",""));
9339
9340   right = IC_RIGHT (ic);
9341   result = IC_RESULT (ic);
9342
9343   /* depending on the type of pointer we need to
9344      move it to the correct pointer register */
9345   type = operandType (result);
9346   etype = getSpec (type);
9347   /* if left is of type of pointer then it is simple */
9348   if (IS_PTR (type) && !IS_FUNC (type->next))
9349     {
9350       p_type = DCL_TYPE (type);
9351     }
9352   else
9353     {
9354       /* we have to go by the storage class */
9355       p_type = PTR_TYPE (SPEC_OCLS (etype));
9356     }
9357
9358   /* special case when cast remat */
9359   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9360       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9361           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9362           type = operandType (result);
9363           p_type = DCL_TYPE (type);
9364   }
9365   /* now that we have the pointer type we assign
9366      the pointer values */
9367   switch (p_type)
9368     {
9369
9370     case POINTER:
9371     case IPOINTER:
9372       genNearPointerSet (right, result, ic, pi);
9373       break;
9374
9375     case PPOINTER:
9376       genPagedPointerSet (right, result, ic, pi);
9377       break;
9378
9379     case FPOINTER:
9380       genFarPointerSet (right, result, ic, pi);
9381       break;
9382
9383     case GPOINTER:
9384       genGenPointerSet (right, result, ic, pi);
9385       break;
9386
9387     default:
9388       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9389               "genPointerSet: illegal pointer type");
9390     }
9391
9392 }
9393
9394 /*-----------------------------------------------------------------*/
9395 /* genIfx - generate code for Ifx statement                        */
9396 /*-----------------------------------------------------------------*/
9397 static void
9398 genIfx (iCode * ic, iCode * popIc)
9399 {
9400   operand *cond = IC_COND (ic);
9401   int isbit = 0;
9402
9403   D(emitcode (";     genIfx",""));
9404
9405   aopOp (cond, ic, FALSE);
9406
9407   /* get the value into acc */
9408   if (AOP_TYPE (cond) != AOP_CRY)
9409     toBoolean (cond);
9410   else
9411     isbit = 1;
9412   /* the result is now in the accumulator */
9413   freeAsmop (cond, NULL, ic, TRUE);
9414
9415   /* if there was something to be popped then do it */
9416   if (popIc)
9417     genIpop (popIc);
9418
9419   /* if the condition is a bit variable */
9420   if (isbit && IS_ITEMP (cond) &&
9421       SPIL_LOC (cond))
9422     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9423   else if (isbit && !IS_ITEMP (cond))
9424     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9425   else
9426     genIfxJump (ic, "a", NULL, NULL, NULL);
9427
9428   ic->generated = 1;
9429 }
9430
9431 /*-----------------------------------------------------------------*/
9432 /* genAddrOf - generates code for address of                       */
9433 /*-----------------------------------------------------------------*/
9434 static void
9435 genAddrOf (iCode * ic)
9436 {
9437   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9438   int size, offset;
9439
9440   D(emitcode (";     genAddrOf",""));
9441
9442   aopOp (IC_RESULT (ic), ic, FALSE);
9443
9444   /* if the operand is on the stack then we
9445      need to get the stack offset of this
9446      variable */
9447   if (sym->onStack)
9448     {
9449       /* if it has an offset then we need to compute
9450          it */
9451       if (sym->stack)
9452         {
9453           emitcode ("mov", "a,_bp");
9454           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9455                                          ((char) (sym->stack - _G.nRegsSaved)) :
9456                                          ((char) sym->stack)) & 0xff);
9457           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9458         }
9459       else
9460         {
9461           /* we can just move _bp */
9462           aopPut (AOP (IC_RESULT (ic)), "_bp", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9463         }
9464       /* fill the result with zero */
9465       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9466
9467       offset = 1;
9468       while (size--)
9469         {
9470           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9471         }
9472
9473       goto release;
9474     }
9475
9476   /* object not on stack then we need the name */
9477   size = AOP_SIZE (IC_RESULT (ic));
9478   offset = 0;
9479
9480   while (size--)
9481     {
9482       char s[SDCC_NAME_MAX];
9483       if (offset)
9484         sprintf (s, "#(%s >> %d)",
9485                  sym->rname,
9486                  offset * 8);
9487       else
9488         sprintf (s, "#%s", sym->rname);
9489       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9490     }
9491
9492 release:
9493   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9494
9495 }
9496
9497 /*-----------------------------------------------------------------*/
9498 /* genFarFarAssign - assignment when both are in far space         */
9499 /*-----------------------------------------------------------------*/
9500 static void
9501 genFarFarAssign (operand * result, operand * right, iCode * ic)
9502 {
9503   int size = AOP_SIZE (right);
9504   int offset = 0;
9505   char *l;
9506
9507   D(emitcode (";     genFarFarAssign",""));
9508
9509   /* first push the right side on to the stack */
9510   while (size--)
9511     {
9512       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9513       MOVA (l);
9514       emitcode ("push", "acc");
9515     }
9516
9517   freeAsmop (right, NULL, ic, FALSE);
9518   /* now assign DPTR to result */
9519   aopOp (result, ic, FALSE);
9520   size = AOP_SIZE (result);
9521   while (size--)
9522     {
9523       emitcode ("pop", "acc");
9524       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9525     }
9526   freeAsmop (result, NULL, ic, FALSE);
9527
9528 }
9529
9530 /*-----------------------------------------------------------------*/
9531 /* genAssign - generate code for assignment                        */
9532 /*-----------------------------------------------------------------*/
9533 static void
9534 genAssign (iCode * ic)
9535 {
9536   operand *result, *right;
9537   int size, offset;
9538   unsigned long lit = 0L;
9539
9540   D(emitcode(";     genAssign",""));
9541
9542   result = IC_RESULT (ic);
9543   right = IC_RIGHT (ic);
9544
9545   /* if they are the same */
9546   if (operandsEqu (result, right) &&
9547       !isOperandVolatile (result, FALSE) &&
9548       !isOperandVolatile (right, FALSE))
9549     return;
9550
9551   aopOp (right, ic, FALSE);
9552
9553   /* special case both in far space */
9554   if (AOP_TYPE (right) == AOP_DPTR &&
9555       IS_TRUE_SYMOP (result) &&
9556       isOperandInFarSpace (result))
9557     {
9558
9559       genFarFarAssign (result, right, ic);
9560       return;
9561     }
9562
9563   aopOp (result, ic, TRUE);
9564
9565   /* if they are the same registers */
9566   if (sameRegs (AOP (right), AOP (result)) &&
9567       !isOperandVolatile (result, FALSE) &&
9568       !isOperandVolatile (right, FALSE))
9569     goto release;
9570
9571   /* if the result is a bit */
9572   if (AOP_TYPE (result) == AOP_CRY)
9573     {
9574
9575       /* if the right size is a literal then
9576          we know what the value is */
9577       if (AOP_TYPE (right) == AOP_LIT)
9578         {
9579           if (((int) operandLitValue (right)))
9580             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9581           else
9582             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9583           goto release;
9584         }
9585
9586       /* the right is also a bit variable */
9587       if (AOP_TYPE (right) == AOP_CRY)
9588         {
9589           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9590           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9591           goto release;
9592         }
9593
9594       /* we need to or */
9595       toBoolean (right);
9596       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9597       goto release;
9598     }
9599
9600   /* bit variables done */
9601   /* general case */
9602   size = AOP_SIZE (result);
9603   offset = 0;
9604   if (AOP_TYPE (right) == AOP_LIT)
9605     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9606   if ((size > 1) &&
9607       (AOP_TYPE (result) != AOP_REG) &&
9608       (AOP_TYPE (right) == AOP_LIT) &&
9609       !IS_FLOAT (operandType (right)) &&
9610       (lit < 256L))
9611     {
9612       emitcode ("clr", "a");
9613       while (size--)
9614         {
9615           if ((unsigned int) ((lit >> (size * 8)) & 0x0FFL) == 0)
9616             aopPut (AOP (result), "a", size, isOperandVolatile (result, FALSE));
9617           else
9618             aopPut (AOP (result),
9619                     aopGet (AOP (right), size, FALSE, FALSE),
9620                     size,
9621                     isOperandVolatile (result, FALSE));
9622         }
9623     }
9624   else
9625     {
9626       while (size--)
9627         {
9628           aopPut (AOP (result),
9629                   aopGet (AOP (right), offset, FALSE, FALSE),
9630                   offset,
9631                   isOperandVolatile (result, FALSE));
9632           offset++;
9633         }
9634     }
9635
9636 release:
9637   freeAsmop (right, NULL, ic, TRUE);
9638   freeAsmop (result, NULL, ic, TRUE);
9639 }
9640
9641 /*-----------------------------------------------------------------*/
9642 /* genJumpTab - genrates code for jump table                       */
9643 /*-----------------------------------------------------------------*/
9644 static void
9645 genJumpTab (iCode * ic)
9646 {
9647   symbol *jtab,*jtablo,*jtabhi;
9648   char *l;
9649   unsigned int count;
9650
9651   D(emitcode (";     genJumpTab",""));
9652
9653   count = elementsInSet( IC_JTLABELS (ic) );
9654
9655   if( count <= 16 )
9656     {
9657       /* this algorithm needs 9 cycles and 7 + 3*n bytes
9658          if the switch argument is in a register.
9659          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
9660       /* (MB) What if peephole converts ljmp to sjmp or ret ???
9661          How will multiply by three be updated ???*/
9662       aopOp (IC_JTCOND (ic), ic, FALSE);
9663       /* get the condition into accumulator */
9664       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9665       MOVA (l);
9666       /* multiply by three */
9667       emitcode ("add", "a,acc");
9668       emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9669       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9670
9671       jtab = newiTempLabel (NULL);
9672       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9673       emitcode ("jmp", "@a+dptr");
9674       emitcode ("", "%05d$:", jtab->key + 100);
9675       /* now generate the jump labels */
9676       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9677            jtab = setNextItem (IC_JTLABELS (ic)))
9678         emitcode ("ljmp", "%05d$", jtab->key + 100);
9679     }
9680   else
9681     {
9682       /* this algorithm needs 14 cycles and 13 + 2*n bytes
9683          if the switch argument is in a register.
9684          For n>6 this algorithm may be more compact */
9685       jtablo = newiTempLabel (NULL);
9686       jtabhi = newiTempLabel (NULL);
9687
9688       /* get the condition into accumulator.
9689          Using b as temporary storage, if register push/pop is needed */
9690       aopOp (IC_JTCOND (ic), ic, FALSE);
9691       l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9692       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
9693           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
9694         {
9695           // (MB) what if B is in use???
9696           wassertl(!_G.BInUse, "B was in use");
9697           emitcode ("mov", "b,%s", l);
9698           l = "b";
9699         }
9700       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9701       MOVA (l);
9702       if( count <= 112 )
9703         {
9704           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
9705           emitcode ("movc", "a,@a+pc");
9706           emitcode ("push", "acc");
9707
9708           MOVA (l);
9709           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
9710           emitcode ("movc", "a,@a+pc");
9711           emitcode ("push", "acc");
9712         }
9713       else
9714         {
9715           /* this scales up to n<=255, but needs two more bytes
9716              and changes dptr */
9717           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
9718           emitcode ("movc", "a,@a+dptr");
9719           emitcode ("push", "acc");
9720
9721           MOVA (l);
9722           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
9723           emitcode ("movc", "a,@a+dptr");
9724           emitcode ("push", "acc");
9725         }
9726
9727       emitcode ("ret", "");
9728
9729       /* now generate jump table, LSB */
9730       emitcode ("", "%05d$:", jtablo->key + 100);
9731       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9732            jtab = setNextItem (IC_JTLABELS (ic)))
9733         emitcode (".db", "%05d$", jtab->key + 100);
9734
9735       /* now generate jump table, MSB */
9736       emitcode ("", "%05d$:", jtabhi->key + 100);
9737       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9738            jtab = setNextItem (IC_JTLABELS (ic)))
9739          emitcode (".db", "%05d$>>8", jtab->key + 100);
9740     }
9741 }
9742
9743 /*-----------------------------------------------------------------*/
9744 /* genCast - gen code for casting                                  */
9745 /*-----------------------------------------------------------------*/
9746 static void
9747 genCast (iCode * ic)
9748 {
9749   operand *result = IC_RESULT (ic);
9750   sym_link *ctype = operandType (IC_LEFT (ic));
9751   sym_link *rtype = operandType (IC_RIGHT (ic));
9752   operand *right = IC_RIGHT (ic);
9753   int size, offset;
9754
9755   D(emitcode(";     genCast",""));
9756
9757   /* if they are equivalent then do nothing */
9758   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9759     return;
9760
9761   aopOp (right, ic, FALSE);
9762   aopOp (result, ic, FALSE);
9763
9764   /* if the result is a bit (and not a bitfield) */
9765   // if (AOP_TYPE (result) == AOP_CRY)
9766   if (IS_BITVAR (OP_SYMBOL (result)->type)
9767       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9768     {
9769       /* if the right size is a literal then
9770          we know what the value is */
9771       if (AOP_TYPE (right) == AOP_LIT)
9772         {
9773           if (((int) operandLitValue (right)))
9774             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9775           else
9776             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9777
9778           goto release;
9779         }
9780
9781       /* the right is also a bit variable */
9782       if (AOP_TYPE (right) == AOP_CRY)
9783         {
9784           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9785           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9786           goto release;
9787         }
9788
9789       /* we need to or */
9790       toBoolean (right);
9791       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9792       goto release;
9793     }
9794
9795
9796   /* if they are the same size : or less */
9797   if (AOP_SIZE (result) <= AOP_SIZE (right))
9798     {
9799
9800       /* if they are in the same place */
9801       if (sameRegs (AOP (right), AOP (result)))
9802         goto release;
9803
9804       /* if they in different places then copy */
9805       size = AOP_SIZE (result);
9806       offset = 0;
9807       while (size--)
9808         {
9809           aopPut (AOP (result),
9810                   aopGet (AOP (right), offset, FALSE, FALSE),
9811                   offset,
9812                   isOperandVolatile (result, FALSE));
9813           offset++;
9814         }
9815       goto release;
9816     }
9817
9818
9819   /* if the result is of type pointer */
9820   if (IS_PTR (ctype))
9821     {
9822
9823       int p_type;
9824       sym_link *type = operandType (right);
9825       sym_link *etype = getSpec (type);
9826
9827       /* pointer to generic pointer */
9828       if (IS_GENPTR (ctype))
9829         {
9830           if (IS_PTR (type))
9831             p_type = DCL_TYPE (type);
9832           else
9833             {
9834               if (SPEC_SCLS(etype)==S_REGISTER) {
9835                 // let's assume it is a generic pointer
9836                 p_type=GPOINTER;
9837               } else {
9838                 /* we have to go by the storage class */
9839                 p_type = PTR_TYPE (SPEC_OCLS (etype));
9840               }
9841             }
9842
9843           /* the first two bytes are known */
9844           size = GPTRSIZE - 1;
9845           offset = 0;
9846           while (size--)
9847             {
9848               aopPut (AOP (result),
9849                       aopGet (AOP (right), offset, FALSE, FALSE),
9850                       offset,
9851                       isOperandVolatile (result, FALSE));
9852               offset++;
9853             }
9854           /* the last byte depending on type */
9855             {
9856                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
9857                 char gpValStr[10];
9858
9859                 if (gpVal == -1)
9860                 {
9861                     // pointerTypeToGPByte will have bitched.
9862                     exit(1);
9863                 }
9864
9865                 sprintf(gpValStr, "#0x%d", gpVal);
9866                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
9867             }
9868           goto release;
9869         }
9870
9871       /* just copy the pointers */
9872       size = AOP_SIZE (result);
9873       offset = 0;
9874       while (size--)
9875         {
9876           aopPut (AOP (result),
9877                   aopGet (AOP (right), offset, FALSE, FALSE),
9878                   offset,
9879                   isOperandVolatile (result, FALSE));
9880           offset++;
9881         }
9882       goto release;
9883     }
9884
9885   /* so we now know that the size of destination is greater
9886      than the size of the source */
9887   /* we move to result for the size of source */
9888   size = AOP_SIZE (right);
9889   offset = 0;
9890   while (size--)
9891     {
9892       aopPut (AOP (result),
9893               aopGet (AOP (right), offset, FALSE, FALSE),
9894               offset,
9895               isOperandVolatile (result, FALSE));
9896       offset++;
9897     }
9898
9899   /* now depending on the sign of the source && destination */
9900   size = AOP_SIZE (result) - AOP_SIZE (right);
9901   /* if unsigned or not an integral type */
9902   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
9903     {
9904       while (size--)
9905         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
9906     }
9907   else
9908     {
9909       /* we need to extend the sign :{ */
9910       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
9911                         FALSE, FALSE);
9912       MOVA (l);
9913       emitcode ("rlc", "a");
9914       emitcode ("subb", "a,acc");
9915       while (size--)
9916         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
9917     }
9918
9919   /* we are done hurray !!!! */
9920
9921 release:
9922   freeAsmop (right, NULL, ic, TRUE);
9923   freeAsmop (result, NULL, ic, TRUE);
9924
9925 }
9926
9927 /*-----------------------------------------------------------------*/
9928 /* genDjnz - generate decrement & jump if not zero instrucion      */
9929 /*-----------------------------------------------------------------*/
9930 static int
9931 genDjnz (iCode * ic, iCode * ifx)
9932 {
9933   symbol *lbl, *lbl1;
9934   if (!ifx)
9935     return 0;
9936
9937   D(emitcode (";     genDjnz",""));
9938
9939   /* if the if condition has a false label
9940      then we cannot save */
9941   if (IC_FALSE (ifx))
9942     return 0;
9943
9944   /* if the minus is not of the form
9945      a = a - 1 */
9946   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
9947       !IS_OP_LITERAL (IC_RIGHT (ic)))
9948     return 0;
9949
9950   if (operandLitValue (IC_RIGHT (ic)) != 1)
9951     return 0;
9952
9953   /* if the size of this greater than one then no
9954      saving */
9955   if (getSize (operandType (IC_RESULT (ic))) > 1)
9956     return 0;
9957
9958   /* otherwise we can save BIG */
9959   lbl = newiTempLabel (NULL);
9960   lbl1 = newiTempLabel (NULL);
9961
9962   aopOp (IC_RESULT (ic), ic, FALSE);
9963
9964   if (AOP_NEEDSACC(IC_RESULT(ic)))
9965   {
9966       /* If the result is accessed indirectly via
9967        * the accumulator, we must explicitly write
9968        * it back after the decrement.
9969        */
9970       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
9971
9972       if (strcmp(rByte, "a"))
9973       {
9974            /* Something is hopelessly wrong */
9975            fprintf(stderr, "*** warning: internal error at %s:%d\n",
9976                    __FILE__, __LINE__);
9977            /* We can just give up; the generated code will be inefficient,
9978             * but what the hey.
9979             */
9980            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9981            return 0;
9982       }
9983       emitcode ("dec", "%s", rByte);
9984       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9985       emitcode ("jnz", "%05d$", lbl->key + 100);
9986   }
9987   else if (IS_AOP_PREG (IC_RESULT (ic)))
9988     {
9989       emitcode ("dec", "%s",
9990                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9991       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9992       emitcode ("jnz", "%05d$", lbl->key + 100);
9993     }
9994   else
9995     {
9996       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
9997                 lbl->key + 100);
9998     }
9999   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10000   emitcode ("", "%05d$:", lbl->key + 100);
10001   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10002   emitcode ("", "%05d$:", lbl1->key + 100);
10003
10004   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10005   ifx->generated = 1;
10006   return 1;
10007 }
10008
10009 /*-----------------------------------------------------------------*/
10010 /* genReceive - generate code for a receive iCode                  */
10011 /*-----------------------------------------------------------------*/
10012 static void
10013 genReceive (iCode * ic)
10014 {
10015     int size = getSize (operandType (IC_RESULT (ic)));
10016     int offset = 0;
10017   D(emitcode (";     genReceive",""));
10018
10019   if (ic->argreg == 1) { /* first parameter */
10020       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10021           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10022            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
10023
10024           regs *tempRegs[4];
10025           int receivingA = 0;
10026           int roffset = 0;
10027
10028           for (offset = 0; offset<size; offset++)
10029             if (!strcmp (fReturn[offset], "a"))
10030               receivingA = 1;
10031
10032           if (!receivingA)
10033             {
10034               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10035                 {
10036                   for (offset = size-1; offset>0; offset--)
10037                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10038                   emitcode("mov","a,%s", fReturn[0]);
10039                   _G.accInUse++;
10040                   aopOp (IC_RESULT (ic), ic, FALSE);
10041                   _G.accInUse--;
10042                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
10043                           isOperandVolatile (IC_RESULT (ic), FALSE));
10044                   for (offset = 1; offset<size; offset++)
10045                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
10046                             isOperandVolatile (IC_RESULT (ic), FALSE));
10047                   goto release;
10048                 }
10049             }
10050           else
10051             {
10052               if (getTempRegs(tempRegs, size, ic))
10053                 {
10054                   for (offset = 0; offset<size; offset++)
10055                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10056                   aopOp (IC_RESULT (ic), ic, FALSE);
10057                   for (offset = 0; offset<size; offset++)
10058                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
10059                             isOperandVolatile (IC_RESULT (ic), FALSE));
10060                   goto release;
10061                 }
10062             }
10063
10064           offset = fReturnSizeMCS51 - size;
10065           while (size--) {
10066               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10067                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10068               offset++;
10069           }
10070           aopOp (IC_RESULT (ic), ic, FALSE);
10071           size = AOP_SIZE (IC_RESULT (ic));
10072           offset = 0;
10073           while (size--) {
10074               emitcode ("pop", "acc");
10075               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10076           }
10077
10078       } else {
10079           _G.accInUse++;
10080           aopOp (IC_RESULT (ic), ic, FALSE);
10081           _G.accInUse--;
10082           assignResultValue (IC_RESULT (ic));
10083       }
10084   } else { /* second receive onwards */
10085       int rb1off ;
10086       aopOp (IC_RESULT (ic), ic, FALSE);
10087       rb1off = ic->argreg;
10088       while (size--) {
10089           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10090       }
10091   }
10092
10093 release:
10094   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10095 }
10096
10097 /*-----------------------------------------------------------------*/
10098 /* genDummyRead - generate code for dummy read of volatiles        */
10099 /*-----------------------------------------------------------------*/
10100 static void
10101 genDummyRead (iCode * ic)
10102 {
10103   operand *op;
10104   int size, offset;
10105
10106   D(emitcode(";     genDummyRead",""));
10107
10108   op = IC_RIGHT (ic);
10109   if (op && IS_SYMOP (op))
10110     {
10111       aopOp (op, ic, FALSE);
10112
10113       /* if the result is a bit */
10114       if (AOP_TYPE (op) == AOP_CRY)
10115         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10116       else
10117         {
10118           /* bit variables done */
10119           /* general case */
10120           size = AOP_SIZE (op);
10121           offset = 0;
10122           while (size--)
10123           {
10124             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10125             offset++;
10126           }
10127         }
10128
10129       freeAsmop (op, NULL, ic, TRUE);
10130     }
10131
10132   op = IC_LEFT (ic);
10133   if (op && IS_SYMOP (op))
10134     {
10135       aopOp (op, ic, FALSE);
10136
10137       /* if the result is a bit */
10138       if (AOP_TYPE (op) == AOP_CRY)
10139         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10140       else
10141         {
10142           /* bit variables done */
10143           /* general case */
10144           size = AOP_SIZE (op);
10145           offset = 0;
10146           while (size--)
10147           {
10148             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
10149             offset++;
10150           }
10151         }
10152
10153       freeAsmop (op, NULL, ic, TRUE);
10154     }
10155 }
10156
10157 /*-----------------------------------------------------------------*/
10158 /* genCritical - generate code for start of a critical sequence    */
10159 /*-----------------------------------------------------------------*/
10160 static void
10161 genCritical (iCode *ic)
10162 {
10163   symbol *tlbl = newiTempLabel (NULL);
10164
10165   D(emitcode(";     genCritical",""));
10166
10167   if (IC_RESULT (ic))
10168     {
10169       aopOp (IC_RESULT (ic), ic, TRUE);
10170       aopPut (AOP (IC_RESULT (ic)), one, 0, 0);
10171       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10172       aopPut (AOP (IC_RESULT (ic)), zero, 0, 0);
10173       emitcode ("", "%05d$:", (tlbl->key + 100));
10174       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10175     }
10176   else
10177     {
10178       emitcode ("setb", "c");
10179       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
10180       emitcode ("clr", "c");
10181       emitcode ("", "%05d$:", (tlbl->key + 100));
10182       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
10183     }
10184 }
10185
10186 /*-----------------------------------------------------------------*/
10187 /* genEndCritical - generate code for end of a critical sequence   */
10188 /*-----------------------------------------------------------------*/
10189 static void
10190 genEndCritical (iCode *ic)
10191 {
10192   D(emitcode(";     genEndCritical",""));
10193
10194   if (IC_RIGHT (ic))
10195     {
10196       aopOp (IC_RIGHT (ic), ic, FALSE);
10197       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
10198         {
10199           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
10200           emitcode ("mov", "ea,c");
10201         }
10202       else
10203         {
10204           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
10205             MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
10206           emitcode ("rrc", "a");
10207           emitcode ("mov", "ea,c");
10208         }
10209       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
10210     }
10211   else
10212     {
10213       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
10214       emitcode ("mov", "ea,c");
10215     }
10216 }
10217
10218 /*-----------------------------------------------------------------*/
10219 /* gen51Code - generate code for 8051 based controllers            */
10220 /*-----------------------------------------------------------------*/
10221 void
10222 gen51Code (iCode * lic)
10223 {
10224   iCode *ic;
10225   int cln = 0;
10226   /* int cseq = 0; */
10227
10228   _G.currentFunc = NULL;
10229   lineHead = lineCurr = NULL;
10230
10231   /* print the allocation information */
10232   if (allocInfo && currFunc)
10233     printAllocInfo (currFunc, codeOutFile);
10234   /* if debug information required */
10235   if (options.debug && currFunc)
10236     {
10237       debugFile->writeFunction (currFunc, lic);
10238     }
10239   /* stack pointer name */
10240   if (options.useXstack)
10241     spname = "_spx";
10242   else
10243     spname = "sp";
10244
10245
10246   for (ic = lic; ic; ic = ic->next)
10247     {
10248       _G.current_iCode = ic;
10249
10250       if (ic->lineno && cln != ic->lineno)
10251         {
10252           if (options.debug)
10253             {
10254               debugFile->writeCLine (ic);
10255             }
10256           if (!options.noCcodeInAsm) {
10257             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
10258                       printCLine(ic->filename, ic->lineno));
10259           }
10260           cln = ic->lineno;
10261         }
10262       #if 0
10263       if (ic->seqPoint && ic->seqPoint != cseq)
10264         {
10265           emitcode ("", "; sequence point %d", ic->seqPoint);
10266           cseq = ic->seqPoint;
10267         }
10268       #endif
10269       if (options.iCodeInAsm) {
10270         char regsInUse[80];
10271         int i;
10272
10273         for (i=0; i<8; i++) {
10274           sprintf (&regsInUse[i],
10275                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
10276         }
10277         regsInUse[i]=0;
10278         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
10279       }
10280       /* if the result is marked as
10281          spilt and rematerializable or code for
10282          this has already been generated then
10283          do nothing */
10284       if (resultRemat (ic) || ic->generated)
10285         continue;
10286
10287       /* depending on the operation */
10288       switch (ic->op)
10289         {
10290         case '!':
10291           genNot (ic);
10292           break;
10293
10294         case '~':
10295           genCpl (ic);
10296           break;
10297
10298         case UNARYMINUS:
10299           genUminus (ic);
10300           break;
10301
10302         case IPUSH:
10303           genIpush (ic);
10304           break;
10305
10306         case IPOP:
10307           /* IPOP happens only when trying to restore a
10308              spilt live range, if there is an ifx statement
10309              following this pop then the if statement might
10310              be using some of the registers being popped which
10311              would destory the contents of the register so
10312              we need to check for this condition and handle it */
10313           if (ic->next &&
10314               ic->next->op == IFX &&
10315               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
10316             genIfx (ic->next, ic);
10317           else
10318             genIpop (ic);
10319           break;
10320
10321         case CALL:
10322           genCall (ic);
10323           break;
10324
10325         case PCALL:
10326           genPcall (ic);
10327           break;
10328
10329         case FUNCTION:
10330           genFunction (ic);
10331           break;
10332
10333         case ENDFUNCTION:
10334           genEndFunction (ic);
10335           break;
10336
10337         case RETURN:
10338           genRet (ic);
10339           break;
10340
10341         case LABEL:
10342           genLabel (ic);
10343           break;
10344
10345         case GOTO:
10346           genGoto (ic);
10347           break;
10348
10349         case '+':
10350           genPlus (ic);
10351           break;
10352
10353         case '-':
10354           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10355             genMinus (ic);
10356           break;
10357
10358         case '*':
10359           genMult (ic);
10360           break;
10361
10362         case '/':
10363           genDiv (ic);
10364           break;
10365
10366         case '%':
10367           genMod (ic);
10368           break;
10369
10370         case '>':
10371           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10372           break;
10373
10374         case '<':
10375           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10376           break;
10377
10378         case LE_OP:
10379         case GE_OP:
10380         case NE_OP:
10381
10382           /* note these two are xlated by algebraic equivalence
10383              during parsing SDCC.y */
10384           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10385                   "got '>=' or '<=' shouldn't have come here");
10386           break;
10387
10388         case EQ_OP:
10389           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10390           break;
10391
10392         case AND_OP:
10393           genAndOp (ic);
10394           break;
10395
10396         case OR_OP:
10397           genOrOp (ic);
10398           break;
10399
10400         case '^':
10401           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10402           break;
10403
10404         case '|':
10405           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10406           break;
10407
10408         case BITWISEAND:
10409           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10410           break;
10411
10412         case INLINEASM:
10413           genInline (ic);
10414           break;
10415
10416         case RRC:
10417           genRRC (ic);
10418           break;
10419
10420         case RLC:
10421           genRLC (ic);
10422           break;
10423
10424         case GETHBIT:
10425           genGetHbit (ic);
10426           break;
10427
10428         case LEFT_OP:
10429           genLeftShift (ic);
10430           break;
10431
10432         case RIGHT_OP:
10433           genRightShift (ic);
10434           break;
10435
10436         case GET_VALUE_AT_ADDRESS:
10437           genPointerGet (ic,
10438                          hasInc (IC_LEFT (ic), ic,
10439                                  getSize (operandType (IC_RESULT (ic)))),
10440                          ifxForOp (IC_RESULT (ic), ic) );
10441           break;
10442
10443         case '=':
10444           if (POINTER_SET (ic))
10445             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10446           else
10447             genAssign (ic);
10448           break;
10449
10450         case IFX:
10451           genIfx (ic, NULL);
10452           break;
10453
10454         case ADDRESS_OF:
10455           genAddrOf (ic);
10456           break;
10457
10458         case JUMPTABLE:
10459           genJumpTab (ic);
10460           break;
10461
10462         case CAST:
10463           genCast (ic);
10464           break;
10465
10466         case RECEIVE:
10467           genReceive (ic);
10468           break;
10469
10470         case SEND:
10471           addSet (&_G.sendSet, ic);
10472           break;
10473
10474         case DUMMY_READ_VOLATILE:
10475           genDummyRead (ic);
10476           break;
10477
10478         case CRITICAL:
10479           genCritical (ic);
10480           break;
10481
10482         case ENDCRITICAL:
10483           genEndCritical (ic);
10484           break;
10485
10486         case SWAP:
10487           genSwap (ic);
10488           break;
10489
10490         default:
10491           ic = ic;
10492         }
10493     }
10494
10495   _G.current_iCode = NULL;
10496
10497   /* now we are ready to call the
10498      peep hole optimizer */
10499   if (!options.nopeep)
10500     peepHole (&lineHead);
10501
10502   /* now do the actual printing */
10503   printLine (lineHead, codeOutFile);
10504   return;
10505 }