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