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