* src/mcs51/gen.c (genCpl): quick fix for bug #974835
[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     short r0InB;
72     short r1InB;
73     short accInUse;
74     short inLine;
75     short debugLine;
76     short nRegsSaved;
77     set *sendSet;
78     iCode *current_iCode;
79     symbol *currentFunc;
80   }
81 _G;
82
83 static char *rb1regs[] = {
84     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
85 };
86
87 extern int mcs51_ptrRegReq;
88 extern int mcs51_nRegs;
89 extern FILE *codeOutFile;
90 static void saveRBank (int, iCode *, bool);
91 #define RESULTONSTACK(x) \
92                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
93                          IC_RESULT(x)->aop->type == AOP_STK )
94
95 #define MOVA(x) mova(x)  /* use function to avoid multiple eval */
96 #define CLRC    emitcode("clr","c")
97 #define SETC    emitcode("setb","c")
98
99 static lineNode *lineHead = NULL;
100 static lineNode *lineCurr = NULL;
101
102 static unsigned char SLMask[] =
103 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
104  0xE0, 0xC0, 0x80, 0x00};
105 static unsigned char SRMask[] =
106 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
107  0x07, 0x03, 0x01, 0x00};
108
109 #define LSB     0
110 #define MSB16   1
111 #define MSB24   2
112 #define MSB32   3
113
114 /*-----------------------------------------------------------------*/
115 /* emitcode - writes the code into a file : for now it is simple    */
116 /*-----------------------------------------------------------------*/
117 static void
118 emitcode (char *inst, const char *fmt,...)
119 {
120   va_list ap;
121   char lb[INITIAL_INLINEASM];
122   char *lbp = lb;
123
124   va_start (ap, fmt);
125
126   if (inst && *inst)
127     {
128       if (fmt && *fmt)
129         sprintf (lb, "%s\t", inst);
130       else
131         sprintf (lb, "%s", inst);
132       vsprintf (lb + (strlen (lb)), fmt, ap);
133     }
134   else
135     vsprintf (lb, fmt, ap);
136
137   while (isspace (*lbp))
138     lbp++;
139
140   //printf ("%s\n", lb);
141   
142   if (lbp && *lbp)
143     lineCurr = (lineCurr ?
144                 connectLine (lineCurr, newLineNode (lb)) :
145                 (lineHead = newLineNode (lb)));
146   lineCurr->isInline = _G.inLine;
147   lineCurr->isDebug = _G.debugLine;
148   lineCurr->ic = _G.current_iCode;
149   lineCurr->isComment = (*lbp==';');
150   va_end (ap);
151 }
152
153 /*-----------------------------------------------------------------*/
154 /* mcs51_emitDebuggerSymbol - associate the current code location  */
155 /*   with a debugger symbol                                        */
156 /*-----------------------------------------------------------------*/
157 void
158 mcs51_emitDebuggerSymbol (char * debugSym)
159 {
160   _G.debugLine = 1;
161   emitcode ("", "%s ==.", debugSym);
162   _G.debugLine = 0;
163 }
164
165 /*-----------------------------------------------------------------*/
166 /* mova - moves specified value into accumulator                   */
167 /*-----------------------------------------------------------------*/
168 static void
169 mova (const char *x)
170 {
171   /* do some early peephole optimization */
172   if (!strcmp(x, "a") || !strcmp(x, "acc"))
173     return;
174
175   emitcode("mov","a,%s", x);
176 }
177
178 /*-----------------------------------------------------------------*/
179 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
180 /*-----------------------------------------------------------------*/
181 static regs *
182 getFreePtr (iCode * ic, asmop ** aopp, bool result)
183 {
184   bool r0iu = FALSE, r1iu = FALSE;
185   bool r0ou = FALSE, r1ou = FALSE;
186
187   /* the logic: if r0 & r1 used in the instruction
188      then we are in trouble otherwise */
189
190   /* first check if r0 & r1 are used by this
191      instruction, in which case we are in trouble */
192   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
193   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
194   if (r0iu && r1iu) {
195       goto endOfWorld;
196     }
197
198   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
199   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
200
201   /* if no usage of r0 then return it */
202   if (!r0iu && !r0ou)
203     {
204       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
205       (*aopp)->type = AOP_R0;
206
207       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
208     }
209
210   /* if no usage of r1 then return it */
211   if (!r1iu && !r1ou)
212     {
213       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
214       (*aopp)->type = AOP_R1;
215
216       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
217     }
218
219   /* now we know they both have usage */
220   /* if r0 not used in this instruction */
221   if (!r0iu)
222     {
223       /* push it if not already pushed */
224       if (ic->op == IPUSH)
225         {
226           emitcode ("mov", "b,%s",
227                     mcs51_regWithIdx (R0_IDX)->dname);
228           _G.r0InB++;
229         }
230       else if (!_G.r0Pushed)
231         {
232           emitcode ("push", "%s",
233                     mcs51_regWithIdx (R0_IDX)->dname);
234           _G.r0Pushed++;
235         }
236
237       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
238       (*aopp)->type = AOP_R0;
239
240       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
241     }
242
243   /* if r1 not used then */
244
245   if (!r1iu)
246     {
247       /* push it if not already pushed */
248       if (ic->op == IPUSH)
249         {
250           emitcode ("mov", "b,%s",
251                     mcs51_regWithIdx (R1_IDX)->dname);
252           _G.r1InB++;
253         }
254       else if (!_G.r1Pushed)
255         {
256           emitcode ("push", "%s",
257                     mcs51_regWithIdx (R1_IDX)->dname);
258           _G.r1Pushed++;
259         }
260
261       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
262       (*aopp)->type = AOP_R1;
263       return mcs51_regWithIdx (R1_IDX);
264     }
265 endOfWorld:
266   /* I said end of world, but not quite end of world yet */
267   if (result) {
268     /* we can push it on the stack */
269     (*aopp)->type = AOP_STK;
270     return NULL;
271   } else {
272     /* in the case that result AND left AND right needs a pointer reg
273        we can safely use the result's */
274     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
275       (*aopp)->type = AOP_R0;
276       return mcs51_regWithIdx (R0_IDX);
277     }
278     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
279       (*aopp)->type = AOP_R1;
280       return mcs51_regWithIdx (R1_IDX);
281     }
282   }
283
284   /* now this is REALLY the end of the world */
285   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
286           "getFreePtr should never reach here");
287   exit (1);
288 }
289
290
291 /*-----------------------------------------------------------------*/
292 /* getTempRegs - initialize an array of pointers to GPR registers */
293 /*               that are not in use. Returns 1 if the requested   */
294 /*               number of registers were available, 0 otherwise.  */
295 /*-----------------------------------------------------------------*/
296 int
297 getTempRegs(regs **tempRegs, int size, iCode *ic)
298 {
299   bitVect * freeRegs;
300   int i;
301   int offset;
302
303   if (!ic)
304     ic = _G.current_iCode;
305   if (!ic)
306     return 0;
307   if (!_G.currentFunc)
308     return 0;
309
310   freeRegs = newBitVect(8);
311   bitVectSetBit (freeRegs, R2_IDX);
312   bitVectSetBit (freeRegs, R3_IDX);
313   bitVectSetBit (freeRegs, R4_IDX);
314   bitVectSetBit (freeRegs, R5_IDX);
315   bitVectSetBit (freeRegs, R6_IDX);
316   bitVectSetBit (freeRegs, R7_IDX);
317
318   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
319     {
320       bitVect * newfreeRegs;
321       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
322       freeBitVect(freeRegs);
323       freeRegs = newfreeRegs;
324     }
325   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
326
327   offset = 0;
328   for (i=0; i<freeRegs->size; i++)
329     {
330       if (bitVectBitValue(freeRegs,i))
331         tempRegs[offset++] = mcs51_regWithIdx(i);
332       if (offset>=size)
333         {
334           freeBitVect(freeRegs);
335           return 1;
336         }
337     }
338
339   freeBitVect(freeRegs);
340   return 1;
341 }
342
343
344 /*-----------------------------------------------------------------*/
345 /* newAsmop - creates a new asmOp                                  */
346 /*-----------------------------------------------------------------*/
347 static asmop *
348 newAsmop (short type)
349 {
350   asmop *aop;
351
352   aop = Safe_calloc (1, sizeof (asmop));
353   aop->type = type;
354   return aop;
355 }
356
357 /*-----------------------------------------------------------------*/
358 /* pointerCode - returns the code for a pointer type               */
359 /*-----------------------------------------------------------------*/
360 static int
361 pointerCode (sym_link * etype)
362 {
363
364   return PTR_TYPE (SPEC_OCLS (etype));
365
366 }
367
368
369 /*-----------------------------------------------------------------*/
370 /* leftRightUseAcc - returns size of accumulator use by operands   */
371 /*-----------------------------------------------------------------*/
372 static int
373 leftRightUseAcc(iCode *ic)
374 {
375   operand *op;
376   int size;
377   int accuseSize = 0;
378   int accuse = 0;
379
380   if (!ic)
381     {
382       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
383               "null iCode pointer");
384       return 0;
385     }
386
387   if (ic->op == IFX)
388     {
389       op = IC_COND (ic);
390       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
391         {
392           accuse = 1;
393           size = getSize (OP_SYMBOL (op)->type);
394           if (size>accuseSize)
395             accuseSize = size;
396         }
397     }
398   else if (ic->op == JUMPTABLE)
399     {
400       op = IC_JTCOND (ic);
401       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
402         {
403           accuse = 1;
404           size = getSize (OP_SYMBOL (op)->type);
405           if (size>accuseSize)
406             accuseSize = size;
407         }
408     }
409   else
410     {
411       op = IC_LEFT (ic);
412       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
413         {
414           accuse = 1;
415           size = getSize (OP_SYMBOL (op)->type);
416           if (size>accuseSize)
417             accuseSize = size;
418         }
419       op = IC_RIGHT (ic);
420       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
421         {
422           accuse = 1;
423           size = getSize (OP_SYMBOL (op)->type);
424           if (size>accuseSize)
425             accuseSize = size;
426         }
427     }
428
429   if (accuseSize)
430     return accuseSize;
431   else
432     return accuse;
433 }
434
435
436 /*-----------------------------------------------------------------*/
437 /* aopForSym - for a true symbol                                   */
438 /*-----------------------------------------------------------------*/
439 static asmop *
440 aopForSym (iCode * ic, symbol * sym, bool result)
441 {
442   asmop *aop;
443   memmap *space;
444
445   wassertl (ic != NULL, "Got a null iCode");
446   wassertl (sym != NULL, "Got a null symbol");
447
448   space = SPEC_OCLS (sym->etype);
449
450   /* if already has one */
451   if (sym->aop)
452     return sym->aop;
453
454   /* assign depending on the storage class */
455   /* if it is on the stack or indirectly addressable */
456   /* space we need to assign either r0 or r1 to it   */
457   if (sym->onStack || sym->iaccess)
458     {
459       sym->aop = aop = newAsmop (0);
460       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
461       aop->size = getSize (sym->type);
462
463       /* now assign the address of the variable to
464          the pointer register */
465       if (aop->type != AOP_STK)
466         {
467
468           if (sym->onStack)
469             {
470               if (_G.accInUse || leftRightUseAcc (ic))
471                 emitcode ("push", "acc");
472
473               emitcode ("mov", "a,_bp");
474               emitcode ("add", "a,#0x%02x",
475                         ((sym->stack < 0) ?
476                          ((char) (sym->stack - _G.nRegsSaved)) :
477                          ((char) sym->stack)) & 0xff);
478               emitcode ("mov", "%s,a",
479                         aop->aopu.aop_ptr->name);
480
481               if (_G.accInUse || leftRightUseAcc (ic))
482                 emitcode ("pop", "acc");
483             }
484           else
485             emitcode ("mov", "%s,#%s",
486                       aop->aopu.aop_ptr->name,
487                       sym->rname);
488           aop->paged = space->paged;
489         }
490       else
491         aop->aopu.aop_stk = sym->stack;
492       return aop;
493     }
494
495   /* if in bit space */
496   if (IN_BITSPACE (space))
497     {
498       sym->aop = aop = newAsmop (AOP_CRY);
499       aop->aopu.aop_dir = sym->rname;
500       aop->size = getSize (sym->type);
501       return aop;
502     }
503   /* if it is in direct space */
504   if (IN_DIRSPACE (space))
505     {
506       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
507       //printTypeChainRaw(sym->type, NULL);
508       //printf("space = %s\n", space ? space->sname : "NULL");
509       sym->aop = aop = newAsmop (AOP_DIR);
510       aop->aopu.aop_dir = sym->rname;
511       aop->size = getSize (sym->type);
512       return aop;
513     }
514
515   /* special case for a function */
516   if (IS_FUNC (sym->type))
517     {
518       sym->aop = aop = newAsmop (AOP_IMMD);
519       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
520       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
521       aop->size = FPTRSIZE;
522       return aop;
523     }
524
525   /* only remaining is far space */
526   /* in which case DPTR gets the address */
527   sym->aop = aop = newAsmop (AOP_DPTR);
528   emitcode ("mov", "dptr,#%s", sym->rname);
529   aop->size = getSize (sym->type);
530
531   /* if it is in code space */
532   if (IN_CODESPACE (space))
533     aop->code = 1;
534
535   return aop;
536 }
537
538 /*-----------------------------------------------------------------*/
539 /* aopForRemat - rematerialzes an object                           */
540 /*-----------------------------------------------------------------*/
541 static asmop *
542 aopForRemat (symbol * sym)
543 {
544   iCode *ic = sym->rematiCode;
545   asmop *aop = newAsmop (AOP_IMMD);
546   int ptr_type=0;
547   int val = 0;
548
549   for (;;)
550     {
551       if (ic->op == '+')
552         val += (int) operandLitValue (IC_RIGHT (ic));
553       else if (ic->op == '-')
554         val -= (int) operandLitValue (IC_RIGHT (ic));
555       else if (IS_CAST_ICODE(ic)) {
556               sym_link *from_type = operandType(IC_RIGHT(ic));
557               aop->aopu.aop_immd.from_cast_remat = 1;
558               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
559               ptr_type = DCL_TYPE(from_type);
560               if (ptr_type == IPOINTER) {
561                 // bug #481053
562                 ptr_type = POINTER;
563               }
564               continue ;
565       } else break;
566
567       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
568     }
569
570   if (val)
571     sprintf (buffer, "(%s %c 0x%04x)",
572              OP_SYMBOL (IC_LEFT (ic))->rname,
573              val >= 0 ? '+' : '-',
574              abs (val) & 0xffff);
575   else
576     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
577
578   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
579   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
580   /* set immd2 field if required */
581   if (aop->aopu.aop_immd.from_cast_remat) {
582           sprintf(buffer,"#0x%02x",ptr_type);
583           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
584           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
585   }
586
587   return aop;
588 }
589
590 /*-----------------------------------------------------------------*/
591 /* regsInCommon - two operands have some registers in common       */
592 /*-----------------------------------------------------------------*/
593 static bool
594 regsInCommon (operand * op1, operand * op2)
595 {
596   symbol *sym1, *sym2;
597   int i;
598
599   /* if they have registers in common */
600   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
601     return FALSE;
602
603   sym1 = OP_SYMBOL (op1);
604   sym2 = OP_SYMBOL (op2);
605
606   if (sym1->nRegs == 0 || sym2->nRegs == 0)
607     return FALSE;
608
609   for (i = 0; i < sym1->nRegs; i++)
610     {
611       int j;
612       if (!sym1->regs[i])
613         continue;
614
615       for (j = 0; j < sym2->nRegs; j++)
616         {
617           if (!sym2->regs[j])
618             continue;
619
620           if (sym2->regs[j] == sym1->regs[i])
621             return TRUE;
622         }
623     }
624
625   return FALSE;
626 }
627
628 /*-----------------------------------------------------------------*/
629 /* operandsEqu - equivalent                                        */
630 /*-----------------------------------------------------------------*/
631 static bool
632 operandsEqu (operand * op1, operand * op2)
633 {
634   symbol *sym1, *sym2;
635
636   /* if they not symbols */
637   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
638     return FALSE;
639
640   sym1 = OP_SYMBOL (op1);
641   sym2 = OP_SYMBOL (op2);
642
643   /* if both are itemps & one is spilt
644      and the other is not then false */
645   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
646       sym1->isspilt != sym2->isspilt)
647     return FALSE;
648
649   /* if they are the same */
650   if (sym1 == sym2)
651     return TRUE;
652
653   if (sym1->rname[0] && sym2->rname[0]
654       && strcmp (sym1->rname, sym2->rname) == 0)
655     return TRUE;
656
657   /* if left is a tmp & right is not */
658   if (IS_ITEMP (op1) &&
659       !IS_ITEMP (op2) &&
660       sym1->isspilt &&
661       (sym1->usl.spillLoc == sym2))
662     return TRUE;
663
664   if (IS_ITEMP (op2) &&
665       !IS_ITEMP (op1) &&
666       sym2->isspilt &&
667       sym1->level > 0 &&
668       (sym2->usl.spillLoc == sym1))
669     return TRUE;
670
671   return FALSE;
672 }
673
674 /*-----------------------------------------------------------------*/
675 /* sameRegs - two asmops have the same registers                   */
676 /*-----------------------------------------------------------------*/
677 static bool
678 sameRegs (asmop * aop1, asmop * aop2)
679 {
680   int i;
681
682   if (aop1 == aop2)
683     return TRUE;
684
685   if (aop1->type != AOP_REG ||
686       aop2->type != AOP_REG)
687     return FALSE;
688
689   if (aop1->size != aop2->size)
690     return FALSE;
691
692   for (i = 0; i < aop1->size; i++)
693     if (aop1->aopu.aop_reg[i] !=
694         aop2->aopu.aop_reg[i])
695       return FALSE;
696
697   return TRUE;
698 }
699
700 /*-----------------------------------------------------------------*/
701 /* aopOp - allocates an asmop for an operand  :                    */
702 /*-----------------------------------------------------------------*/
703 static void
704 aopOp (operand * op, iCode * ic, bool result)
705 {
706   asmop *aop;
707   symbol *sym;
708   int i;
709
710   if (!op)
711     return;
712
713   /* if this a literal */
714   if (IS_OP_LITERAL (op))
715     {
716       op->aop = aop = newAsmop (AOP_LIT);
717       aop->aopu.aop_lit = op->operand.valOperand;
718       aop->size = getSize (operandType (op));
719       return;
720     }
721
722   /* if already has a asmop then continue */
723   if (op->aop )
724     return;
725
726   /* if the underlying symbol has a aop */
727   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
728     {
729       op->aop = OP_SYMBOL (op)->aop;
730       return;
731     }
732
733   /* if this is a true symbol */
734   if (IS_TRUE_SYMOP (op))
735     {
736       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
737       return;
738     }
739
740   /* this is a temporary : this has
741      only four choices :
742      a) register
743      b) spillocation
744      c) rematerialize
745      d) conditional
746      e) can be a return use only */
747
748   sym = OP_SYMBOL (op);
749
750   /* if the type is a conditional */
751   if (sym->regType == REG_CND)
752     {
753       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
754       aop->size = 0;
755       return;
756     }
757
758   /* if it is spilt then two situations
759      a) is rematerialize
760      b) has a spill location */
761   if (sym->isspilt || sym->nRegs == 0)
762     {
763
764       /* rematerialize it NOW */
765       if (sym->remat)
766         {
767           sym->aop = op->aop = aop =
768             aopForRemat (sym);
769           aop->size = getSize (sym->type);
770           return;
771         }
772
773       if (sym->accuse)
774         {
775           int i;
776           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
777           aop->size = getSize (sym->type);
778           for (i = 0; i < 2; i++)
779             aop->aopu.aop_str[i] = accUse[i];
780           return;
781         }
782
783       if (sym->ruonly)
784         {
785           unsigned i;
786
787           aop = op->aop = sym->aop = newAsmop (AOP_STR);
788           aop->size = getSize (sym->type);
789           for (i = 0; i < fReturnSizeMCS51; i++)
790             aop->aopu.aop_str[i] = fReturn[i];
791           return;
792         }
793
794       if (sym->usl.spillLoc)
795         {
796           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
797             {
798               /* force a new aop if sizes differ */
799               sym->usl.spillLoc->aop = NULL;
800             }
801           sym->aop = op->aop = aop =
802                      aopForSym (ic, sym->usl.spillLoc, result);
803           aop->size = getSize (sym->type);
804           return;
805         }
806
807       /* else must be a dummy iTemp */
808       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
809       aop->size = getSize (sym->type);
810       return;
811     }
812
813   /* must be in a register */
814   sym->aop = op->aop = aop = newAsmop (AOP_REG);
815   aop->size = sym->nRegs;
816   for (i = 0; i < sym->nRegs; i++)
817     aop->aopu.aop_reg[i] = sym->regs[i];
818 }
819
820 /*-----------------------------------------------------------------*/
821 /* freeAsmop - free up the asmop given to an operand               */
822 /*----------------------------------------------------------------*/
823 static void
824 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
825 {
826   asmop *aop;
827
828   if (!op)
829     aop = aaop;
830   else
831     aop = op->aop;
832
833   if (!aop)
834     return;
835
836   if (aop->freed)
837     goto dealloc;
838
839   aop->freed = 1;
840
841   /* depending on the asmop type only three cases need work AOP_RO
842      , AOP_R1 && AOP_STK */
843   switch (aop->type)
844     {
845     case AOP_R0:
846       if (_G.r0InB)
847         {
848           emitcode ("mov", "r0,b");
849           _G.r0InB--;
850         }
851       else if (_G.r0Pushed)
852         {
853           if (pop)
854             {
855               emitcode ("pop", "ar0");
856               _G.r0Pushed--;
857             }
858         }
859       bitVectUnSetBit (ic->rUsed, R0_IDX);
860       break;
861
862     case AOP_R1:
863       if (_G.r1InB)
864         {
865           emitcode ("mov", "r1,b");
866           _G.r1InB--;
867         }
868       if (_G.r1Pushed)
869         {
870           if (pop)
871             {
872               emitcode ("pop", "ar1");
873               _G.r1Pushed--;
874             }
875         }
876       bitVectUnSetBit (ic->rUsed, R1_IDX);
877       break;
878
879     case AOP_STK:
880       {
881         int sz = aop->size;
882         int stk = aop->aopu.aop_stk + aop->size - 1;
883         bitVectUnSetBit (ic->rUsed, R0_IDX);
884         bitVectUnSetBit (ic->rUsed, R1_IDX);
885
886         getFreePtr (ic, &aop, FALSE);
887
888         if (stk)
889           {
890             emitcode ("mov", "a,_bp");
891             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
892             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
893           }
894         else
895           {
896             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
897           }
898
899         while (sz--)
900           {
901             emitcode ("pop", "acc");
902             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
903             if (!sz)
904               break;
905             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
906           }
907         op->aop = aop;
908         freeAsmop (op, NULL, ic, TRUE);
909         if (_G.r1Pushed)
910           {
911             emitcode ("pop", "ar1");
912             _G.r1Pushed--;
913           }
914
915         if (_G.r0Pushed)
916           {
917             emitcode ("pop", "ar0");
918             _G.r0Pushed--;
919           }
920       }
921     }
922
923 dealloc:
924   /* all other cases just dealloc */
925   if (op)
926     {
927       op->aop = NULL;
928       if (IS_SYMOP (op))
929         {
930           OP_SYMBOL (op)->aop = NULL;
931           /* if the symbol has a spill */
932           if (SPIL_LOC (op))
933             SPIL_LOC (op)->aop = NULL;
934         }
935     }
936 }
937
938 /*------------------------------------------------------------------*/
939 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
940 /*                      pop r0 or r1 off stack if pushed            */
941 /*------------------------------------------------------------------*/
942 static void
943 freeForBranchAsmop (operand * op)
944 {
945   asmop *aop;
946
947   if (!op)
948     return;
949     
950   aop = op->aop;
951
952   if (!aop)
953     return;
954
955   if (aop->freed)
956     return;
957
958   switch (aop->type)
959     {
960     case AOP_R0:
961       if (_G.r0InB)
962         {
963           emitcode ("mov", "r0,b");
964         }
965       else if (_G.r0Pushed)
966         {
967           emitcode ("pop", "ar0");
968         }
969       break;
970
971     case AOP_R1:
972       if (_G.r1InB)
973         {
974           emitcode ("mov", "r1,b");
975         }
976       else if (_G.r1Pushed)
977         {
978           emitcode ("pop", "ar1");
979         }
980       break;
981
982     case AOP_STK:
983       {
984         int sz = aop->size;
985         int stk = aop->aopu.aop_stk + aop->size - 1;
986
987         emitcode ("mov", "b,r0");
988         if (stk)
989           {
990             emitcode ("mov", "a,_bp");
991             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
992             emitcode ("mov", "r0,a");
993           }
994         else
995           {
996             emitcode ("mov", "r0,_bp");
997           }
998
999         while (sz--)
1000           {
1001             emitcode ("pop", "acc");
1002             emitcode ("mov", "@r0,a");
1003             if (!sz)
1004               break;
1005             emitcode ("dec", "r0");
1006           }
1007         emitcode ("mov", "r0,b");
1008       }
1009     }
1010
1011 }
1012
1013 /*-----------------------------------------------------------------*/
1014 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1015 /*                 clobber the accumulator                         */
1016 /*-----------------------------------------------------------------*/
1017 static bool
1018 aopGetUsesAcc (asmop *aop, int offset)
1019 {
1020   if (offset > (aop->size - 1))
1021     return FALSE;
1022
1023   switch (aop->type)
1024     {
1025
1026     case AOP_R0:
1027     case AOP_R1:
1028       if (aop->paged)
1029         return TRUE;
1030       return FALSE;
1031     case AOP_DPTR:
1032       return TRUE;
1033     case AOP_IMMD:
1034       return FALSE;
1035     case AOP_DIR:
1036       return FALSE;
1037     case AOP_REG:
1038       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1039       return FALSE;
1040     case AOP_CRY:
1041       return TRUE;
1042     case AOP_ACC:
1043       return TRUE;
1044     case AOP_LIT:
1045       return FALSE;
1046     case AOP_STR:
1047       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1048         return TRUE;
1049       return FALSE;
1050     case AOP_DUMMY:
1051       return FALSE;
1052     default:
1053       /* Error case --- will have been caught already */
1054       wassert(0);
1055       return FALSE;
1056     }
1057 }
1058
1059 /*-----------------------------------------------------------------*/
1060 /* aopGet - for fetching value of the aop                          */
1061 /*-----------------------------------------------------------------*/
1062 static char *
1063 aopGet (asmop * aop, int offset, bool bit16, bool dname)
1064 {
1065   char *s = buffer;
1066   char *rs;
1067
1068   /* offset is greater than
1069      size then zero */
1070   if (offset > (aop->size - 1) &&
1071       aop->type != AOP_LIT)
1072     return zero;
1073
1074   /* depending on type */
1075   switch (aop->type)
1076     {
1077     case AOP_DUMMY:
1078       return zero;
1079
1080     case AOP_R0:
1081     case AOP_R1:
1082       /* if we need to increment it */
1083       while (offset > aop->coff)
1084         {
1085           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1086           aop->coff++;
1087         }
1088
1089       while (offset < aop->coff)
1090         {
1091           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1092           aop->coff--;
1093         }
1094
1095       aop->coff = offset;
1096       if (aop->paged)
1097         {
1098           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1099           return (dname ? "acc" : "a");
1100         }
1101       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1102       rs = Safe_calloc (1, strlen (s) + 1);
1103       strcpy (rs, s);
1104       return rs;
1105
1106     case AOP_DPTR:
1107       if (aop->code && aop->coff==0 && offset>=1) {
1108         emitcode ("mov", "a,#0x%02x", offset);
1109         emitcode ("movc", "a,@a+dptr");
1110         return (dname ? "acc" : "a");
1111       }
1112
1113       while (offset > aop->coff)
1114         {
1115           emitcode ("inc", "dptr");
1116           aop->coff++;
1117         }
1118
1119       while (offset < aop->coff)
1120         {
1121           emitcode ("lcall", "__decdptr");
1122           aop->coff--;
1123         }
1124
1125       aop->coff = offset;
1126       if (aop->code)
1127         {
1128           emitcode ("clr", "a");
1129           emitcode ("movc", "a,@a+dptr");
1130         }
1131       else
1132         {
1133           emitcode ("movx", "a,@dptr");
1134         }
1135       return (dname ? "acc" : "a");
1136
1137
1138     case AOP_IMMD:
1139       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1140               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1141       } else if (bit16)
1142         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1143       else if (offset)
1144         sprintf (s, "#(%s >> %d)",
1145                  aop->aopu.aop_immd.aop_immd1,
1146                  offset * 8);
1147       else
1148         sprintf (s, "#%s",
1149                  aop->aopu.aop_immd.aop_immd1);
1150       rs = Safe_calloc (1, strlen (s) + 1);
1151       strcpy (rs, s);
1152       return rs;
1153
1154     case AOP_DIR:
1155       if (offset)
1156         sprintf (s, "(%s + %d)",
1157                  aop->aopu.aop_dir,
1158                  offset);
1159       else
1160         sprintf (s, "%s", aop->aopu.aop_dir);
1161       rs = Safe_calloc (1, strlen (s) + 1);
1162       strcpy (rs, s);
1163       return rs;
1164
1165     case AOP_REG:
1166       if (dname)
1167         return aop->aopu.aop_reg[offset]->dname;
1168       else
1169         return aop->aopu.aop_reg[offset]->name;
1170
1171     case AOP_CRY:
1172       emitcode ("clr", "a");
1173       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1174       emitcode ("rlc", "a");
1175       return (dname ? "acc" : "a");
1176
1177     case AOP_ACC:
1178       if (!offset && dname)
1179         return "acc";
1180       return aop->aopu.aop_str[offset];
1181
1182     case AOP_LIT:
1183       return aopLiteral (aop->aopu.aop_lit, offset);
1184
1185     case AOP_STR:
1186       aop->coff = offset;
1187       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1188           dname)
1189         return "acc";
1190
1191       return aop->aopu.aop_str[offset];
1192
1193     }
1194
1195   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1196           "aopget got unsupported aop->type");
1197   exit (1);
1198 }
1199 /*-----------------------------------------------------------------*/
1200 /* aopPut - puts a string for a aop                                */
1201 /*-----------------------------------------------------------------*/
1202 static void
1203 aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
1204 {
1205   char *d = buffer;
1206
1207   if (aop->size && offset > (aop->size - 1))
1208     {
1209       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1210               "aopPut got offset > aop->size");
1211       exit (1);
1212     }
1213
1214   /* will assign value to value */
1215   /* depending on where it is ofcourse */
1216   switch (aop->type)
1217     {
1218     case AOP_DUMMY:
1219       MOVA (s);         /* read s in case it was volatile */
1220       break;
1221
1222     case AOP_DIR:
1223       if (offset)
1224         sprintf (d, "(%s + %d)",
1225                  aop->aopu.aop_dir, offset);
1226       else
1227         sprintf (d, "%s", aop->aopu.aop_dir);
1228
1229       if (strcmp (d, s) ||
1230           bvolatile)
1231         emitcode ("mov", "%s,%s", d, s);
1232
1233       break;
1234
1235     case AOP_REG:
1236       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1237           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1238         {
1239           if (*s == '@' ||
1240               strcmp (s, "r0") == 0 ||
1241               strcmp (s, "r1") == 0 ||
1242               strcmp (s, "r2") == 0 ||
1243               strcmp (s, "r3") == 0 ||
1244               strcmp (s, "r4") == 0 ||
1245               strcmp (s, "r5") == 0 ||
1246               strcmp (s, "r6") == 0 ||
1247               strcmp (s, "r7") == 0)
1248             emitcode ("mov", "%s,%s",
1249                       aop->aopu.aop_reg[offset]->dname, s);
1250           else
1251             emitcode ("mov", "%s,%s",
1252                       aop->aopu.aop_reg[offset]->name, s);
1253         }
1254       break;
1255
1256     case AOP_DPTR:
1257       if (aop->code)
1258         {
1259           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1260                   "aopPut writing to code space");
1261           exit (1);
1262         }
1263
1264       while (offset > aop->coff)
1265         {
1266           aop->coff++;
1267           emitcode ("inc", "dptr");
1268         }
1269
1270       while (offset < aop->coff)
1271         {
1272           aop->coff--;
1273           emitcode ("lcall", "__decdptr");
1274         }
1275
1276       aop->coff = offset;
1277
1278       /* if not in accumulater */
1279       MOVA (s);
1280
1281       emitcode ("movx", "@dptr,a");
1282       break;
1283
1284     case AOP_R0:
1285     case AOP_R1:
1286       while (offset > aop->coff)
1287         {
1288           aop->coff++;
1289           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1290         }
1291       while (offset < aop->coff)
1292         {
1293           aop->coff--;
1294           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1295         }
1296       aop->coff = offset;
1297
1298       if (aop->paged)
1299         {
1300           MOVA (s);
1301           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1302
1303         }
1304       else if (*s == '@')
1305         {
1306           MOVA (s);
1307           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1308         }
1309       else if (strcmp (s, "r0") == 0 ||
1310                strcmp (s, "r1") == 0 ||
1311                strcmp (s, "r2") == 0 ||
1312                strcmp (s, "r3") == 0 ||
1313                strcmp (s, "r4") == 0 ||
1314                strcmp (s, "r5") == 0 ||
1315                strcmp (s, "r6") == 0 ||
1316                strcmp (s, "r7") == 0)
1317         {
1318           char buffer[10];
1319           sprintf (buffer, "a%s", s);
1320           emitcode ("mov", "@%s,%s",
1321                     aop->aopu.aop_ptr->name, buffer);
1322         }
1323       else
1324         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1325
1326       break;
1327
1328     case AOP_STK:
1329       if (strcmp (s, "a") == 0)
1330         emitcode ("push", "acc");
1331       else
1332         if (*s=='@') {
1333           MOVA(s);
1334           emitcode ("push", "acc");
1335         } else {
1336           emitcode ("push", s);
1337         }
1338
1339       break;
1340
1341     case AOP_CRY:
1342       /* if bit variable */
1343       if (!aop->aopu.aop_dir)
1344         {
1345           emitcode ("clr", "a");
1346           emitcode ("rlc", "a");
1347         }
1348       else
1349         {
1350           if (s == zero)
1351             emitcode ("clr", "%s", aop->aopu.aop_dir);
1352           else if (s == one)
1353             emitcode ("setb", "%s", aop->aopu.aop_dir);
1354           else if (!strcmp (s, "c"))
1355             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1356           else
1357             {
1358               if (strcmp (s, "a"))
1359                 {
1360                   MOVA (s);
1361                 }
1362               {
1363                 /* set C, if a >= 1 */
1364                 emitcode ("add", "a,#0xff");
1365                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1366               }
1367             }
1368         }
1369       break;
1370
1371     case AOP_STR:
1372       aop->coff = offset;
1373       if (strcmp (aop->aopu.aop_str[offset], s) ||
1374           bvolatile)
1375         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1376       break;
1377
1378     case AOP_ACC:
1379       aop->coff = offset;
1380       if (!offset && (strcmp (s, "acc") == 0) &&
1381           !bvolatile)
1382         break;
1383
1384       if (strcmp (aop->aopu.aop_str[offset], s) &&
1385           !bvolatile)
1386         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1387       break;
1388
1389     default:
1390       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1391               "aopPut got unsupported aop->type");
1392       exit (1);
1393     }
1394
1395 }
1396
1397
1398 #if 0
1399 /*-----------------------------------------------------------------*/
1400 /* pointToEnd :- points to the last byte of the operand            */
1401 /*-----------------------------------------------------------------*/
1402 static void
1403 pointToEnd (asmop * aop)
1404 {
1405   int count;
1406   if (!aop)
1407     return;
1408
1409   aop->coff = count = (aop->size - 1);
1410   switch (aop->type)
1411     {
1412     case AOP_R0:
1413     case AOP_R1:
1414       while (count--)
1415         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1416       break;
1417     case AOP_DPTR:
1418       while (count--)
1419         emitcode ("inc", "dptr");
1420       break;
1421     }
1422
1423 }
1424 #endif
1425
1426 /*-----------------------------------------------------------------*/
1427 /* reAdjustPreg - points a register back to where it should        */
1428 /*-----------------------------------------------------------------*/
1429 static void
1430 reAdjustPreg (asmop * aop)
1431 {
1432   if ((aop->coff==0) || aop->size <= 1)
1433     return;
1434
1435   switch (aop->type)
1436     {
1437     case AOP_R0:
1438     case AOP_R1:
1439       while (aop->coff--)
1440         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1441       break;
1442     case AOP_DPTR:
1443       while (aop->coff--)
1444         {
1445           emitcode ("lcall", "__decdptr");
1446         }
1447       break;
1448     }
1449   aop->coff = 0;
1450 }
1451
1452 #define AOP(op) op->aop
1453 #define AOP_TYPE(op) AOP(op)->type
1454 #define AOP_SIZE(op) AOP(op)->size
1455 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1456                        AOP_TYPE(x) == AOP_R0))
1457
1458 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1459                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
1460
1461 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1462                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
1463                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
1464
1465
1466 /*-----------------------------------------------------------------*/
1467 /* opIsGptr: returns non-zero if the passed operand is       */
1468 /* a generic pointer type.             */
1469 /*-----------------------------------------------------------------*/
1470 static int
1471 opIsGptr (operand * op)
1472 {
1473   sym_link *type = operandType (op);
1474
1475   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1476     {
1477       return 1;
1478     }
1479   return 0;
1480 }
1481
1482 /*-----------------------------------------------------------------*/
1483 /* getDataSize - get the operand data size                         */
1484 /*-----------------------------------------------------------------*/
1485 static int
1486 getDataSize (operand * op)
1487 {
1488   int size;
1489   size = AOP_SIZE (op);
1490   if (size == GPTRSIZE)
1491     {
1492       sym_link *type = operandType (op);
1493       if (IS_GENPTR (type))
1494         {
1495           /* generic pointer; arithmetic operations
1496            * should ignore the high byte (pointer type).
1497            */
1498           size--;
1499         }
1500     }
1501   return size;
1502 }
1503
1504 /*-----------------------------------------------------------------*/
1505 /* outAcc - output Acc                                             */
1506 /*-----------------------------------------------------------------*/
1507 static void
1508 outAcc (operand * result)
1509 {
1510   int size, offset;
1511   size = getDataSize (result);
1512   if (size)
1513     {
1514       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
1515       size--;
1516       offset = 1;
1517       /* unsigned or positive */
1518       while (size--)
1519         {
1520           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
1521         }
1522     }
1523 }
1524
1525 /*-----------------------------------------------------------------*/
1526 /* outBitC - output a bit C                                        */
1527 /*-----------------------------------------------------------------*/
1528 static void
1529 outBitC (operand * result)
1530 {
1531   /* if the result is bit */
1532   if (AOP_TYPE (result) == AOP_CRY)
1533     aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
1534   else
1535     {
1536       emitcode ("clr", "a");
1537       emitcode ("rlc", "a");
1538       outAcc (result);
1539     }
1540 }
1541
1542 /*-----------------------------------------------------------------*/
1543 /* toBoolean - emit code for orl a,operator(sizeop)                */
1544 /*-----------------------------------------------------------------*/
1545 static void
1546 toBoolean (operand * oper)
1547 {
1548   int size = AOP_SIZE (oper) - 1;
1549   int offset = 1;
1550   MOVA (aopGet (AOP (oper), 0, FALSE, FALSE));
1551   while (size--)
1552     emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE));
1553 }
1554
1555
1556 /*-----------------------------------------------------------------*/
1557 /* genNot - generate code for ! operation                          */
1558 /*-----------------------------------------------------------------*/
1559 static void
1560 genNot (iCode * ic)
1561 {
1562   symbol *tlbl;
1563
1564   D(emitcode (";     genNot",""));
1565
1566   /* assign asmOps to operand & result */
1567   aopOp (IC_LEFT (ic), ic, FALSE);
1568   aopOp (IC_RESULT (ic), ic, TRUE);
1569
1570   /* if in bit space then a special case */
1571   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1572     {
1573       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1574       emitcode ("cpl", "c");
1575       outBitC (IC_RESULT (ic));
1576       goto release;
1577     }
1578
1579   toBoolean (IC_LEFT (ic));
1580
1581   tlbl = newiTempLabel (NULL);
1582   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1583   emitcode ("", "%05d$:", tlbl->key + 100);
1584   outBitC (IC_RESULT (ic));
1585
1586 release:
1587   /* release the aops */
1588   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1589   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1590 }
1591
1592
1593 /*-----------------------------------------------------------------*/
1594 /* genCpl - generate code for complement                           */
1595 /*-----------------------------------------------------------------*/
1596 static void
1597 genCpl (iCode * ic)
1598 {
1599   int offset = 0;
1600   int size;
1601   symbol *tlbl;
1602
1603   D(emitcode (";     genCpl",""));
1604
1605   /* assign asmOps to operand & result */
1606   aopOp (IC_LEFT (ic), ic, FALSE);
1607   aopOp (IC_RESULT (ic), ic, TRUE);
1608
1609   /* special case if in bit space */
1610   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1611     {
1612       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1613         {
1614           /* promotion rules are responsible for this strange result: */
1615           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1616           goto release;
1617         }
1618
1619       tlbl=newiTempLabel(NULL);
1620       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC ||
1621           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1622           IS_AOP_PREG (IC_LEFT (ic)))
1623         {
1624           emitcode ("cjne", "%s,#0x01,%05d$",
1625                     aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE),
1626                     tlbl->key + 100);
1627         }
1628       else
1629         {
1630           char *l = aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE);
1631           MOVA (l);
1632           emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1633         }
1634       emitcode ("", "%05d$:", tlbl->key + 100);
1635       outBitC (IC_RESULT(ic));
1636       goto release;
1637     }
1638
1639   size = AOP_SIZE (IC_RESULT (ic));
1640   while (size--)
1641     {
1642       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1643       MOVA (l);
1644       emitcode ("cpl", "a");
1645       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1646     }
1647
1648
1649 release:
1650   /* release the aops */
1651   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1652   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1653 }
1654
1655 /*-----------------------------------------------------------------*/
1656 /* genUminusFloat - unary minus for floating points                */
1657 /*-----------------------------------------------------------------*/
1658 static void
1659 genUminusFloat (operand * op, operand * result)
1660 {
1661   int size, offset = 0;
1662   char *l;
1663
1664   D(emitcode (";     genUminusFloat",""));
1665
1666   /* for this we just copy and then flip the bit */
1667
1668   size = AOP_SIZE (op) - 1;
1669
1670   while (size--)
1671     {
1672       aopPut (AOP (result),
1673               aopGet (AOP (op), offset, FALSE, FALSE),
1674               offset,
1675               isOperandVolatile (result, FALSE));
1676       offset++;
1677     }
1678
1679   l = aopGet (AOP (op), offset, FALSE, FALSE);
1680
1681   MOVA (l);
1682
1683   emitcode ("cpl", "acc.7");
1684   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
1685 }
1686
1687 /*-----------------------------------------------------------------*/
1688 /* genUminus - unary minus code generation                         */
1689 /*-----------------------------------------------------------------*/
1690 static void
1691 genUminus (iCode * ic)
1692 {
1693   int offset, size;
1694   sym_link *optype, *rtype;
1695
1696
1697   D(emitcode (";     genUminus",""));
1698
1699   /* assign asmops */
1700   aopOp (IC_LEFT (ic), ic, FALSE);
1701   aopOp (IC_RESULT (ic), ic, TRUE);
1702
1703   /* if both in bit space then special
1704      case */
1705   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1706       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1707     {
1708
1709       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1710       emitcode ("cpl", "c");
1711       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1712       goto release;
1713     }
1714
1715   optype = operandType (IC_LEFT (ic));
1716   rtype = operandType (IC_RESULT (ic));
1717
1718   /* if float then do float stuff */
1719   if (IS_FLOAT (optype))
1720     {
1721       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1722       goto release;
1723     }
1724
1725   /* otherwise subtract from zero */
1726   size = AOP_SIZE (IC_LEFT (ic));
1727   offset = 0;
1728   //CLRC ;
1729   while (size--)
1730     {
1731       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE);
1732       if (!strcmp (l, "a"))
1733         {
1734           if (offset == 0)
1735             SETC;
1736           emitcode ("cpl", "a");
1737           emitcode ("addc", "a,#0");
1738         }
1739       else
1740         {
1741           if (offset == 0)
1742             CLRC;
1743           emitcode ("clr", "a");
1744           emitcode ("subb", "a,%s", l);
1745         }
1746       aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1747     }
1748
1749   /* if any remaining bytes in the result */
1750   /* we just need to propagate the sign   */
1751   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1752     {
1753       emitcode ("rlc", "a");
1754       emitcode ("subb", "a,acc");
1755       while (size--)
1756         aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1757     }
1758
1759 release:
1760   /* release the aops */
1761   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1762   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1763 }
1764
1765 /*-----------------------------------------------------------------*/
1766 /* saveRegisters - will look for a call and save the registers     */
1767 /*-----------------------------------------------------------------*/
1768 static void
1769 saveRegisters (iCode * lic)
1770 {
1771   int i;
1772   iCode *ic;
1773   bitVect *rsave;
1774
1775   /* look for call */
1776   for (ic = lic; ic; ic = ic->next)
1777     if (ic->op == CALL || ic->op == PCALL)
1778       break;
1779
1780   if (!ic)
1781     {
1782       fprintf (stderr, "found parameter push with no function call\n");
1783       return;
1784     }
1785
1786   /* if the registers have been saved already or don't need to be then
1787      do nothing */
1788   if (ic->regsSaved)
1789     return;
1790   if (IS_SYMOP(IC_LEFT(ic)) &&
1791       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
1792        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
1793     return;
1794
1795   /* safe the registers in use at this time but skip the
1796      ones for the result */
1797   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1798                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1799
1800   ic->regsSaved = 1;
1801   if (options.useXstack)
1802     {
1803       if (bitVectBitValue (rsave, R0_IDX))
1804         emitcode ("mov", "b,r0");
1805       emitcode ("mov", "r0,%s", spname);
1806       for (i = 0; i < mcs51_nRegs; i++)
1807         {
1808           if (bitVectBitValue (rsave, i))
1809             {
1810               if (i == R0_IDX)
1811                 emitcode ("mov", "a,b");
1812               else
1813                 emitcode ("mov", "a,%s", mcs51_regWithIdx (i)->name);
1814               emitcode ("movx", "@r0,a");
1815               emitcode ("inc", "r0");
1816             }
1817         }
1818       emitcode ("mov", "%s,r0", spname);
1819       if (bitVectBitValue (rsave, R0_IDX))
1820         emitcode ("mov", "r0,b");
1821     }
1822   else
1823     for (i = 0; i < mcs51_nRegs; i++)
1824       {
1825         if (bitVectBitValue (rsave, i))
1826           emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
1827       }
1828 }
1829
1830 /*-----------------------------------------------------------------*/
1831 /* unsaveRegisters - pop the pushed registers                      */
1832 /*-----------------------------------------------------------------*/
1833 static void
1834 unsaveRegisters (iCode * ic)
1835 {
1836   int i;
1837   bitVect *rsave;
1838
1839   /* restore the registers in use at this time but skip the
1840      ones for the result */
1841   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
1842                          mcs51_rUmaskForOp (IC_RESULT(ic)));
1843
1844   if (options.useXstack)
1845     {
1846       emitcode ("mov", "r0,%s", spname);
1847       for (i = mcs51_nRegs; i >= 0; i--)
1848         {
1849           if (bitVectBitValue (rsave, i))
1850             {
1851               emitcode ("dec", "r0");
1852               emitcode ("movx", "a,@r0");
1853               if (i == R0_IDX)
1854                 emitcode ("mov", "b,a");
1855               else
1856                 emitcode ("mov", "%s,a", mcs51_regWithIdx (i)->name);
1857             }
1858
1859         }
1860       emitcode ("mov", "%s,r0", spname);
1861       if (bitVectBitValue (rsave, R0_IDX))
1862         emitcode ("mov", "r0,b");
1863     }
1864   else
1865     for (i = mcs51_nRegs; i >= 0; i--)
1866       {
1867         if (bitVectBitValue (rsave, i))
1868           emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
1869       }
1870
1871 }
1872
1873
1874 /*-----------------------------------------------------------------*/
1875 /* pushSide -                */
1876 /*-----------------------------------------------------------------*/
1877 static void
1878 pushSide (operand * oper, int size)
1879 {
1880   int offset = 0;
1881   while (size--)
1882     {
1883       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE);
1884       if (AOP_TYPE (oper) != AOP_REG &&
1885           AOP_TYPE (oper) != AOP_DIR &&
1886           strcmp (l, "a"))
1887         {
1888           MOVA (l);
1889           emitcode ("push", "acc");
1890         }
1891       else
1892         emitcode ("push", "%s", l);
1893     }
1894 }
1895
1896 /*-----------------------------------------------------------------*/
1897 /* assignResultValue -               */
1898 /*-----------------------------------------------------------------*/
1899 static void
1900 assignResultValue (operand * oper)
1901 {
1902   int offset = 0;
1903   int size = AOP_SIZE (oper);
1904   while (size--)
1905     {
1906       aopPut (AOP (oper), fReturn[offset], offset, isOperandVolatile (oper, FALSE));
1907       offset++;
1908     }
1909 }
1910
1911
1912 /*-----------------------------------------------------------------*/
1913 /* genXpush - pushes onto the external stack                       */
1914 /*-----------------------------------------------------------------*/
1915 static void
1916 genXpush (iCode * ic)
1917 {
1918   asmop *aop = newAsmop (0);
1919   regs *r;
1920   int size, offset = 0;
1921
1922   D(emitcode (";     genXpush",""));
1923
1924   aopOp (IC_LEFT (ic), ic, FALSE);
1925   r = getFreePtr (ic, &aop, FALSE);
1926
1927
1928   emitcode ("mov", "%s,_spx", r->name);
1929
1930   size = AOP_SIZE (IC_LEFT (ic));
1931   while (size--)
1932     {
1933
1934       char *l = aopGet (AOP (IC_LEFT (ic)),
1935                         offset++, FALSE, FALSE);
1936       MOVA (l);
1937       emitcode ("movx", "@%s,a", r->name);
1938       emitcode ("inc", "%s", r->name);
1939
1940     }
1941
1942
1943   emitcode ("mov", "_spx,%s", r->name);
1944
1945   freeAsmop (NULL, aop, ic, TRUE);
1946   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
1947 }
1948
1949 /*-----------------------------------------------------------------*/
1950 /* genIpush - genrate code for pushing this gets a little complex  */
1951 /*-----------------------------------------------------------------*/
1952 static void
1953 genIpush (iCode * ic)
1954 {
1955   int size, offset = 0;
1956   char *l;
1957
1958   D(emitcode (";     genIpush",""));
1959
1960   /* if this is not a parm push : ie. it is spill push
1961      and spill push is always done on the local stack */
1962   if (!ic->parmPush)
1963     {
1964
1965       /* and the item is spilt then do nothing */
1966       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
1967         return;
1968
1969       aopOp (IC_LEFT (ic), ic, FALSE);
1970       size = AOP_SIZE (IC_LEFT (ic));
1971       /* push it on the stack */
1972       while (size--)
1973         {
1974           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
1975           if (*l == '#')
1976             {
1977               MOVA (l);
1978               l = "acc";
1979             }
1980           emitcode ("push", "%s", l);
1981         }
1982       return;
1983     }
1984
1985   /* this is a paramter push: in this case we call
1986      the routine to find the call and save those
1987      registers that need to be saved */
1988   saveRegisters (ic);
1989
1990   /* if use external stack then call the external
1991      stack pushing routine */
1992   if (options.useXstack)
1993     {
1994       genXpush (ic);
1995       return;
1996     }
1997
1998   /* then do the push */
1999   aopOp (IC_LEFT (ic), ic, FALSE);
2000
2001
2002   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2003   size = AOP_SIZE (IC_LEFT (ic));
2004
2005   while (size--)
2006     {
2007       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE);
2008       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2009           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2010           strcmp (l, "a"))
2011         {
2012           MOVA (l);
2013           emitcode ("push", "acc");
2014         }
2015       else
2016         emitcode ("push", "%s", l);
2017     }
2018
2019   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2020 }
2021
2022 /*-----------------------------------------------------------------*/
2023 /* genIpop - recover the registers: can happen only for spilling   */
2024 /*-----------------------------------------------------------------*/
2025 static void
2026 genIpop (iCode * ic)
2027 {
2028   int size, offset;
2029
2030   D(emitcode (";     genIpop",""));
2031
2032   /* if the temp was not pushed then */
2033   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2034     return;
2035
2036   aopOp (IC_LEFT (ic), ic, FALSE);
2037   size = AOP_SIZE (IC_LEFT (ic));
2038   offset = (size - 1);
2039   while (size--)
2040     emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2041                                    FALSE, TRUE));
2042
2043   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2044 }
2045
2046 /*-----------------------------------------------------------------*/
2047 /* unsaveRBank - restores the resgister bank from stack            */
2048 /*-----------------------------------------------------------------*/
2049 static void
2050 unsaveRBank (int bank, iCode * ic, bool popPsw)
2051 {
2052   int i;
2053   asmop *aop = NULL;
2054   regs *r = NULL;
2055
2056   if (options.useXstack)
2057   {
2058       if (!ic)
2059       {
2060           /* Assume r0 is available for use. */
2061           r = mcs51_regWithIdx (R0_IDX);;
2062       }
2063       else
2064       {
2065           aop = newAsmop (0);
2066           r = getFreePtr (ic, &aop, FALSE);
2067       }
2068       emitcode ("mov", "%s,_spx", r->name);
2069   }
2070
2071   if (popPsw)
2072     {
2073       if (options.useXstack)
2074       {
2075           emitcode ("movx", "a,@%s", r->name);
2076           emitcode ("mov", "psw,a");
2077           emitcode ("dec", "%s", r->name);
2078         }
2079       else
2080       {
2081         emitcode ("pop", "psw");
2082       }
2083     }
2084
2085   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2086     {
2087       if (options.useXstack)
2088         {
2089           emitcode ("movx", "a,@%s", r->name);
2090           emitcode ("mov", "(%s+%d),a",
2091                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2092           emitcode ("dec", "%s", r->name);
2093
2094         }
2095       else
2096         emitcode ("pop", "(%s+%d)",
2097                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2098     }
2099
2100   if (options.useXstack)
2101     {
2102       emitcode ("mov", "_spx,%s", r->name);
2103     }
2104
2105   if (aop)
2106   {
2107       freeAsmop (NULL, aop, ic, TRUE);
2108   }
2109 }
2110
2111 /*-----------------------------------------------------------------*/
2112 /* saveRBank - saves an entire register bank on the stack          */
2113 /*-----------------------------------------------------------------*/
2114 static void
2115 saveRBank (int bank, iCode * ic, bool pushPsw)
2116 {
2117   int i;
2118   asmop *aop = NULL;
2119   regs *r = NULL;
2120
2121   if (options.useXstack)
2122     {
2123       if (!ic)
2124       {
2125           /* Assume r0 is available for use. */
2126           r = mcs51_regWithIdx (R0_IDX);;
2127       }
2128       else
2129       {
2130           aop = newAsmop (0);
2131           r = getFreePtr (ic, &aop, FALSE);
2132       }
2133       emitcode ("mov", "%s,_spx", r->name);
2134     }
2135
2136   for (i = 0; i < mcs51_nRegs; i++)
2137     {
2138       if (options.useXstack)
2139         {
2140           emitcode ("inc", "%s", r->name);
2141           emitcode ("mov", "a,(%s+%d)",
2142                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2143           emitcode ("movx", "@%s,a", r->name);
2144         }
2145       else
2146         emitcode ("push", "(%s+%d)",
2147                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2148     }
2149
2150   if (pushPsw)
2151     {
2152       if (options.useXstack)
2153         {
2154           emitcode ("mov", "a,psw");
2155           emitcode ("movx", "@%s,a", r->name);
2156           emitcode ("inc", "%s", r->name);
2157           emitcode ("mov", "_spx,%s", r->name);
2158
2159         }
2160       else
2161       {
2162         emitcode ("push", "psw");
2163       }
2164
2165       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2166     }
2167
2168     if (aop)
2169     {
2170         freeAsmop (NULL, aop, ic, TRUE);
2171     }
2172
2173   if (ic)
2174   {
2175       ic->bankSaved = 1;
2176   }
2177 }
2178
2179 /*-----------------------------------------------------------------*/
2180 /* genSend - gen code for SEND                                     */
2181 /*-----------------------------------------------------------------*/
2182 static void genSend(set *sendSet)
2183 {
2184     iCode *sic;
2185     int rb1_count = 0 ;
2186
2187     for (sic = setFirstItem (_G.sendSet); sic;
2188          sic = setNextItem (_G.sendSet)) {
2189           int size, offset = 0;
2190           aopOp (IC_LEFT (sic), sic, FALSE);
2191           size = AOP_SIZE (IC_LEFT (sic));
2192
2193           if (sic->argreg == 1) {
2194               while (size--) {
2195                   char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2196                                     FALSE, FALSE);
2197                   if (strcmp (l, fReturn[offset]))
2198                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2199                   offset++;
2200               }
2201               rb1_count = 0;
2202           } else {
2203               while (size--) {
2204                   emitcode ("mov","b1_%d,%s",rb1_count++,
2205                             aopGet (AOP (IC_LEFT (sic)), offset++,FALSE, FALSE));
2206               }
2207           }
2208           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2209     }
2210 }
2211
2212 /*-----------------------------------------------------------------*/
2213 /* genCall - generates a call statement                            */
2214 /*-----------------------------------------------------------------*/
2215 static void
2216 genCall (iCode * ic)
2217 {
2218   sym_link *dtype;
2219 //  bool restoreBank = FALSE;
2220   bool swapBanks = FALSE;
2221
2222   D(emitcode(";     genCall",""));
2223
2224   dtype = operandType (IC_LEFT (ic));
2225   /* if send set is not empty the assign */
2226   if (_G.sendSet)
2227     {
2228         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2229             genSend(reverseSet(_G.sendSet));
2230         } else {
2231             genSend(_G.sendSet);
2232         }
2233
2234       _G.sendSet = NULL;
2235     }
2236
2237   /* if we are calling a not _naked function that is not using
2238      the same register bank then we need to save the
2239      destination registers on the stack */
2240   dtype = operandType (IC_LEFT (ic));
2241   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2242       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2243        !IFFUNC_ISISR (dtype))
2244   {
2245       swapBanks = TRUE;
2246   }
2247
2248   /* if caller saves & we have not saved then */
2249   if (!ic->regsSaved)
2250       saveRegisters (ic);
2251
2252   if (swapBanks)
2253   {
2254         emitcode ("mov", "psw,#0x%02x",
2255            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2256   }
2257
2258   /* make the call */
2259   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2260                             OP_SYMBOL (IC_LEFT (ic))->rname :
2261                             OP_SYMBOL (IC_LEFT (ic))->name));
2262
2263   if (swapBanks)
2264   {
2265        emitcode ("mov", "psw,#0x%02x",
2266           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2267   }
2268
2269   /* if we need assign a result value */
2270   if ((IS_ITEMP (IC_RESULT (ic)) &&
2271        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2272         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2273         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2274       IS_TRUE_SYMOP (IC_RESULT (ic)))
2275     {
2276
2277       _G.accInUse++;
2278       aopOp (IC_RESULT (ic), ic, FALSE);
2279       _G.accInUse--;
2280
2281       assignResultValue (IC_RESULT (ic));
2282
2283       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2284     }
2285
2286   /* adjust the stack for parameters if
2287      required */
2288   if (ic->parmBytes)
2289     {
2290       int i;
2291       if (ic->parmBytes > 3)
2292         {
2293           emitcode ("mov", "a,%s", spname);
2294           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2295           emitcode ("mov", "%s,a", spname);
2296         }
2297       else
2298         for (i = 0; i < ic->parmBytes; i++)
2299           emitcode ("dec", "%s", spname);
2300     }
2301
2302   /* if we hade saved some registers then unsave them */
2303   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2304     unsaveRegisters (ic);
2305
2306 //  /* if register bank was saved then pop them */
2307 //  if (restoreBank)
2308 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2309 }
2310
2311 /*-----------------------------------------------------------------*/
2312 /* -10l - generates a call by pointer statement                */
2313 /*-----------------------------------------------------------------*/
2314 static void
2315 genPcall (iCode * ic)
2316 {
2317   sym_link *dtype;
2318   symbol *rlbl = newiTempLabel (NULL);
2319 //  bool restoreBank=FALSE;
2320   bool swapBanks = FALSE;
2321
2322   D(emitcode(";     genPCall",""));
2323
2324   /* if caller saves & we have not saved then */
2325   if (!ic->regsSaved)
2326     saveRegisters (ic);
2327
2328   /* if we are calling a not _naked function that is not using
2329      the same register bank then we need to save the
2330      destination registers on the stack */
2331   dtype = operandType (IC_LEFT (ic))->next;
2332   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2333       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2334       !IFFUNC_ISISR (dtype))
2335   {
2336 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2337 //    restoreBank=TRUE;
2338       swapBanks = TRUE;
2339       // need caution message to user here
2340   }
2341
2342   /* push the return address on to the stack */
2343   emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2344   emitcode ("push", "acc");
2345   emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2346   emitcode ("push", "acc");
2347
2348   /* now push the calling address */
2349   aopOp (IC_LEFT (ic), ic, FALSE);
2350
2351   pushSide (IC_LEFT (ic), FPTRSIZE);
2352
2353   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2354
2355   /* if send set is not empty the assign */
2356   if (_G.sendSet)
2357     {
2358         genSend(reverseSet(_G.sendSet));
2359         _G.sendSet = NULL;
2360     }
2361
2362   if (swapBanks)
2363   {
2364         emitcode ("mov", "psw,#0x%02x",
2365            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2366   }
2367
2368   /* make the call */
2369   emitcode ("ret", "");
2370   emitcode ("", "%05d$:", (rlbl->key + 100));
2371
2372
2373   if (swapBanks)
2374   {
2375        emitcode ("mov", "psw,#0x%02x",
2376           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2377   }
2378
2379   /* if we need assign a result value */
2380   if ((IS_ITEMP (IC_RESULT (ic)) &&
2381        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2382         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2383       IS_TRUE_SYMOP (IC_RESULT (ic)))
2384     {
2385
2386       _G.accInUse++;
2387       aopOp (IC_RESULT (ic), ic, FALSE);
2388       _G.accInUse--;
2389
2390       assignResultValue (IC_RESULT (ic));
2391
2392       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2393     }
2394
2395   /* adjust the stack for parameters if
2396      required */
2397   if (ic->parmBytes)
2398     {
2399       int i;
2400       if (ic->parmBytes > 3)
2401         {
2402           emitcode ("mov", "a,%s", spname);
2403           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2404           emitcode ("mov", "%s,a", spname);
2405         }
2406       else
2407         for (i = 0; i < ic->parmBytes; i++)
2408           emitcode ("dec", "%s", spname);
2409
2410     }
2411
2412 //  /* if register bank was saved then unsave them */
2413 //  if (restoreBank)
2414 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2415
2416   /* if we hade saved some registers then
2417      unsave them */
2418   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2419     unsaveRegisters (ic);
2420 }
2421
2422 /*-----------------------------------------------------------------*/
2423 /* resultRemat - result  is rematerializable                       */
2424 /*-----------------------------------------------------------------*/
2425 static int
2426 resultRemat (iCode * ic)
2427 {
2428   if (SKIP_IC (ic) || ic->op == IFX)
2429     return 0;
2430
2431   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2432     {
2433       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2434       if (sym->remat && !POINTER_SET (ic))
2435         return 1;
2436     }
2437
2438   return 0;
2439 }
2440
2441 #if defined(__BORLANDC__) || defined(_MSC_VER)
2442 #define STRCASECMP stricmp
2443 #else
2444 #define STRCASECMP strcasecmp
2445 #endif
2446
2447 /*-----------------------------------------------------------------*/
2448 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2449 /*-----------------------------------------------------------------*/
2450 static int
2451 regsCmp(void *p1, void *p2)
2452 {
2453   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2454 }
2455
2456 static bool
2457 inExcludeList (char *s)
2458 {
2459   const char *p = setFirstItem(options.excludeRegsSet);
2460
2461   if (p == NULL || STRCASECMP(p, "none") == 0)
2462     return FALSE;
2463
2464
2465   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2466 }
2467
2468 /*-----------------------------------------------------------------*/
2469 /* genFunction - generated code for function entry                 */
2470 /*-----------------------------------------------------------------*/
2471 static void
2472 genFunction (iCode * ic)
2473 {
2474   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2475   sym_link *ftype;
2476   bool   switchedPSW = FALSE;
2477   int calleesaves_saved_register = -1;
2478   int stackAdjust = sym->stack;
2479   int accIsFree = sym->recvSize < 4;
2480   iCode * ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
2481
2482   _G.nRegsSaved = 0;
2483   /* create the function header */
2484   emitcode (";", "-----------------------------------------");
2485   emitcode (";", " function %s", sym->name);
2486   emitcode (";", "-----------------------------------------");
2487
2488   emitcode ("", "%s:", sym->rname);
2489   ftype = operandType (IC_LEFT (ic));
2490   _G.currentFunc = sym;
2491
2492   if (IFFUNC_ISNAKED(ftype))
2493   {
2494       emitcode(";", "naked function: no prologue.");
2495       return;
2496   }
2497   
2498   /* here we need to generate the equates for the
2499      register bank if required */
2500   if (FUNC_REGBANK (ftype) != rbank)
2501     {
2502       int i;
2503
2504       rbank = FUNC_REGBANK (ftype);
2505       for (i = 0; i < mcs51_nRegs; i++)
2506         {
2507           if (strcmp (regs8051[i].base, "0") == 0)
2508             emitcode ("", "%s = 0x%02x",
2509                       regs8051[i].dname,
2510                       8 * rbank + regs8051[i].offset);
2511           else
2512             emitcode ("", "%s = %s + 0x%02x",
2513                       regs8051[i].dname,
2514                       regs8051[i].base,
2515                       8 * rbank + regs8051[i].offset);
2516         }
2517     }
2518
2519   /* if this is an interrupt service routine then
2520      save acc, b, dpl, dph  */
2521   if (IFFUNC_ISISR (sym->type))
2522     {
2523
2524       if (!inExcludeList ("acc"))
2525         emitcode ("push", "acc");
2526       if (!inExcludeList ("b"))
2527         emitcode ("push", "b");
2528       if (!inExcludeList ("dpl"))
2529         emitcode ("push", "dpl");
2530       if (!inExcludeList ("dph"))
2531         emitcode ("push", "dph");
2532       /* if this isr has no bank i.e. is going to
2533          run with bank 0 , then we need to save more
2534          registers :-) */
2535       if (!FUNC_REGBANK (sym->type))
2536         {
2537
2538           /* if this function does not call any other
2539              function then we can be economical and
2540              save only those registers that are used */
2541           if (!IFFUNC_HASFCALL(sym->type))
2542             {
2543               int i;
2544
2545               /* if any registers used */
2546               if (sym->regsUsed)
2547                 {
2548                   /* save the registers used */
2549                   for (i = 0; i < sym->regsUsed->size; i++)
2550                     {
2551                       if (bitVectBitValue (sym->regsUsed, i))
2552                         emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2553                     }
2554                 }
2555             }
2556           else
2557             {
2558
2559               /* this function has a function call. We cannot
2560                  determines register usage so we will have to push the
2561                  entire bank */
2562                 saveRBank (0, ic, FALSE);
2563                 if (options.parms_in_bank1) {
2564                     int i;
2565                     for (i=0; i < 8 ; i++ ) {
2566                         emitcode ("push","%s",rb1regs[i]);
2567                     }
2568                 }
2569             }
2570         }
2571         else
2572         {
2573             /* This ISR uses a non-zero bank.
2574              *
2575              * We assume that the bank is available for our
2576              * exclusive use.
2577              *
2578              * However, if this ISR calls a function which uses some
2579              * other bank, we must save that bank entirely.
2580              */
2581             unsigned long banksToSave = 0;
2582
2583             if (IFFUNC_HASFCALL(sym->type))
2584             {
2585
2586 #define MAX_REGISTER_BANKS 4
2587
2588                 iCode *i;
2589                 int ix;
2590
2591                 for (i = ic; i; i = i->next)
2592                 {
2593                     if (i->op == ENDFUNCTION)
2594                     {
2595                         /* we got to the end OK. */
2596                         break;
2597                     }
2598
2599                     if (i->op == CALL)
2600                     {
2601                         sym_link *dtype;
2602
2603                         dtype = operandType (IC_LEFT(i));
2604                         if (dtype
2605                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
2606                         {
2607                              /* Mark this bank for saving. */
2608                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
2609                              {
2610                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
2611                              }
2612                              else
2613                              {
2614                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
2615                              }
2616
2617                              /* And note that we don't need to do it in
2618                               * genCall.
2619                               */
2620                              i->bankSaved = 1;
2621                         }
2622                     }
2623                     if (i->op == PCALL)
2624                     {
2625                         /* This is a mess; we have no idea what
2626                          * register bank the called function might
2627                          * use.
2628                          *
2629                          * The only thing I can think of to do is
2630                          * throw a warning and hope.
2631                          */
2632                         werror(W_FUNCPTR_IN_USING_ISR);
2633                     }
2634                 }
2635
2636                 if (banksToSave && options.useXstack)
2637                 {
2638                     /* Since we aren't passing it an ic,
2639                      * saveRBank will assume r0 is available to abuse.
2640                      *
2641                      * So switch to our (trashable) bank now, so
2642                      * the caller's R0 isn't trashed.
2643                      */
2644                     emitcode ("push", "psw");
2645                     emitcode ("mov", "psw,#0x%02x",
2646                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2647                     switchedPSW = TRUE;
2648                 }
2649
2650                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
2651                 {
2652                      if (banksToSave & (1 << ix))
2653                      {
2654                          saveRBank(ix, NULL, FALSE);
2655                      }
2656                 }
2657             }
2658             // TODO: this needs a closer look
2659             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
2660         }
2661       
2662       /* Set the register bank to the desired value if nothing else */
2663       /* has done so yet. */
2664       if (!switchedPSW)
2665         {
2666           emitcode ("push", "psw");
2667           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
2668         }
2669     }
2670   else
2671     {
2672       /* This is a non-ISR function. The caller has already switched register */
2673       /* banks, if necessary, so just handle the callee-saves option. */
2674       
2675       /* if callee-save to be used for this function
2676          then save the registers being used in this function */
2677       if (IFFUNC_CALLEESAVES(sym->type))
2678         {
2679           int i;
2680
2681           /* if any registers used */
2682           if (sym->regsUsed)
2683             {
2684               /* save the registers used */
2685               for (i = 0; i < sym->regsUsed->size; i++)
2686                 {
2687                   if (bitVectBitValue (sym->regsUsed, i))
2688                     {
2689                       /* remember one saved register for later usage */
2690                       if (calleesaves_saved_register < 0)
2691                         calleesaves_saved_register = i;
2692                       emitcode ("push", "%s", mcs51_regWithIdx (i)->dname);
2693                       _G.nRegsSaved++;
2694                     }
2695                 }
2696             }
2697         }
2698     }
2699
2700
2701   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2702     {
2703
2704       if (options.useXstack)
2705         {
2706           if (!accIsFree)
2707             emitcode ("push", "acc");
2708           emitcode ("mov", "r0,%s", spname);
2709           emitcode ("mov", "a,_bp");
2710           emitcode ("movx", "@r0,a");
2711           emitcode ("inc", "%s", spname);
2712           if (!accIsFree)
2713             emitcode ("pop", "acc");
2714         }
2715       else
2716         {
2717           /* set up the stack */
2718           emitcode ("push", "_bp");     /* save the callers stack  */
2719         }
2720       emitcode ("mov", "_bp,%s", spname);
2721     }
2722   
2723   /* For some cases it is worthwhile to perform a RECEIVE iCode */
2724   /* before setting up the stack frame completely. */
2725   if (ric && ric->argreg == 1 && IC_RESULT (ric))
2726     {
2727       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
2728       
2729       if (rsym->isitmp)
2730         {
2731           if (rsym && rsym->regType == REG_CND)
2732             rsym = NULL;
2733           if (rsym && (rsym->accuse || rsym->ruonly))
2734             rsym = NULL;
2735           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
2736             rsym = rsym->usl.spillLoc;
2737         }
2738       
2739       /* If the RECEIVE operand immediately spills to the first entry on the */
2740       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
2741       /* rather than the usual @r0/r1 machinations. */
2742       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
2743         {
2744           int ofs;
2745           
2746           _G.current_iCode = ric;
2747           D(emitcode (";     genReceive",""));
2748           for (ofs=0; ofs < sym->recvSize; ofs++)
2749             {
2750               if (!strcmp (fReturn[ofs], "a"))
2751                 emitcode ("push", "acc");
2752               else
2753                 emitcode ("push", fReturn[ofs]);
2754             }
2755           stackAdjust -= sym->recvSize;
2756           if (stackAdjust<0)
2757             {
2758               assert (stackAdjust>=0);
2759               stackAdjust = 0;
2760             }
2761           _G.current_iCode = ic;
2762           ric->generated = 1;
2763           accIsFree = 1;
2764         }
2765       /* If the RECEIVE operand is 4 registers, we can do the moves now */
2766       /* to free up the accumulator. */
2767       else if (rsym && rsym->nRegs && sym->recvSize == 4)
2768         {
2769           int ofs;
2770           
2771           _G.current_iCode = ric;
2772           D(emitcode (";     genReceive",""));
2773           for (ofs=0; ofs < sym->recvSize; ofs++)
2774             {
2775               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
2776             }
2777           _G.current_iCode = ic;
2778           ric->generated = 1;
2779           accIsFree = 1;
2780         }
2781     }
2782   
2783   /* adjust the stack for the function */
2784   if (stackAdjust)
2785     {
2786
2787       int i = stackAdjust;
2788       if (i > 256)
2789         werror (W_STACK_OVERFLOW, sym->name);
2790
2791       if (i > 3 && accIsFree)
2792         {
2793
2794           emitcode ("mov", "a,sp");
2795           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2796           emitcode ("mov", "sp,a");
2797
2798         }
2799       else if (i > 5)
2800         {
2801           /* The accumulator is not free, so we will need another register */
2802           /* to clobber. No need to worry about a possible conflict with */
2803           /* the above early RECEIVE optimizations since they would have */
2804           /* freed the accumulator if they were generated. */
2805           
2806           if (IFFUNC_CALLEESAVES(sym->type))
2807             {
2808               /* if it's a callee-saves function we need a saved register */
2809               if (calleesaves_saved_register >= 0)
2810                 {
2811                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2812                   emitcode ("mov", "a,sp");
2813                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2814                   emitcode ("mov", "sp,a");
2815                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
2816                 }
2817               else
2818                 /* do it the hard way */
2819                 while (i--)
2820                   emitcode ("inc", "sp");
2821             }
2822           else
2823             {
2824               /* not callee-saves, we can clobber r0 */
2825               emitcode ("mov", "r0,a");
2826               emitcode ("mov", "a,sp");
2827               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
2828               emitcode ("mov", "sp,a");
2829               emitcode ("mov", "a,r0");
2830             }
2831         }
2832       else
2833         while (i--)
2834           emitcode ("inc", "sp");
2835     }
2836
2837   if (sym->xstack)
2838     {
2839
2840       if (!accIsFree)
2841         emitcode ("push", "acc");
2842       emitcode ("mov", "a,_spx");
2843       emitcode ("add", "a,#0x%02x", ((char) sym->xstack & 0xff));
2844       emitcode ("mov", "_spx,a");
2845       if (!accIsFree)
2846         emitcode ("pop", "acc");
2847     }
2848
2849   /* if critical function then turn interrupts off */
2850   if (IFFUNC_ISCRITICAL (ftype))
2851     {
2852       symbol *tlbl = newiTempLabel (NULL);
2853       emitcode ("setb", "c");
2854       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
2855       emitcode ("clr", "c");
2856       emitcode ("", "%05d$:", (tlbl->key + 100));
2857       emitcode ("push", "psw"); /* save old ea via c in psw */
2858     }
2859 }
2860
2861 /*-----------------------------------------------------------------*/
2862 /* genEndFunction - generates epilogue for functions               */
2863 /*-----------------------------------------------------------------*/
2864 static void
2865 genEndFunction (iCode * ic)
2866 {
2867   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2868   lineNode *lnp = lineCurr;
2869   bitVect *regsUsed;
2870   bitVect *regsUsedPrologue;
2871   bitVect *regsUnneeded;
2872   int idx;
2873   
2874   _G.currentFunc = NULL;
2875   if (IFFUNC_ISNAKED(sym->type))
2876   {
2877       emitcode(";", "naked function: no epilogue.");
2878       if (options.debug && currFunc)
2879         debugFile->writeEndFunction (currFunc, ic, 0);
2880       return;
2881   }
2882
2883   if (IFFUNC_ISCRITICAL (sym->type))
2884     {
2885       emitcode ("pop", "psw"); /* restore ea via c in psw */
2886       emitcode ("mov", "ea,c");
2887     }
2888
2889   if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
2890     {
2891       emitcode ("mov", "%s,_bp", spname);
2892     }
2893
2894   /* if use external stack but some variables were
2895      added to the local stack then decrement the
2896      local stack */
2897   if (options.useXstack && sym->stack)
2898     {
2899       emitcode ("mov", "a,sp");
2900       emitcode ("add", "a,#0x%02x", ((char) -sym->stack) & 0xff);
2901       emitcode ("mov", "sp,a");
2902     }
2903
2904
2905   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
2906     {
2907       if (options.useXstack)
2908         {
2909           emitcode ("mov", "r0,%s", spname);
2910           emitcode ("movx", "a,@r0");
2911           emitcode ("mov", "_bp,a");
2912           emitcode ("dec", "%s", spname);
2913         }
2914       else
2915         {
2916           emitcode ("pop", "_bp");
2917         }
2918     }
2919
2920   /* restore the register bank  */
2921   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
2922   {
2923     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
2924      || !options.useXstack)
2925     {
2926         /* Special case of ISR using non-zero bank with useXstack
2927          * is handled below.
2928          */
2929         emitcode ("pop", "psw");
2930     }
2931   }
2932
2933   if (IFFUNC_ISISR (sym->type))
2934     {
2935
2936       /* now we need to restore the registers */
2937       /* if this isr has no bank i.e. is going to
2938          run with bank 0 , then we need to save more
2939          registers :-) */
2940       if (!FUNC_REGBANK (sym->type))
2941         {
2942           /* if this function does not call any other
2943              function then we can be economical and
2944              save only those registers that are used */
2945           if (!IFFUNC_HASFCALL(sym->type))
2946             {
2947               int i;
2948
2949               /* if any registers used */
2950               if (sym->regsUsed)
2951                 {
2952                   /* save the registers used */
2953                   for (i = sym->regsUsed->size; i >= 0; i--)
2954                     {
2955                       if (bitVectBitValue (sym->regsUsed, i))
2956                         emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
2957                     }
2958                 }
2959             }
2960           else
2961             {
2962               if (options.parms_in_bank1) {
2963                   int i;
2964                   for (i = 7 ; i >= 0 ; i-- ) {
2965                       emitcode ("pop","%s",rb1regs[i]);
2966                   }
2967               }
2968               /* this function has  a function call cannot
2969                  determines register usage so we will have to pop the
2970                  entire bank */
2971               unsaveRBank (0, ic, FALSE);
2972             }
2973         }
2974         else
2975         {
2976             /* This ISR uses a non-zero bank.
2977              *
2978              * Restore any register banks saved by genFunction
2979              * in reverse order.
2980              */
2981             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
2982             int ix;
2983
2984             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
2985             {
2986                 if (savedBanks & (1 << ix))
2987                 {
2988                     unsaveRBank(ix, NULL, FALSE);
2989                 }
2990             }
2991
2992             if (options.useXstack)
2993             {
2994                 /* Restore bank AFTER calling unsaveRBank,
2995                  * since it can trash r0.
2996                  */
2997                 emitcode ("pop", "psw");
2998             }
2999         }
3000
3001       if (!inExcludeList ("dph"))
3002         emitcode ("pop", "dph");
3003       if (!inExcludeList ("dpl"))
3004         emitcode ("pop", "dpl");
3005       if (!inExcludeList ("b"))
3006         emitcode ("pop", "b");
3007       if (!inExcludeList ("acc"))
3008         emitcode ("pop", "acc");
3009
3010       /* if debug then send end of function */
3011       if (options.debug && currFunc)
3012         {
3013           debugFile->writeEndFunction (currFunc, ic, 1);
3014         }
3015
3016       emitcode ("reti", "");
3017     }
3018   else
3019     {
3020       if (IFFUNC_CALLEESAVES(sym->type))
3021         {
3022           int i;
3023
3024           /* if any registers used */
3025           if (sym->regsUsed)
3026             {
3027               /* save the registers used */
3028               for (i = sym->regsUsed->size; i >= 0; i--)
3029                 {
3030                   if (bitVectBitValue (sym->regsUsed, i) ||
3031                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3032                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3033                 }
3034             }
3035           else if (mcs51_ptrRegReq)
3036             {
3037               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3038               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3039             }
3040
3041         }
3042
3043       /* if debug then send end of function */
3044       if (options.debug && currFunc)
3045         {
3046           debugFile->writeEndFunction (currFunc, ic, 1);
3047         }
3048
3049       emitcode ("ret", "");
3050     }
3051
3052   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3053     return;
3054   
3055   /* If this was an interrupt handler using bank 0 that called another */
3056   /* function, then all registers must be saved; nothing to optimized. */
3057   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3058       && !FUNC_REGBANK(sym->type))
3059     return;
3060
3061   /* There are no push/pops to optimize if not callee-saves or ISR */
3062   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3063     return;
3064   
3065   /* If there were stack parameters, we cannot optimize without also    */
3066   /* fixing all of the stack offsets; this is too dificult to consider. */
3067   if (FUNC_HASSTACKPARM(sym->type))
3068     return;
3069     
3070   /* Compute the registers actually used */
3071   regsUsed = newBitVect (mcs51_nRegs);
3072   regsUsedPrologue = newBitVect (mcs51_nRegs);
3073   while (lnp)
3074     {
3075       if (lnp->ic && lnp->ic->op == FUNCTION)
3076         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3077       else
3078         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3079       
3080       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3081           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3082         break;
3083       if (!lnp->prev)
3084         break;
3085       lnp = lnp->prev;
3086     }
3087
3088   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3089       && !bitVectBitValue (regsUsed, CND_IDX))
3090     {
3091       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3092       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3093           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3094         bitVectUnSetBit (regsUsed, CND_IDX);
3095     }
3096   else
3097     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3098     
3099   /* If this was an interrupt handler that called another function */
3100   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3101   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3102     {
3103       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3104       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3105       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3106       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3107       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3108     }
3109
3110   /* Remove the unneeded push/pops */
3111   regsUnneeded = newBitVect (mcs51_nRegs);
3112   while (lnp)
3113     {
3114       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3115         {
3116           if (!strncmp(lnp->line, "push", 4))
3117             {
3118               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3119               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3120                 {
3121                   connectLine (lnp->prev, lnp->next);
3122                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3123                 }
3124             }
3125           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3126             {
3127               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3128               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3129                 {
3130                   connectLine (lnp->prev, lnp->next);
3131                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3132                 }
3133             }
3134         }
3135       lnp = lnp->next;
3136     }  
3137   
3138   for (idx = 0; idx < regsUnneeded->size; idx++)
3139     if (bitVectBitValue (regsUnneeded, idx))
3140       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3141   
3142   freeBitVect (regsUnneeded);
3143   freeBitVect (regsUsed);
3144   freeBitVect (regsUsedPrologue);
3145 }
3146
3147 /*-----------------------------------------------------------------*/
3148 /* genRet - generate code for return statement                     */
3149 /*-----------------------------------------------------------------*/
3150 static void
3151 genRet (iCode * ic)
3152 {
3153   int size, offset = 0, pushed = 0;
3154
3155   D(emitcode (";     genRet",""));
3156
3157   /* if we have no return value then
3158      just generate the "ret" */
3159   if (!IC_LEFT (ic))
3160     goto jumpret;
3161
3162   /* we have something to return then
3163      move the return value into place */
3164   aopOp (IC_LEFT (ic), ic, FALSE);
3165   size = AOP_SIZE (IC_LEFT (ic));
3166
3167   while (size--)
3168     {
3169       char *l;
3170       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3171         {
3172           /* #NOCHANGE */
3173           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3174                       FALSE, TRUE);
3175           emitcode ("push", "%s", l);
3176           pushed++;
3177         }
3178       else
3179         {
3180           l = aopGet (AOP (IC_LEFT (ic)), offset,
3181                       FALSE, FALSE);
3182           if (strcmp (fReturn[offset], l))
3183             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3184         }
3185     }
3186
3187   if (pushed)
3188     {
3189       while (pushed)
3190         {
3191           pushed--;
3192           if (strcmp (fReturn[pushed], "a"))
3193             emitcode ("pop", fReturn[pushed]);
3194           else
3195             emitcode ("pop", "acc");
3196         }
3197     }
3198   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3199
3200 jumpret:
3201   /* generate a jump to the return label
3202      if the next is not the return statement */
3203   if (!(ic->next && ic->next->op == LABEL &&
3204         IC_LABEL (ic->next) == returnLabel))
3205
3206     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3207
3208 }
3209
3210 /*-----------------------------------------------------------------*/
3211 /* genLabel - generates a label                                    */
3212 /*-----------------------------------------------------------------*/
3213 static void
3214 genLabel (iCode * ic)
3215 {
3216   /* special case never generate */
3217   if (IC_LABEL (ic) == entryLabel)
3218     return;
3219
3220   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3221 }
3222
3223 /*-----------------------------------------------------------------*/
3224 /* genGoto - generates a ljmp                                      */
3225 /*-----------------------------------------------------------------*/
3226 static void
3227 genGoto (iCode * ic)
3228 {
3229   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3230 }
3231
3232 /*-----------------------------------------------------------------*/
3233 /* findLabelBackwards: walks back through the iCode chain looking  */
3234 /* for the given label. Returns number of iCode instructions     */
3235 /* between that label and given ic.          */
3236 /* Returns zero if label not found.          */
3237 /*-----------------------------------------------------------------*/
3238 static int
3239 findLabelBackwards (iCode * ic, int key)
3240 {
3241   int count = 0;
3242
3243   while (ic->prev)
3244     {
3245       ic = ic->prev;
3246       count++;
3247
3248       /* If we have any pushes or pops, we cannot predict the distance.
3249          I don't like this at all, this should be dealt with in the
3250          back-end */
3251       if (ic->op == IPUSH || ic->op == IPOP) {
3252         return 0;
3253       }
3254
3255       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3256         {
3257           return count;
3258         }
3259     }
3260
3261   return 0;
3262 }
3263
3264 /*-----------------------------------------------------------------*/
3265 /* genPlusIncr :- does addition with increment if possible         */
3266 /*-----------------------------------------------------------------*/
3267 static bool
3268 genPlusIncr (iCode * ic)
3269 {
3270   unsigned int icount;
3271   unsigned int size = getDataSize (IC_RESULT (ic));
3272
3273   /* will try to generate an increment */
3274   /* if the right side is not a literal
3275      we cannot */
3276   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3277     return FALSE;
3278
3279   /* if the literal value of the right hand side
3280      is greater than 4 then it is not worth it */
3281   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3282     return FALSE;
3283
3284   D(emitcode (";     genPlusIncr",""));
3285
3286   /* if increment >=16 bits in register or direct space */
3287   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3288       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3289       (size > 1) &&
3290       (icount == 1))
3291     {
3292       symbol *tlbl;
3293       int emitTlbl;
3294       int labelRange;
3295
3296       /* If the next instruction is a goto and the goto target
3297        * is < 10 instructions previous to this, we can generate
3298        * jumps straight to that target.
3299        */
3300       if (ic->next && ic->next->op == GOTO
3301           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3302           && labelRange <= 10)
3303         {
3304           emitcode (";", "tail increment optimized");
3305           tlbl = IC_LABEL (ic->next);
3306           emitTlbl = 0;
3307         }
3308       else
3309         {
3310           tlbl = newiTempLabel (NULL);
3311           emitTlbl = 1;
3312         }
3313       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3314       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3315           IS_AOP_PREG (IC_RESULT (ic)))
3316         emitcode ("cjne", "%s,#0x00,%05d$",
3317                   aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3318                   tlbl->key + 100);
3319       else
3320         {
3321           emitcode ("clr", "a");
3322           emitcode ("cjne", "a,%s,%05d$",
3323                     aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE),
3324                     tlbl->key + 100);
3325         }
3326
3327       emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3328       if (size > 2)
3329         {
3330           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3331               IS_AOP_PREG (IC_RESULT (ic)))
3332             emitcode ("cjne", "%s,#0x00,%05d$",
3333                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3334                       tlbl->key + 100);
3335           else
3336             emitcode ("cjne", "a,%s,%05d$",
3337                       aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE),
3338                       tlbl->key + 100);
3339
3340           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3341         }
3342       if (size > 3)
3343         {
3344           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3345               IS_AOP_PREG (IC_RESULT (ic)))
3346             emitcode ("cjne", "%s,#0x00,%05d$",
3347                       aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3348                       tlbl->key + 100);
3349           else
3350             {
3351               emitcode ("cjne", "a,%s,%05d$",
3352                         aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE),
3353                         tlbl->key + 100);
3354             }
3355           emitcode ("inc", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3356         }
3357
3358       if (emitTlbl)
3359         {
3360           emitcode ("", "%05d$:", tlbl->key + 100);
3361         }
3362       return TRUE;
3363     }
3364
3365   /* if the sizes are greater than 1 then we cannot */
3366   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3367       AOP_SIZE (IC_LEFT (ic)) > 1)
3368     return FALSE;
3369
3370   /* we can if the aops of the left & result match or
3371      if they are in registers and the registers are the
3372      same */
3373   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3374     {
3375
3376       if (icount > 3)
3377         {
3378           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3379           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
3380           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3381         }
3382       else
3383         {
3384
3385           while (icount--)
3386             emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE));
3387         }
3388
3389       return TRUE;
3390     }
3391
3392   return FALSE;
3393 }
3394
3395 /*-----------------------------------------------------------------*/
3396 /* outBitAcc - output a bit in acc                                 */
3397 /*-----------------------------------------------------------------*/
3398 static void
3399 outBitAcc (operand * result)
3400 {
3401   symbol *tlbl = newiTempLabel (NULL);
3402   /* if the result is a bit */
3403   if (AOP_TYPE (result) == AOP_CRY)
3404     {
3405       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
3406     }
3407   else
3408     {
3409       emitcode ("jz", "%05d$", tlbl->key + 100);
3410       emitcode ("mov", "a,%s", one);
3411       emitcode ("", "%05d$:", tlbl->key + 100);
3412       outAcc (result);
3413     }
3414 }
3415
3416 /*-----------------------------------------------------------------*/
3417 /* genPlusBits - generates code for addition of two bits           */
3418 /*-----------------------------------------------------------------*/
3419 static void
3420 genPlusBits (iCode * ic)
3421 {
3422   D(emitcode (";     genPlusBits",""));
3423
3424   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3425     {
3426       symbol *lbl = newiTempLabel (NULL);
3427       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3428       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3429       emitcode ("cpl", "c");
3430       emitcode ("", "%05d$:", (lbl->key + 100));
3431       outBitC (IC_RESULT (ic));
3432     }
3433   else
3434     {
3435       emitcode ("clr", "a");
3436       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3437       emitcode ("rlc", "a");
3438       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3439       emitcode ("addc", "a,#0x00");
3440       outAcc (IC_RESULT (ic));
3441     }
3442 }
3443
3444 #if 0
3445 /* This is the original version of this code.
3446
3447  * This is being kept around for reference,
3448  * because I am not entirely sure I got it right...
3449  */
3450 static void
3451 adjustArithmeticResult (iCode * ic)
3452 {
3453   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3454       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3455       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3456     aopPut (AOP (IC_RESULT (ic)),
3457             aopGet (AOP (IC_LEFT (ic)), 2, FALSE, FALSE),
3458             2,
3459             isOperandVolatile (IC_RESULT (ic), FALSE));
3460
3461   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3462       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
3463       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3464     aopPut (AOP (IC_RESULT (ic)),
3465             aopGet (AOP (IC_RIGHT (ic)), 2, FALSE, FALSE),
3466             2,
3467             isOperandVolatile (IC_RESULT (ic), FALSE));
3468
3469   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3470       AOP_SIZE (IC_LEFT (ic)) < 3 &&
3471       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
3472       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3473       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3474     {
3475       char buffer[5];
3476       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3477       aopPut (AOP (IC_RESULT (ic)), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
3478     }
3479 }
3480 #else
3481 /* This is the pure and virtuous version of this code.
3482  * I'm pretty certain it's right, but not enough to toss the old
3483  * code just yet...
3484  */
3485 static void
3486 adjustArithmeticResult (iCode * ic)
3487 {
3488   if (opIsGptr (IC_RESULT (ic)) &&
3489       opIsGptr (IC_LEFT (ic)) &&
3490       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3491     {
3492       aopPut (AOP (IC_RESULT (ic)),
3493               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3494               GPTRSIZE - 1,
3495               isOperandVolatile (IC_RESULT (ic), FALSE));
3496     }
3497
3498   if (opIsGptr (IC_RESULT (ic)) &&
3499       opIsGptr (IC_RIGHT (ic)) &&
3500       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3501     {
3502       aopPut (AOP (IC_RESULT (ic)),
3503               aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE),
3504               GPTRSIZE - 1,
3505               isOperandVolatile (IC_RESULT (ic), FALSE));
3506     }
3507
3508   if (opIsGptr (IC_RESULT (ic)) &&
3509       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3510       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3511       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3512       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3513     {
3514       char buffer[5];
3515       sprintf (buffer, "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3516       aopPut (AOP (IC_RESULT (ic)), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3517     }
3518 }
3519 #endif
3520
3521 /*-----------------------------------------------------------------*/
3522 /* genPlus - generates code for addition                           */
3523 /*-----------------------------------------------------------------*/
3524 static void
3525 genPlus (iCode * ic)
3526 {
3527   int size, offset = 0;
3528   int skip_bytes = 0;
3529   char *add = "add";
3530   asmop *leftOp, *rightOp;
3531   operand * op;
3532
3533   /* special cases :- */
3534
3535   D(emitcode (";     genPlus",""));
3536
3537   aopOp (IC_LEFT (ic), ic, FALSE);
3538   aopOp (IC_RIGHT (ic), ic, FALSE);
3539   aopOp (IC_RESULT (ic), ic, TRUE);
3540
3541   /* if literal, literal on the right or
3542      if left requires ACC or right is already
3543      in ACC */
3544   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3545       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3546       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3547     {
3548       operand *t = IC_RIGHT (ic);
3549       IC_RIGHT (ic) = IC_LEFT (ic);
3550       IC_LEFT (ic) = t;
3551     }
3552
3553   /* if both left & right are in bit
3554      space */
3555   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3556       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3557     {
3558       genPlusBits (ic);
3559       goto release;
3560     }
3561
3562   /* if left in bit space & right literal */
3563   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3564       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3565     {
3566       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3567       /* if result in bit space */
3568       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3569         {
3570           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
3571             emitcode ("cpl", "c");
3572           outBitC (IC_RESULT (ic));
3573         }
3574       else
3575         {
3576           size = getDataSize (IC_RESULT (ic));
3577           while (size--)
3578             {
3579               MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE));
3580               emitcode ("addc", "a,#00");
3581               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3582             }
3583         }
3584       goto release;
3585     }
3586
3587   /* if I can do an increment instead
3588      of add then GOOD for ME */
3589   if (genPlusIncr (ic) == TRUE)
3590     goto release;
3591
3592   size = getDataSize (IC_RESULT (ic));
3593   leftOp = AOP(IC_LEFT(ic));
3594   rightOp = AOP(IC_RIGHT(ic));
3595   op=IC_LEFT(ic);
3596
3597   /* if this is an add for an array access
3598      at a 256 byte boundary */
3599   if ( 2 == size
3600        && AOP_TYPE (op) == AOP_IMMD
3601        && IS_SYMOP (op)
3602        && IS_SPEC (OP_SYM_ETYPE (op))
3603        && SPEC_ABSA (OP_SYM_ETYPE (op))
3604        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
3605      )
3606     {
3607       D(emitcode (";     genPlus aligned array",""));
3608       aopPut (AOP (IC_RESULT (ic)),
3609               aopGet (rightOp, 0, FALSE, FALSE),
3610               0,
3611               isOperandVolatile (IC_RESULT (ic), FALSE));
3612
3613       if( 1 == getDataSize (IC_RIGHT (ic)) )
3614         {
3615           aopPut (AOP (IC_RESULT (ic)),
3616                   aopGet (leftOp, 1, FALSE, FALSE),
3617                   1,
3618                   isOperandVolatile (IC_RESULT (ic), FALSE));
3619         }
3620       else
3621         {
3622           MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
3623           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
3624           aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
3625         }
3626       goto release;
3627     }
3628
3629   /* if the lower bytes of a literal are zero skip the addition */
3630   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
3631     {
3632        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
3633               (skip_bytes+1 < size))
3634          {
3635            skip_bytes++;
3636          }
3637        if (skip_bytes)
3638          D(emitcode (";     genPlus shortcut",""));
3639     }
3640
3641   while (size--)
3642     {
3643       if( offset >= skip_bytes )
3644         {
3645           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
3646             {
3647               emitcode("mov", "b,a");
3648               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
3649               emitcode("xch", "a,b");
3650               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3651               emitcode (add, "a,b");
3652             }
3653           else if (aopGetUsesAcc (leftOp, offset))
3654             {
3655               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
3656               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
3657             }
3658           else
3659             {
3660               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
3661               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
3662             }
3663           aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
3664           add = "addc";  /* further adds must propagate carry */
3665         }
3666       else
3667         {
3668           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
3669               isOperandVolatile (IC_RESULT (ic), FALSE))
3670             {
3671               /* just move */
3672               aopPut (AOP (IC_RESULT (ic)),
3673                       aopGet (leftOp, offset, FALSE, FALSE),
3674                       offset,
3675                       isOperandVolatile (IC_RESULT (ic), FALSE));
3676             }
3677         }
3678       offset++;
3679     }
3680
3681   adjustArithmeticResult (ic);
3682
3683 release:
3684   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3685   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3686   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3687 }
3688
3689 /*-----------------------------------------------------------------*/
3690 /* genMinusDec :- does subtraction with deccrement if possible     */
3691 /*-----------------------------------------------------------------*/
3692 static bool
3693 genMinusDec (iCode * ic)
3694 {
3695   unsigned int icount;
3696   unsigned int size = getDataSize (IC_RESULT (ic));
3697
3698   /* will try to generate an increment */
3699   /* if the right side is not a literal
3700      we cannot */
3701   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3702     return FALSE;
3703
3704   /* if the literal value of the right hand side
3705      is greater than 4 then it is not worth it */
3706   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3707     return FALSE;
3708
3709   D(emitcode (";     genMinusDec",""));
3710
3711   /* if decrement >=16 bits in register or direct space */
3712   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
3713       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3714       (size > 1) &&
3715       (icount == 1))
3716     {
3717       symbol *tlbl;
3718       int emitTlbl;
3719       int labelRange;
3720
3721       /* If the next instruction is a goto and the goto target
3722        * is <= 10 instructions previous to this, we can generate
3723        * jumps straight to that target.
3724        */
3725       if (ic->next && ic->next->op == GOTO
3726           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3727           && labelRange <= 10)
3728         {
3729           emitcode (";", "tail decrement optimized");
3730           tlbl = IC_LABEL (ic->next);
3731           emitTlbl = 0;
3732         }
3733       else
3734         {
3735           tlbl = newiTempLabel (NULL);
3736           emitTlbl = 1;
3737         }
3738
3739       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE));
3740       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3741           IS_AOP_PREG (IC_RESULT (ic)))
3742         emitcode ("cjne", "%s,#0xff,%05d$"
3743                   ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3744                   ,tlbl->key + 100);
3745       else
3746         {
3747           emitcode ("mov", "a,#0xff");
3748           emitcode ("cjne", "a,%s,%05d$"
3749                     ,aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE)
3750                     ,tlbl->key + 100);
3751         }
3752       emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE));
3753       if (size > 2)
3754         {
3755           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3756               IS_AOP_PREG (IC_RESULT (ic)))
3757             emitcode ("cjne", "%s,#0xff,%05d$"
3758                       ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3759                       ,tlbl->key + 100);
3760           else
3761             {
3762               emitcode ("cjne", "a,%s,%05d$"
3763                         ,aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE)
3764                         ,tlbl->key + 100);
3765             }
3766           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE));
3767         }
3768       if (size > 3)
3769         {
3770           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3771               IS_AOP_PREG (IC_RESULT (ic)))
3772             emitcode ("cjne", "%s,#0xff,%05d$"
3773                       ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3774                       ,tlbl->key + 100);
3775           else
3776             {
3777               emitcode ("cjne", "a,%s,%05d$"
3778                         ,aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE)
3779                         ,tlbl->key + 100);
3780             }
3781           emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE));
3782         }
3783       if (emitTlbl)
3784         {
3785           emitcode ("", "%05d$:", tlbl->key + 100);
3786         }
3787       return TRUE;
3788     }
3789
3790   /* if the sizes are greater than 1 then we cannot */
3791   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3792       AOP_SIZE (IC_LEFT (ic)) > 1)
3793     return FALSE;
3794
3795   /* we can if the aops of the left & result match or
3796      if they are in registers and the registers are the
3797      same */
3798   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3799     {
3800
3801       while (icount--)
3802         emitcode ("dec", "%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
3803
3804       return TRUE;
3805     }
3806
3807   return FALSE;
3808 }
3809
3810 /*-----------------------------------------------------------------*/
3811 /* addSign - complete with sign                                    */
3812 /*-----------------------------------------------------------------*/
3813 static void
3814 addSign (operand * result, int offset, int sign)
3815 {
3816   int size = (getDataSize (result) - offset);
3817   if (size > 0)
3818     {
3819       if (sign)
3820         {
3821           emitcode ("rlc", "a");
3822           emitcode ("subb", "a,acc");
3823           while (size--)
3824             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
3825         }
3826       else
3827         while (size--)
3828           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
3829     }
3830 }
3831
3832 /*-----------------------------------------------------------------*/
3833 /* genMinusBits - generates code for subtraction  of two bits      */
3834 /*-----------------------------------------------------------------*/
3835 static void
3836 genMinusBits (iCode * ic)
3837 {
3838   symbol *lbl = newiTempLabel (NULL);
3839
3840   D(emitcode (";     genMinusBits",""));
3841
3842   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3843     {
3844       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3845       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3846       emitcode ("cpl", "c");
3847       emitcode ("", "%05d$:", (lbl->key + 100));
3848       outBitC (IC_RESULT (ic));
3849     }
3850   else
3851     {
3852       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3853       emitcode ("subb", "a,acc");
3854       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
3855       emitcode ("inc", "a");
3856       emitcode ("", "%05d$:", (lbl->key + 100));
3857       aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
3858       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
3859     }
3860 }
3861
3862 /*-----------------------------------------------------------------*/
3863 /* genMinus - generates code for subtraction                       */
3864 /*-----------------------------------------------------------------*/
3865 static void
3866 genMinus (iCode * ic)
3867 {
3868   int size, offset = 0;
3869
3870   D(emitcode (";     genMinus",""));
3871
3872   aopOp (IC_LEFT (ic), ic, FALSE);
3873   aopOp (IC_RIGHT (ic), ic, FALSE);
3874   aopOp (IC_RESULT (ic), ic, TRUE);
3875
3876   /* special cases :- */
3877   /* if both left & right are in bit space */
3878   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3879       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3880     {
3881       genMinusBits (ic);
3882       goto release;
3883     }
3884
3885   /* if I can do an decrement instead
3886      of subtract then GOOD for ME */
3887   if (genMinusDec (ic) == TRUE)
3888     goto release;
3889
3890   size = getDataSize (IC_RESULT (ic));
3891
3892   /* if literal, add a,#-lit, else normal subb */
3893   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3894     {
3895       unsigned long lit = 0L;
3896
3897       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3898       lit = -(long) lit;
3899
3900       while (size--)
3901         {
3902           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE));
3903           /* first add without previous c */
3904           if (!offset) {
3905             if (!size && lit== (unsigned long) -1) {
3906               emitcode ("dec", "a");
3907             } else {
3908               emitcode ("add", "a,#0x%02x",
3909                         (unsigned int) (lit & 0x0FFL));
3910             }
3911           } else {
3912             emitcode ("addc", "a,#0x%02x",
3913                       (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3914           }
3915           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3916         }
3917     }
3918   else
3919     {
3920       asmop *leftOp, *rightOp;
3921
3922       leftOp = AOP(IC_LEFT(ic));
3923       rightOp = AOP(IC_RIGHT(ic));
3924
3925       while (size--)
3926         {
3927           if (aopGetUsesAcc(rightOp, offset)) {
3928             wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
3929             MOVA (aopGet(rightOp, offset, FALSE, TRUE));
3930             if (offset == 0) {
3931               emitcode( "setb", "c");
3932             }
3933             emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
3934             emitcode("cpl", "a");
3935           } else {
3936             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
3937             if (offset == 0)
3938               CLRC;
3939             emitcode ("subb", "a,%s",
3940                       aopGet(rightOp, offset, FALSE, TRUE));
3941           }
3942
3943           aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
3944         }
3945     }
3946
3947
3948   adjustArithmeticResult (ic);
3949
3950 release:
3951   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3952   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
3953   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3954 }
3955
3956
3957 /*-----------------------------------------------------------------*/
3958 /* genMultbits :- multiplication of bits                           */
3959 /*-----------------------------------------------------------------*/
3960 static void
3961 genMultbits (operand * left,
3962              operand * right,
3963              operand * result)
3964 {
3965   D(emitcode (";     genMultbits",""));
3966
3967   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
3968   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
3969   outBitC (result);
3970 }
3971
3972 /*-----------------------------------------------------------------*/
3973 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
3974 /*-----------------------------------------------------------------*/
3975 static void
3976 genMultOneByte (operand * left,
3977                 operand * right,
3978                 operand * result)
3979 {
3980   symbol *lbl;
3981   int size = AOP_SIZE (result);
3982   bool runtimeSign, compiletimeSign;
3983   bool lUnsigned, rUnsigned;
3984
3985   D(emitcode (";     genMultOneByte",""));
3986
3987   if (size < 1 || size > 2)
3988     {
3989       /* this should never happen */
3990       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
3991                AOP_SIZE(result), __FILE__, lineno);
3992       exit (1);
3993     }
3994
3995   /* (if two literals: the value is computed before) */
3996   /* if one literal, literal on the right */
3997   if (AOP_TYPE (left) == AOP_LIT)
3998     {
3999       operand *t = right;
4000       right = left;
4001       left = t;
4002       /* emitcode (";", "swapped left and right"); */
4003     }
4004   /* if no literal, unsigned on the right: shorter code */
4005   if (   AOP_TYPE (right) != AOP_LIT
4006       && SPEC_USIGN (getSpec (operandType (left))))
4007     {
4008       operand *t = right;
4009       right = left;
4010       left = t;
4011     }
4012
4013   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4014   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4015
4016   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4017                    no need to take care about the signedness! */
4018       || (lUnsigned && rUnsigned))
4019     {
4020       /* just an unsigned 8 * 8 = 8 multiply
4021          or 8u * 8u = 16u */
4022       /* emitcode (";","unsigned"); */
4023       /* TODO: check for accumulator clash between left & right aops? */
4024
4025       if (AOP_TYPE (right) == AOP_LIT)
4026         {
4027           /* moving to accumulator first helps peepholes */
4028           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4029           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4030         }
4031       else
4032         {
4033           emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4034           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4035         }
4036
4037       emitcode ("mul", "ab");
4038       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4039       if (size == 2)
4040         aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4041       return;
4042     }
4043
4044   /* we have to do a signed multiply */
4045   /* emitcode (";", "signed"); */
4046
4047   /* now sign adjust for both left & right */
4048
4049   /* let's see what's needed: */
4050   /* apply negative sign during runtime */
4051   runtimeSign = FALSE;
4052   /* negative sign from literals */
4053   compiletimeSign = FALSE;
4054
4055   if (!lUnsigned)
4056     {
4057       if (AOP_TYPE(left) == AOP_LIT)
4058         {
4059           /* signed literal */
4060           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4061           if (val < 0)
4062             compiletimeSign = TRUE;
4063         }
4064       else
4065         /* signed but not literal */
4066         runtimeSign = TRUE;
4067     }
4068
4069   if (!rUnsigned)
4070     {
4071       if (AOP_TYPE(right) == AOP_LIT)
4072         {
4073           /* signed literal */
4074           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4075           if (val < 0)
4076             compiletimeSign ^= TRUE;
4077         }
4078       else
4079         /* signed but not literal */
4080         runtimeSign = TRUE;
4081     }
4082
4083   /* initialize F0, which stores the runtime sign */
4084   if (runtimeSign)
4085     {
4086       if (compiletimeSign)
4087         emitcode ("setb", "F0"); /* set sign flag */
4088       else
4089         emitcode ("clr", "F0"); /* reset sign flag */
4090     }
4091
4092   /* save the signs of the operands */
4093   if (AOP_TYPE(right) == AOP_LIT)
4094     {
4095       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4096
4097       if (!rUnsigned && val < 0)
4098         emitcode ("mov", "b,#0x%02x", -val);
4099       else
4100         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4101     }
4102   else /* ! literal */
4103     {
4104       if (rUnsigned)  /* emitcode (";", "signed"); */
4105
4106         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4107       else
4108         {
4109           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4110           lbl = newiTempLabel (NULL);
4111           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4112           emitcode ("cpl", "F0"); /* complement sign flag */
4113           emitcode ("cpl", "a");  /* 2's complement */
4114           emitcode ("inc", "a");
4115           emitcode ("", "%05d$:", (lbl->key + 100));
4116           emitcode ("mov", "b,a");
4117         }
4118     }
4119
4120   if (AOP_TYPE(left) == AOP_LIT)
4121     {
4122       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4123
4124       if (!lUnsigned && val < 0)
4125         emitcode ("mov", "a,#0x%02x", -val);
4126       else
4127         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4128     }
4129   else /* ! literal */
4130     {
4131       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4132
4133       if (!lUnsigned)
4134         {
4135           lbl = newiTempLabel (NULL);
4136           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4137           emitcode ("cpl", "F0"); /* complement sign flag */
4138           emitcode ("cpl", "a"); /* 2's complement */
4139           emitcode ("inc", "a");
4140           emitcode ("", "%05d$:", (lbl->key + 100));
4141         }
4142     }
4143
4144   /* now the multiplication */
4145   emitcode ("mul", "ab");
4146   if (runtimeSign || compiletimeSign)
4147     {
4148       lbl = newiTempLabel (NULL);
4149       if (runtimeSign)
4150         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4151       emitcode ("cpl", "a"); /* lsb 2's complement */
4152       if (size != 2)
4153         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4154       else
4155         {
4156           emitcode ("add", "a,#1"); /* this sets carry flag */
4157           emitcode ("xch", "a,b");
4158           emitcode ("cpl", "a"); /* msb 2's complement */
4159           emitcode ("addc", "a,#0");
4160           emitcode ("xch", "a,b");
4161         }
4162       emitcode ("", "%05d$:", (lbl->key + 100));
4163     }
4164   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4165   if (size == 2)
4166     aopPut (AOP (result), "b", 1, isOperandVolatile (result, FALSE));
4167 }
4168
4169 /*-----------------------------------------------------------------*/
4170 /* genMult - generates code for multiplication                     */
4171 /*-----------------------------------------------------------------*/
4172 static void
4173 genMult (iCode * ic)
4174 {
4175   operand *left = IC_LEFT (ic);
4176   operand *right = IC_RIGHT (ic);
4177   operand *result = IC_RESULT (ic);
4178
4179   D(emitcode (";     genMult",""));
4180
4181   /* assign the amsops */
4182   aopOp (left, ic, FALSE);
4183   aopOp (right, ic, FALSE);
4184   aopOp (result, ic, TRUE);
4185
4186   /* special cases first */
4187   /* both are bits */
4188   if (AOP_TYPE (left) == AOP_CRY &&
4189       AOP_TYPE (right) == AOP_CRY)
4190     {
4191       genMultbits (left, right, result);
4192       goto release;
4193     }
4194
4195   /* if both are of size == 1 */
4196 #if 0 // one of them can be a sloc shared with the result
4197     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4198 #else
4199   if (getSize(operandType(left)) == 1 &&
4200       getSize(operandType(right)) == 1)
4201 #endif
4202     {
4203       genMultOneByte (left, right, result);
4204       goto release;
4205     }
4206
4207   /* should have been converted to function call */
4208     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4209              getSize(OP_SYMBOL(right)->type));
4210   assert (0);
4211
4212 release:
4213   freeAsmop (result, NULL, ic, TRUE);
4214   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4215   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4216 }
4217
4218 /*-----------------------------------------------------------------*/
4219 /* genDivbits :- division of bits                                  */
4220 /*-----------------------------------------------------------------*/
4221 static void
4222 genDivbits (operand * left,
4223             operand * right,
4224             operand * result)
4225 {
4226
4227   char *l;
4228
4229   D(emitcode (";     genDivbits",""));
4230
4231   /* the result must be bit */
4232   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4233   l = aopGet (AOP (left), 0, FALSE, FALSE);
4234
4235   MOVA (l);
4236
4237   emitcode ("div", "ab");
4238   emitcode ("rrc", "a");
4239   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4240 }
4241
4242 /*-----------------------------------------------------------------*/
4243 /* genDivOneByte : 8 bit division                                  */
4244 /*-----------------------------------------------------------------*/
4245 static void
4246 genDivOneByte (operand * left,
4247                operand * right,
4248                operand * result)
4249 {
4250   bool lUnsigned, rUnsigned;
4251   bool runtimeSign, compiletimeSign;
4252   symbol *lbl;
4253   int size, offset;
4254
4255   D(emitcode (";     genDivOneByte",""));
4256
4257   /* Why is it necessary that genDivOneByte() can return an int result?
4258      Have a look at:
4259      
4260         volatile unsigned char uc;
4261         volatile signed char sc1, sc2;
4262         volatile int i;
4263      
4264         uc  = 255;
4265         sc1 = -1;
4266         i = uc / sc1;
4267
4268      Or:
4269   
4270         sc1 = -128;
4271         sc2 = -1;
4272         i = sc1 / sc2;
4273
4274      In all cases a one byte result would overflow, the following cast to int
4275      would return the wrong result.
4276   
4277      Two possible solution:
4278         a) cast operands to int, if ((unsigned) / (signed)) or
4279            ((signed) / (signed))
4280         b) return an 16 bit signed int; this is what we're doing here!
4281   */
4282   
4283   size = AOP_SIZE (result) - 1;
4284   offset = 1;
4285   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4286   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4287
4288   /* signed or unsigned */
4289   if (lUnsigned && rUnsigned)
4290     {
4291       /* unsigned is easy */
4292       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4293       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4294       emitcode ("div", "ab");
4295       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4296       while (size--)
4297         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4298       return;
4299     }
4300   
4301   /* signed is a little bit more difficult */
4302
4303   /* now sign adjust for both left & right */
4304
4305   /* let's see what's needed: */
4306   /* apply negative sign during runtime */
4307   runtimeSign = FALSE;
4308   /* negative sign from literals */
4309   compiletimeSign = FALSE;
4310
4311   if (!lUnsigned)
4312     {
4313       if (AOP_TYPE(left) == AOP_LIT)
4314         {
4315           /* signed literal */
4316           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4317           if (val < 0)
4318             compiletimeSign = TRUE;
4319         }
4320       else
4321         /* signed but not literal */
4322         runtimeSign = TRUE;
4323     }
4324
4325   if (!rUnsigned)
4326     {
4327       if (AOP_TYPE(right) == AOP_LIT)
4328         {
4329           /* signed literal */
4330           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4331           if (val < 0)
4332             compiletimeSign ^= TRUE;
4333         }
4334       else
4335         /* signed but not literal */
4336         runtimeSign = TRUE;
4337     }
4338
4339   /* initialize F0, which stores the runtime sign */
4340   if (runtimeSign)
4341     {
4342       if (compiletimeSign)
4343         emitcode ("setb", "F0"); /* set sign flag */
4344       else
4345         emitcode ("clr", "F0"); /* reset sign flag */
4346     }
4347
4348   /* save the signs of the operands */
4349   if (AOP_TYPE(right) == AOP_LIT)
4350     {
4351       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4352
4353       if (!rUnsigned && val < 0)
4354         emitcode ("mov", "b,#0x%02x", -val);
4355       else
4356         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4357     }
4358   else /* ! literal */
4359     {
4360       if (rUnsigned)
4361         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4362       else
4363         {
4364           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4365           lbl = newiTempLabel (NULL);
4366           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4367           emitcode ("cpl", "F0"); /* complement sign flag */
4368           emitcode ("cpl", "a");  /* 2's complement */
4369           emitcode ("inc", "a");
4370           emitcode ("", "%05d$:", (lbl->key + 100));
4371           emitcode ("mov", "b,a");
4372         }
4373     }
4374
4375   if (AOP_TYPE(left) == AOP_LIT)
4376     {
4377       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4378
4379       if (!lUnsigned && val < 0)
4380         emitcode ("mov", "a,#0x%02x", -val);
4381       else
4382         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4383     }
4384   else /* ! literal */
4385     {
4386       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4387
4388       if (!lUnsigned)
4389         {
4390           lbl = newiTempLabel (NULL);
4391           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4392           emitcode ("cpl", "F0"); /* complement sign flag */
4393           emitcode ("cpl", "a");  /* 2's complement */
4394           emitcode ("inc", "a");
4395           emitcode ("", "%05d$:", (lbl->key + 100));
4396         }
4397     }
4398
4399   /* now the division */
4400   emitcode ("div", "ab");
4401
4402   if (runtimeSign || compiletimeSign)
4403     {
4404       lbl = newiTempLabel (NULL);
4405       if (runtimeSign)
4406         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4407       emitcode ("cpl", "a"); /* lsb 2's complement */
4408       emitcode ("inc", "a");
4409       emitcode ("", "%05d$:", (lbl->key + 100));
4410
4411       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4412       if (size > 0)
4413         {
4414           /* msb is 0x00 or 0xff depending on the sign */
4415           if (runtimeSign)
4416             {
4417               emitcode ("mov", "c,F0");
4418               emitcode ("subb", "a,acc");
4419               while (size--)
4420                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4421             }
4422           else /* compiletimeSign */
4423             while (size--)
4424               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4425         }
4426     }
4427   else
4428     {
4429       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4430       while (size--)
4431         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4432     }
4433 }
4434
4435 /*-----------------------------------------------------------------*/
4436 /* genDiv - generates code for division                            */
4437 /*-----------------------------------------------------------------*/
4438 static void
4439 genDiv (iCode * ic)
4440 {
4441   operand *left = IC_LEFT (ic);
4442   operand *right = IC_RIGHT (ic);
4443   operand *result = IC_RESULT (ic);
4444
4445   D(emitcode (";     genDiv",""));
4446
4447   /* assign the amsops */
4448   aopOp (left, ic, FALSE);
4449   aopOp (right, ic, FALSE);
4450   aopOp (result, ic, TRUE);
4451
4452   /* special cases first */
4453   /* both are bits */
4454   if (AOP_TYPE (left) == AOP_CRY &&
4455       AOP_TYPE (right) == AOP_CRY)
4456     {
4457       genDivbits (left, right, result);
4458       goto release;
4459     }
4460
4461   /* if both are of size == 1 */
4462   if (AOP_SIZE (left) == 1 &&
4463       AOP_SIZE (right) == 1)
4464     {
4465       genDivOneByte (left, right, result);
4466       goto release;
4467     }
4468
4469   /* should have been converted to function call */
4470   assert (0);
4471 release:
4472   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4473   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4474   freeAsmop (result, NULL, ic, TRUE);
4475 }
4476
4477 /*-----------------------------------------------------------------*/
4478 /* genModbits :- modulus of bits                                   */
4479 /*-----------------------------------------------------------------*/
4480 static void
4481 genModbits (operand * left,
4482             operand * right,
4483             operand * result)
4484 {
4485
4486   char *l;
4487
4488   D(emitcode (";     genModbits",""));
4489
4490   /* the result must be bit */
4491   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4492   l = aopGet (AOP (left), 0, FALSE, FALSE);
4493
4494   MOVA (l);
4495
4496   emitcode ("div", "ab");
4497   emitcode ("mov", "a,b");
4498   emitcode ("rrc", "a");
4499   aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
4500 }
4501
4502 /*-----------------------------------------------------------------*/
4503 /* genModOneByte : 8 bit modulus                                   */
4504 /*-----------------------------------------------------------------*/
4505 static void
4506 genModOneByte (operand * left,
4507                operand * right,
4508                operand * result)
4509 {
4510   bool lUnsigned, rUnsigned;
4511   bool runtimeSign, compiletimeSign;
4512   symbol *lbl;
4513   int size, offset;
4514
4515   D(emitcode (";     genModOneByte",""));
4516
4517   size = AOP_SIZE (result) - 1;
4518   offset = 1;
4519   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4520   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4521   
4522   /* signed or unsigned */
4523   if (lUnsigned && rUnsigned)
4524     {
4525       /* unsigned is easy */
4526       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4527       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4528       emitcode ("div", "ab");
4529       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4530       while (size--)
4531         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4532       return;
4533     }
4534
4535   /* signed is a little bit more difficult */
4536
4537   /* now sign adjust for both left & right */
4538
4539   /* modulus: sign of the right operand has no influence on the result! */
4540   if (AOP_TYPE(right) == AOP_LIT)
4541     {
4542       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4543
4544       if (!rUnsigned && val < 0)
4545         emitcode ("mov", "b,#0x%02x", -val);
4546       else
4547         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4548     }
4549   else /* not literal */
4550     {
4551       if (rUnsigned)
4552         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
4553       else
4554         {
4555           MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
4556           lbl = newiTempLabel (NULL);
4557           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4558           emitcode ("cpl", "a"); /* 2's complement */
4559           emitcode ("inc", "a");
4560           emitcode ("", "%05d$:", (lbl->key + 100));
4561           emitcode ("mov", "b,a");
4562         }
4563     }
4564
4565   /* let's see what's needed: */
4566   /* apply negative sign during runtime */
4567   runtimeSign = FALSE;
4568   /* negative sign from literals */
4569   compiletimeSign = FALSE;
4570   
4571   /* sign adjust left side */
4572   if (AOP_TYPE(left) == AOP_LIT)
4573     {
4574       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4575
4576       if (!lUnsigned && val < 0)
4577         {
4578           compiletimeSign = TRUE; /* set sign flag */
4579           emitcode ("mov", "a,#0x%02x", -val);
4580         }
4581       else
4582         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4583     }
4584   else /* ! literal */
4585     {
4586       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
4587
4588       if (!lUnsigned)
4589         {
4590           runtimeSign = TRUE;
4591           emitcode ("clr", "F0"); /* clear sign flag */
4592
4593           lbl = newiTempLabel (NULL);
4594           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4595           emitcode ("setb", "F0"); /* set sign flag */
4596           emitcode ("cpl", "a");   /* 2's complement */
4597           emitcode ("inc", "a");
4598           emitcode ("", "%05d$:", (lbl->key + 100));
4599         }
4600     }
4601
4602   /* now the modulus */
4603   emitcode ("div", "ab");
4604   
4605   if (runtimeSign || compiletimeSign)
4606     {
4607       emitcode ("mov", "a,b");
4608       lbl = newiTempLabel (NULL);
4609       if (runtimeSign)
4610         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4611       emitcode ("cpl", "a"); /* 2's complement */
4612       emitcode ("inc", "a");
4613       emitcode ("", "%05d$:", (lbl->key + 100));
4614      
4615       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
4616       if (size > 0)
4617         {
4618           /* msb is 0x00 or 0xff depending on the sign */
4619           if (runtimeSign)
4620             {
4621               emitcode ("mov", "c,F0");
4622               emitcode ("subb", "a,acc");
4623               while (size--)
4624                 aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
4625             }
4626           else /* compiletimeSign */
4627             while (size--)
4628               aopPut (AOP (result), "#0xff", offset++, isOperandVolatile (result, FALSE));
4629         }
4630     }
4631   else
4632     {
4633       aopPut (AOP (result), "b", 0, isOperandVolatile (result, FALSE));
4634       while (size--)
4635         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
4636     }
4637 }
4638
4639 /*-----------------------------------------------------------------*/
4640 /* genMod - generates code for division                            */
4641 /*-----------------------------------------------------------------*/
4642 static void
4643 genMod (iCode * ic)
4644 {
4645   operand *left = IC_LEFT (ic);
4646   operand *right = IC_RIGHT (ic);
4647   operand *result = IC_RESULT (ic);
4648
4649   D(emitcode (";     genMod",""));
4650
4651   /* assign the amsops */
4652   aopOp (left, ic, FALSE);
4653   aopOp (right, ic, FALSE);
4654   aopOp (result, ic, TRUE);
4655
4656   /* special cases first */
4657   /* both are bits */
4658   if (AOP_TYPE (left) == AOP_CRY &&
4659       AOP_TYPE (right) == AOP_CRY)
4660     {
4661       genModbits (left, right, result);
4662       goto release;
4663     }
4664
4665   /* if both are of size == 1 */
4666   if (AOP_SIZE (left) == 1 &&
4667       AOP_SIZE (right) == 1)
4668     {
4669       genModOneByte (left, right, result);
4670       goto release;
4671     }
4672
4673   /* should have been converted to function call */
4674   assert (0);
4675
4676 release:
4677   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4678   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4679   freeAsmop (result, NULL, ic, TRUE);
4680 }
4681
4682 /*-----------------------------------------------------------------*/
4683 /* genIfxJump :- will create a jump depending on the ifx           */
4684 /*-----------------------------------------------------------------*/
4685 static void
4686 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
4687 {
4688   symbol *jlbl;
4689   symbol *tlbl = newiTempLabel (NULL);
4690   char *inst;
4691
4692   D(emitcode (";     genIfxJump",""));
4693
4694   /* if true label then we jump if condition
4695      supplied is true */
4696   if (IC_TRUE (ic))
4697     {
4698       jlbl = IC_TRUE (ic);
4699       inst = ((strcmp (jval, "a") == 0 ? "jz" :
4700                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
4701     }
4702   else
4703     {
4704       /* false label is present */
4705       jlbl = IC_FALSE (ic);
4706       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
4707                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
4708     }
4709   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
4710     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
4711   else
4712     emitcode (inst, "%05d$", tlbl->key + 100);
4713   freeForBranchAsmop (result);
4714   freeForBranchAsmop (right);
4715   freeForBranchAsmop (left);
4716   emitcode ("ljmp", "%05d$", jlbl->key + 100);
4717   emitcode ("", "%05d$:", tlbl->key + 100);
4718
4719   /* mark the icode as generated */
4720   ic->generated = 1;
4721 }
4722
4723 /*-----------------------------------------------------------------*/
4724 /* genCmp :- greater or less than comparison                       */
4725 /*-----------------------------------------------------------------*/
4726 static void
4727 genCmp (operand * left, operand * right,
4728         operand * result, iCode * ifx, int sign, iCode *ic)
4729 {
4730   int size, offset = 0;
4731   unsigned long lit = 0L;
4732   bool rightInB;
4733
4734   D(emitcode (";     genCmp",""));
4735
4736   /* if left & right are bit variables */
4737   if (AOP_TYPE (left) == AOP_CRY &&
4738       AOP_TYPE (right) == AOP_CRY)
4739     {
4740       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
4741       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
4742     }
4743   else
4744     {
4745       /* subtract right from left if at the
4746          end the carry flag is set then we know that
4747          left is greater than right */
4748       size = max (AOP_SIZE (left), AOP_SIZE (right));
4749
4750       /* if unsigned char cmp with lit, do cjne left,#right,zz */
4751       if ((size == 1) && !sign &&
4752           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
4753         {
4754           symbol *lbl = newiTempLabel (NULL);
4755           emitcode ("cjne", "%s,%s,%05d$",
4756                     aopGet (AOP (left), offset, FALSE, FALSE),
4757                     aopGet (AOP (right), offset, FALSE, FALSE),
4758                     lbl->key + 100);
4759           emitcode ("", "%05d$:", lbl->key + 100);
4760         }
4761       else
4762         {
4763           if (AOP_TYPE (right) == AOP_LIT)
4764             {
4765               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4766               /* optimize if(x < 0) or if(x >= 0) */
4767               if (lit == 0L)
4768                 {
4769                   if (!sign)
4770                     {
4771                       CLRC;
4772                     }
4773                   else
4774                     {
4775                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
4776                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4777                         {
4778                           genIfxJump (ifx, "acc.7", left, right, result);
4779                           freeAsmop (right, NULL, ic, TRUE);
4780                           freeAsmop (left, NULL, ic, TRUE);
4781
4782                           return;
4783                         }
4784                       else
4785                         emitcode ("rlc", "a");
4786                     }
4787                   goto release;
4788                 }
4789             }
4790           CLRC;
4791           while (size--)
4792             {
4793               rightInB = aopGetUsesAcc(AOP (right), offset);
4794               if (rightInB)
4795                 emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4796               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4797               if (sign && size == 0)
4798                 {
4799                   emitcode ("xrl", "a,#0x80");
4800                   if (AOP_TYPE (right) == AOP_LIT)
4801                     {
4802                       unsigned long lit = (unsigned long)
4803                       floatFromVal (AOP (right)->aopu.aop_lit);
4804                       emitcode ("subb", "a,#0x%02x",
4805                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4806                     }
4807                   else
4808                     {
4809                       if (!rightInB)
4810                         emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4811                       emitcode ("xrl", "b,#0x80");
4812                       emitcode ("subb", "a,b");
4813                     }
4814                 }
4815               else
4816                 {
4817                   if (rightInB)
4818                     emitcode ("subb", "a,b");
4819                   else
4820                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4821                 }
4822               offset++;
4823             }
4824         }
4825     }
4826
4827 release:
4828   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4829   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4830   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4831     {
4832       outBitC (result);
4833     }
4834   else
4835     {
4836       /* if the result is used in the next
4837          ifx conditional branch then generate
4838          code a little differently */
4839       if (ifx)
4840         genIfxJump (ifx, "c", NULL, NULL, result);
4841       else
4842         outBitC (result);
4843       /* leave the result in acc */
4844     }
4845 }
4846
4847 /*-----------------------------------------------------------------*/
4848 /* genCmpGt :- greater than comparison                             */
4849 /*-----------------------------------------------------------------*/
4850 static void
4851 genCmpGt (iCode * ic, iCode * ifx)
4852 {
4853   operand *left, *right, *result;
4854   sym_link *letype, *retype;
4855   int sign;
4856
4857   D(emitcode (";     genCmpGt",""));
4858
4859   left = IC_LEFT (ic);
4860   right = IC_RIGHT (ic);
4861   result = IC_RESULT (ic);
4862
4863   letype = getSpec (operandType (left));
4864   retype = getSpec (operandType (right));
4865   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4866            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4867   /* assign the amsops */
4868   aopOp (left, ic, FALSE);
4869   aopOp (right, ic, FALSE);
4870   aopOp (result, ic, TRUE);
4871
4872   genCmp (right, left, result, ifx, sign,ic);
4873
4874   freeAsmop (result, NULL, ic, TRUE);
4875 }
4876
4877 /*-----------------------------------------------------------------*/
4878 /* genCmpLt - less than comparisons                                */
4879 /*-----------------------------------------------------------------*/
4880 static void
4881 genCmpLt (iCode * ic, iCode * ifx)
4882 {
4883   operand *left, *right, *result;
4884   sym_link *letype, *retype;
4885   int sign;
4886
4887   D(emitcode (";     genCmpLt",""));
4888
4889   left = IC_LEFT (ic);
4890   right = IC_RIGHT (ic);
4891   result = IC_RESULT (ic);
4892
4893   letype = getSpec (operandType (left));
4894   retype = getSpec (operandType (right));
4895   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4896            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4897   /* assign the amsops */
4898   aopOp (left, ic, FALSE);
4899   aopOp (right, ic, FALSE);
4900   aopOp (result, ic, TRUE);
4901
4902   genCmp (left, right, result, ifx, sign,ic);
4903
4904   freeAsmop (result, NULL, ic, TRUE);
4905 }
4906
4907 /*-----------------------------------------------------------------*/
4908 /* gencjneshort - compare and jump if not equal                    */
4909 /*-----------------------------------------------------------------*/
4910 static void
4911 gencjneshort (operand * left, operand * right, symbol * lbl)
4912 {
4913   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4914   int offset = 0;
4915   unsigned long lit = 0L;
4916
4917   /* if the left side is a literal or
4918      if the right is in a pointer register and left
4919      is not */
4920   if ((AOP_TYPE (left) == AOP_LIT) ||
4921       (AOP_TYPE (left) == AOP_IMMD) ||
4922       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
4923     {
4924       operand *t = right;
4925       right = left;
4926       left = t;
4927     }
4928
4929   if (AOP_TYPE (right) == AOP_LIT)
4930     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4931
4932   /* if the right side is a literal then anything goes */
4933   if (AOP_TYPE (right) == AOP_LIT &&
4934       AOP_TYPE (left) != AOP_DIR  &&
4935       AOP_TYPE (left) != AOP_IMMD)
4936     {
4937       while (size--)
4938         {
4939           emitcode ("cjne", "%s,%s,%05d$",
4940                     aopGet (AOP (left), offset, FALSE, FALSE),
4941                     aopGet (AOP (right), offset, FALSE, FALSE),
4942                     lbl->key + 100);
4943           offset++;
4944         }
4945     }
4946
4947   /* if the right side is in a register or in direct space or
4948      if the left is a pointer register & right is not */
4949   else if (AOP_TYPE (right) == AOP_REG ||
4950            AOP_TYPE (right) == AOP_DIR ||
4951            AOP_TYPE (right) == AOP_LIT ||
4952            AOP_TYPE (right) == AOP_IMMD ||
4953            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
4954            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
4955     {
4956       while (size--)
4957         {
4958           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4959           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4960               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4961             emitcode ("jnz", "%05d$", lbl->key + 100);
4962           else
4963             emitcode ("cjne", "a,%s,%05d$",
4964                       aopGet (AOP (right), offset, FALSE, TRUE),
4965                       lbl->key + 100);
4966           offset++;
4967         }
4968     }
4969   else
4970     {
4971       /* right is a pointer reg need both a & b */
4972       while (size--)
4973         {
4974           char *l = aopGet (AOP (left), offset, FALSE, FALSE);
4975           if (strcmp (l, "b"))
4976             emitcode ("mov", "b,%s", l);
4977           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
4978           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
4979           offset++;
4980         }
4981     }
4982 }
4983
4984 /*-----------------------------------------------------------------*/
4985 /* gencjne - compare and jump if not equal                         */
4986 /*-----------------------------------------------------------------*/
4987 static void
4988 gencjne (operand * left, operand * right, symbol * lbl)
4989 {
4990   symbol *tlbl = newiTempLabel (NULL);
4991
4992   gencjneshort (left, right, lbl);
4993
4994   emitcode ("mov", "a,%s", one);
4995   emitcode ("sjmp", "%05d$", tlbl->key + 100);
4996   emitcode ("", "%05d$:", lbl->key + 100);
4997   emitcode ("clr", "a");
4998   emitcode ("", "%05d$:", tlbl->key + 100);
4999 }
5000
5001 /*-----------------------------------------------------------------*/
5002 /* genCmpEq - generates code for equal to                          */
5003 /*-----------------------------------------------------------------*/
5004 static void
5005 genCmpEq (iCode * ic, iCode * ifx)
5006 {
5007   operand *left, *right, *result;
5008
5009   D(emitcode (";     genCmpEq",""));
5010
5011   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5012   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5013   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5014
5015   /* if literal, literal on the right or
5016      if the right is in a pointer register and left
5017      is not */
5018   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5019       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5020     {
5021       operand *t = IC_RIGHT (ic);
5022       IC_RIGHT (ic) = IC_LEFT (ic);
5023       IC_LEFT (ic) = t;
5024     }
5025
5026   if (ifx && !AOP_SIZE (result))
5027     {
5028       symbol *tlbl;
5029       /* if they are both bit variables */
5030       if (AOP_TYPE (left) == AOP_CRY &&
5031           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5032         {
5033           if (AOP_TYPE (right) == AOP_LIT)
5034             {
5035               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5036               if (lit == 0L)
5037                 {
5038                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5039                   emitcode ("cpl", "c");
5040                 }
5041               else if (lit == 1L)
5042                 {
5043                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5044                 }
5045               else
5046                 {
5047                   emitcode ("clr", "c");
5048                 }
5049               /* AOP_TYPE(right) == AOP_CRY */
5050             }
5051           else
5052             {
5053               symbol *lbl = newiTempLabel (NULL);
5054               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5055               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5056               emitcode ("cpl", "c");
5057               emitcode ("", "%05d$:", (lbl->key + 100));
5058             }
5059           /* if true label then we jump if condition
5060              supplied is true */
5061           tlbl = newiTempLabel (NULL);
5062           if (IC_TRUE (ifx))
5063             {
5064               emitcode ("jnc", "%05d$", tlbl->key + 100);
5065               freeForBranchAsmop (result);
5066               freeForBranchAsmop (right);
5067               freeForBranchAsmop (left);
5068               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5069             }
5070           else
5071             {
5072               emitcode ("jc", "%05d$", tlbl->key + 100);
5073               freeForBranchAsmop (result);
5074               freeForBranchAsmop (right);
5075               freeForBranchAsmop (left);
5076               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5077             }
5078           emitcode ("", "%05d$:", tlbl->key + 100);
5079         }
5080       else
5081         {
5082           tlbl = newiTempLabel (NULL);
5083           gencjneshort (left, right, tlbl);
5084           if (IC_TRUE (ifx))
5085             {
5086               freeForBranchAsmop (result);
5087               freeForBranchAsmop (right);
5088               freeForBranchAsmop (left);
5089               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5090               emitcode ("", "%05d$:", tlbl->key + 100);
5091             }
5092           else
5093             {
5094               symbol *lbl = newiTempLabel (NULL);
5095               emitcode ("sjmp", "%05d$", lbl->key + 100);
5096               emitcode ("", "%05d$:", tlbl->key + 100);
5097               freeForBranchAsmop (result);
5098               freeForBranchAsmop (right);
5099               freeForBranchAsmop (left);
5100               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5101               emitcode ("", "%05d$:", lbl->key + 100);
5102             }
5103         }
5104       /* mark the icode as generated */
5105       ifx->generated = 1;
5106       goto release;
5107     }
5108
5109   /* if they are both bit variables */
5110   if (AOP_TYPE (left) == AOP_CRY &&
5111       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5112     {
5113       if (AOP_TYPE (right) == AOP_LIT)
5114         {
5115           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5116           if (lit == 0L)
5117             {
5118               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5119               emitcode ("cpl", "c");
5120             }
5121           else if (lit == 1L)
5122             {
5123               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5124             }
5125           else
5126             {
5127               emitcode ("clr", "c");
5128             }
5129           /* AOP_TYPE(right) == AOP_CRY */
5130         }
5131       else
5132         {
5133           symbol *lbl = newiTempLabel (NULL);
5134           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5135           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5136           emitcode ("cpl", "c");
5137           emitcode ("", "%05d$:", (lbl->key + 100));
5138         }
5139       /* c = 1 if egal */
5140       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5141         {
5142           outBitC (result);
5143           goto release;
5144         }
5145       if (ifx)
5146         {
5147           genIfxJump (ifx, "c", left, right, result);
5148           goto release;
5149         }
5150       /* if the result is used in an arithmetic operation
5151          then put the result in place */
5152       outBitC (result);
5153     }
5154   else
5155     {
5156       gencjne (left, right, newiTempLabel (NULL));
5157       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5158         {
5159           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5160           goto release;
5161         }
5162       if (ifx)
5163         {
5164           genIfxJump (ifx, "a", left, right, result);
5165           goto release;
5166         }
5167       /* if the result is used in an arithmetic operation
5168          then put the result in place */
5169       if (AOP_TYPE (result) != AOP_CRY)
5170         outAcc (result);
5171       /* leave the result in acc */
5172     }
5173
5174 release:
5175   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5176   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5177   freeAsmop (result, NULL, ic, TRUE);
5178 }
5179
5180 /*-----------------------------------------------------------------*/
5181 /* ifxForOp - returns the icode containing the ifx for operand     */
5182 /*-----------------------------------------------------------------*/
5183 static iCode *
5184 ifxForOp (operand * op, iCode * ic)
5185 {
5186   /* if true symbol then needs to be assigned */
5187   if (IS_TRUE_SYMOP (op))
5188     return NULL;
5189
5190   /* if this has register type condition and
5191      the next instruction is ifx with the same operand
5192      and live to of the operand is upto the ifx only then */
5193   if (ic->next &&
5194       ic->next->op == IFX &&
5195       IC_COND (ic->next)->key == op->key &&
5196       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5197     return ic->next;
5198
5199   return NULL;
5200 }
5201
5202 /*-----------------------------------------------------------------*/
5203 /* hasInc - operand is incremented before any other use            */
5204 /*-----------------------------------------------------------------*/
5205 static iCode *
5206 hasInc (operand *op, iCode *ic,int osize)
5207 {
5208   sym_link *type = operandType(op);
5209   sym_link *retype = getSpec (type);
5210   iCode *lic = ic->next;
5211   int isize ;
5212
5213   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5214   if (!IS_SYMOP(op)) return NULL;
5215
5216   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5217   if (IS_AGGREGATE(type->next)) return NULL;
5218   if (osize != (isize = getSize(type->next))) return NULL;
5219
5220   while (lic) {
5221     /* if operand of the form op = op + <sizeof *op> */
5222     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5223         isOperandEqual(IC_RESULT(lic),op) &&
5224         isOperandLiteral(IC_RIGHT(lic)) &&
5225         operandLitValue(IC_RIGHT(lic)) == isize) {
5226       return lic;
5227     }
5228     /* if the operand used or deffed */
5229     if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) {
5230       return NULL;
5231     }
5232     /* if GOTO or IFX */
5233     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5234     lic = lic->next;
5235   }
5236   return NULL;
5237 }
5238
5239 /*-----------------------------------------------------------------*/
5240 /* genAndOp - for && operation                                     */
5241 /*-----------------------------------------------------------------*/
5242 static void
5243 genAndOp (iCode * ic)
5244 {
5245   operand *left, *right, *result;
5246   symbol *tlbl;
5247
5248   D(emitcode (";     genAndOp",""));
5249
5250   /* note here that && operations that are in an
5251      if statement are taken away by backPatchLabels
5252      only those used in arthmetic operations remain */
5253   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5254   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5255   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5256
5257   /* if both are bit variables */
5258   if (AOP_TYPE (left) == AOP_CRY &&
5259       AOP_TYPE (right) == AOP_CRY)
5260     {
5261       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5262       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5263       outBitC (result);
5264     }
5265   else
5266     {
5267       tlbl = newiTempLabel (NULL);
5268       toBoolean (left);
5269       emitcode ("jz", "%05d$", tlbl->key + 100);
5270       toBoolean (right);
5271       emitcode ("", "%05d$:", tlbl->key + 100);
5272       outBitAcc (result);
5273     }
5274
5275   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5276   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5277   freeAsmop (result, NULL, ic, TRUE);
5278 }
5279
5280
5281 /*-----------------------------------------------------------------*/
5282 /* genOrOp - for || operation                                      */
5283 /*-----------------------------------------------------------------*/
5284 static void
5285 genOrOp (iCode * ic)
5286 {
5287   operand *left, *right, *result;
5288   symbol *tlbl;
5289
5290   D(emitcode (";     genOrOp",""));
5291
5292   /* note here that || operations that are in an
5293      if statement are taken away by backPatchLabels
5294      only those used in arthmetic operations remain */
5295   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5296   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5297   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5298
5299   /* if both are bit variables */
5300   if (AOP_TYPE (left) == AOP_CRY &&
5301       AOP_TYPE (right) == AOP_CRY)
5302     {
5303       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5304       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5305       outBitC (result);
5306     }
5307   else
5308     {
5309       tlbl = newiTempLabel (NULL);
5310       toBoolean (left);
5311       emitcode ("jnz", "%05d$", tlbl->key + 100);
5312       toBoolean (right);
5313       emitcode ("", "%05d$:", tlbl->key + 100);
5314       outBitAcc (result);
5315     }
5316
5317   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5318   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5319   freeAsmop (result, NULL, ic, TRUE);
5320 }
5321
5322 /*-----------------------------------------------------------------*/
5323 /* isLiteralBit - test if lit == 2^n                               */
5324 /*-----------------------------------------------------------------*/
5325 static int
5326 isLiteralBit (unsigned long lit)
5327 {
5328   unsigned long pw[32] =
5329   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5330    0x100L, 0x200L, 0x400L, 0x800L,
5331    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5332    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5333    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5334    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5335    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5336   int idx;
5337
5338   for (idx = 0; idx < 32; idx++)
5339     if (lit == pw[idx])
5340       return idx + 1;
5341   return 0;
5342 }
5343
5344 /*-----------------------------------------------------------------*/
5345 /* continueIfTrue -                                                */
5346 /*-----------------------------------------------------------------*/
5347 static void
5348 continueIfTrue (iCode * ic)
5349 {
5350   if (IC_TRUE (ic))
5351     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5352   ic->generated = 1;
5353 }
5354
5355 /*-----------------------------------------------------------------*/
5356 /* jmpIfTrue -                                                     */
5357 /*-----------------------------------------------------------------*/
5358 static void
5359 jumpIfTrue (iCode * ic)
5360 {
5361   if (!IC_TRUE (ic))
5362     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5363   ic->generated = 1;
5364 }
5365
5366 /*-----------------------------------------------------------------*/
5367 /* jmpTrueOrFalse -                                                */
5368 /*-----------------------------------------------------------------*/
5369 static void
5370 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5371 {
5372   // ugly but optimized by peephole
5373   if (IC_TRUE (ic))
5374     {
5375       symbol *nlbl = newiTempLabel (NULL);
5376       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5377       emitcode ("", "%05d$:", tlbl->key + 100);
5378       freeForBranchAsmop (result);
5379       freeForBranchAsmop (right);
5380       freeForBranchAsmop (left);
5381       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5382       emitcode ("", "%05d$:", nlbl->key + 100);
5383     }
5384   else
5385     {
5386       freeForBranchAsmop (result);
5387       freeForBranchAsmop (right);
5388       freeForBranchAsmop (left);
5389       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5390       emitcode ("", "%05d$:", tlbl->key + 100);
5391     }
5392   ic->generated = 1;
5393 }
5394
5395 /*-----------------------------------------------------------------*/
5396 /* genAnd  - code for and                                          */
5397 /*-----------------------------------------------------------------*/
5398 static void
5399 genAnd (iCode * ic, iCode * ifx)
5400 {
5401   operand *left, *right, *result;
5402   int size, offset = 0;
5403   unsigned long lit = 0L;
5404   int bytelit = 0;
5405   char buffer[10];
5406
5407   D(emitcode (";     genAnd",""));
5408
5409   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5410   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5411   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5412
5413 #ifdef DEBUG_TYPE
5414   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5415             AOP_TYPE (result),
5416             AOP_TYPE (left), AOP_TYPE (right));
5417   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5418             AOP_SIZE (result),
5419             AOP_SIZE (left), AOP_SIZE (right));
5420 #endif
5421
5422   /* if left is a literal & right is not then exchange them */
5423   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5424       AOP_NEEDSACC (left))
5425     {
5426       operand *tmp = right;
5427       right = left;
5428       left = tmp;
5429     }
5430
5431   /* if result = right then exchange them */
5432   if (sameRegs (AOP (result), AOP (right)))
5433     {
5434       operand *tmp = right;
5435       right = left;
5436       left = tmp;
5437     }
5438
5439   /* if right is bit then exchange them */
5440   if (AOP_TYPE (right) == AOP_CRY &&
5441       AOP_TYPE (left) != AOP_CRY)
5442     {
5443       operand *tmp = right;
5444       right = left;
5445       left = tmp;
5446     }
5447   if (AOP_TYPE (right) == AOP_LIT)
5448     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5449
5450   size = AOP_SIZE (result);
5451
5452   // if(bit & yy)
5453   // result = bit & yy;
5454   if (AOP_TYPE (left) == AOP_CRY)
5455     {
5456       // c = bit & literal;
5457       if (AOP_TYPE (right) == AOP_LIT)
5458         {
5459           if (lit & 1)
5460             {
5461               if (size && sameRegs (AOP (result), AOP (left)))
5462                 // no change
5463                 goto release;
5464               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5465             }
5466           else
5467             {
5468               // bit(result) = 0;
5469               if (size && (AOP_TYPE (result) == AOP_CRY))
5470                 {
5471                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5472                   goto release;
5473                 }
5474               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5475                 {
5476                   jumpIfTrue (ifx);
5477                   goto release;
5478                 }
5479               emitcode ("clr", "c");
5480             }
5481         }
5482       else
5483         {
5484           if (AOP_TYPE (right) == AOP_CRY)
5485             {
5486               // c = bit & bit;
5487               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5488               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5489             }
5490           else
5491             {
5492               // c = bit & val;
5493               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5494               // c = lsb
5495               emitcode ("rrc", "a");
5496               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5497             }
5498         }
5499       // bit = c
5500       // val = c
5501       if (size)
5502         outBitC (result);
5503       // if(bit & ...)
5504       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5505         genIfxJump (ifx, "c", left, right, result);
5506       goto release;
5507     }
5508
5509   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5510   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5511   if ((AOP_TYPE (right) == AOP_LIT) &&
5512       (AOP_TYPE (result) == AOP_CRY) &&
5513       (AOP_TYPE (left) != AOP_CRY))
5514     {
5515       int posbit = isLiteralBit (lit);
5516       /* left &  2^n */
5517       if (posbit)
5518         {
5519           posbit--;
5520           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5521           // bit = left & 2^n
5522           if (size)
5523             emitcode ("mov", "c,acc.%d", posbit & 0x07);
5524           // if(left &  2^n)
5525           else
5526             {
5527               if (ifx)
5528                 {
5529                   sprintf (buffer, "acc.%d", posbit & 0x07);
5530                   genIfxJump (ifx, buffer, left, right, result);
5531                 }
5532               goto release;
5533             }
5534         }
5535       else
5536         {
5537           symbol *tlbl = newiTempLabel (NULL);
5538           int sizel = AOP_SIZE (left);
5539           if (size)
5540             emitcode ("setb", "c");
5541           while (sizel--)
5542             {
5543               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5544                 {
5545                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5546                   // byte ==  2^n ?
5547                   if ((posbit = isLiteralBit (bytelit)) != 0)
5548                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5549                   else
5550                     {
5551                       if (bytelit != 0x0FFL)
5552                         emitcode ("anl", "a,%s",
5553                                   aopGet (AOP (right), offset, FALSE, TRUE));
5554                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5555                     }
5556                 }
5557               offset++;
5558             }
5559           // bit = left & literal
5560           if (size)
5561             {
5562               emitcode ("clr", "c");
5563               emitcode ("", "%05d$:", tlbl->key + 100);
5564             }
5565           // if(left & literal)
5566           else
5567             {
5568               if (ifx)
5569                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5570               else
5571                 emitcode ("", "%05d$:", tlbl->key + 100);
5572               goto release;
5573             }
5574         }
5575       outBitC (result);
5576       goto release;
5577     }
5578
5579   /* if left is same as result */
5580   if (sameRegs (AOP (result), AOP (left)))
5581     {
5582       for (; size--; offset++)
5583         {
5584           if (AOP_TYPE (right) == AOP_LIT)
5585             {
5586               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5587                 continue;
5588               else if (bytelit == 0)
5589                 {
5590                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5591                 }
5592               else if (IS_AOP_PREG (result))
5593                 {
5594                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5595                   emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5596                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5597                 }
5598               else
5599                 emitcode ("anl", "%s,%s",
5600                           aopGet (AOP (left), offset, FALSE, TRUE),
5601                           aopGet (AOP (right), offset, FALSE, FALSE));
5602             }
5603           else
5604             {
5605               if (AOP_TYPE (left) == AOP_ACC)
5606                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5607               else
5608                 {
5609                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5610                   if (IS_AOP_PREG (result))
5611                     {
5612                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5613                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5614
5615                     }
5616                   else
5617                     emitcode ("anl", "%s,a",
5618                               aopGet (AOP (left), offset, FALSE, TRUE));
5619                 }
5620             }
5621         }
5622     }
5623   else
5624     {
5625       // left & result in different registers
5626       if (AOP_TYPE (result) == AOP_CRY)
5627         {
5628           // result = bit
5629           // if(size), result in bit
5630           // if(!size && ifx), conditional oper: if(left & right)
5631           symbol *tlbl = newiTempLabel (NULL);
5632           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5633           if (size)
5634             emitcode ("setb", "c");
5635           while (sizer--)
5636             {
5637               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5638                 emitcode ("anl", "a,%s",
5639                           aopGet (AOP (right), offset, FALSE, FALSE));
5640               } else {
5641                 if (AOP_TYPE(left)==AOP_ACC) {
5642                   emitcode("mov", "b,a");
5643                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5644                   emitcode("anl", "a,b");
5645                 }else {
5646                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5647                   emitcode ("anl", "a,%s",
5648                             aopGet (AOP (left), offset, FALSE, FALSE));
5649                 }
5650               }
5651               emitcode ("jnz", "%05d$", tlbl->key + 100);
5652               offset++;
5653             }
5654           if (size)
5655             {
5656               CLRC;
5657               emitcode ("", "%05d$:", tlbl->key + 100);
5658               outBitC (result);
5659             }
5660           else if (ifx)
5661             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5662           else
5663             emitcode ("", "%05d$:", tlbl->key + 100);
5664         }
5665       else
5666         {
5667           for (; (size--); offset++)
5668             {
5669               // normal case
5670               // result = left & right
5671               if (AOP_TYPE (right) == AOP_LIT)
5672                 {
5673                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5674                     {
5675                       aopPut (AOP (result),
5676                               aopGet (AOP (left), offset, FALSE, FALSE),
5677                               offset,
5678                               isOperandVolatile (result, FALSE));
5679                       continue;
5680                     }
5681                   else if (bytelit == 0)
5682                     {
5683                       /* dummy read of volatile operand */
5684                       if (isOperandVolatile (left, FALSE))
5685                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5686                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5687                       continue;
5688                     }
5689                 }
5690               // faster than result <- left, anl result,right
5691               // and better if result is SFR
5692               if (AOP_TYPE (left) == AOP_ACC)
5693                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5694               else
5695                 {
5696                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5697                   emitcode ("anl", "a,%s",
5698                             aopGet (AOP (left), offset, FALSE, FALSE));
5699                 }
5700               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5701             }
5702         }
5703     }
5704
5705 release:
5706   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5707   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5708   freeAsmop (result, NULL, ic, TRUE);
5709 }
5710
5711 /*-----------------------------------------------------------------*/
5712 /* genOr  - code for or                                            */
5713 /*-----------------------------------------------------------------*/
5714 static void
5715 genOr (iCode * ic, iCode * ifx)
5716 {
5717   operand *left, *right, *result;
5718   int size, offset = 0;
5719   unsigned long lit = 0L;
5720
5721   D(emitcode (";     genOr",""));
5722
5723   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5724   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5725   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5726
5727 #ifdef DEBUG_TYPE
5728   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5729             AOP_TYPE (result),
5730             AOP_TYPE (left), AOP_TYPE (right));
5731   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5732             AOP_SIZE (result),
5733             AOP_SIZE (left), AOP_SIZE (right));
5734 #endif
5735
5736   /* if left is a literal & right is not then exchange them */
5737   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5738       AOP_NEEDSACC (left))
5739     {
5740       operand *tmp = right;
5741       right = left;
5742       left = tmp;
5743     }
5744
5745   /* if result = right then exchange them */
5746   if (sameRegs (AOP (result), AOP (right)))
5747     {
5748       operand *tmp = right;
5749       right = left;
5750       left = tmp;
5751     }
5752
5753   /* if right is bit then exchange them */
5754   if (AOP_TYPE (right) == AOP_CRY &&
5755       AOP_TYPE (left) != AOP_CRY)
5756     {
5757       operand *tmp = right;
5758       right = left;
5759       left = tmp;
5760     }
5761   if (AOP_TYPE (right) == AOP_LIT)
5762     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5763
5764   size = AOP_SIZE (result);
5765
5766   // if(bit | yy)
5767   // xx = bit | yy;
5768   if (AOP_TYPE (left) == AOP_CRY)
5769     {
5770       if (AOP_TYPE (right) == AOP_LIT)
5771         {
5772           // c = bit | literal;
5773           if (lit)
5774             {
5775               // lit != 0 => result = 1
5776               if (AOP_TYPE (result) == AOP_CRY)
5777                 {
5778                   if (size)
5779                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5780                   else if (ifx)
5781                     continueIfTrue (ifx);
5782                   goto release;
5783                 }
5784               emitcode ("setb", "c");
5785             }
5786           else
5787             {
5788               // lit == 0 => result = left
5789               if (size && sameRegs (AOP (result), AOP (left)))
5790                 goto release;
5791               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5792             }
5793         }
5794       else
5795         {
5796           if (AOP_TYPE (right) == AOP_CRY)
5797             {
5798               // c = bit | bit;
5799               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5800               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
5801             }
5802           else
5803             {
5804               // c = bit | val;
5805               symbol *tlbl = newiTempLabel (NULL);
5806               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
5807                 emitcode ("setb", "c");
5808               emitcode ("jb", "%s,%05d$",
5809                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
5810               toBoolean (right);
5811               emitcode ("jnz", "%05d$", tlbl->key + 100);
5812               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5813                 {
5814                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
5815                   goto release;
5816                 }
5817               else
5818                 {
5819                   CLRC;
5820                   emitcode ("", "%05d$:", tlbl->key + 100);
5821                 }
5822             }
5823         }
5824       // bit = c
5825       // val = c
5826       if (size)
5827         outBitC (result);
5828       // if(bit | ...)
5829       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5830         genIfxJump (ifx, "c", left, right, result);
5831       goto release;
5832     }
5833
5834   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5835   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5836   if ((AOP_TYPE (right) == AOP_LIT) &&
5837       (AOP_TYPE (result) == AOP_CRY) &&
5838       (AOP_TYPE (left) != AOP_CRY))
5839     {
5840       if (lit)
5841         {
5842           // result = 1
5843           if (size)
5844             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5845           else
5846             continueIfTrue (ifx);
5847           goto release;
5848         }
5849       else
5850         {
5851           // lit = 0, result = boolean(left)
5852           if (size)
5853             emitcode ("setb", "c");
5854           toBoolean (right);
5855           if (size)
5856             {
5857               symbol *tlbl = newiTempLabel (NULL);
5858               emitcode ("jnz", "%05d$", tlbl->key + 100);
5859               CLRC;
5860               emitcode ("", "%05d$:", tlbl->key + 100);
5861             }
5862           else
5863             {
5864               genIfxJump (ifx, "a", left, right, result);
5865               goto release;
5866             }
5867         }
5868       outBitC (result);
5869       goto release;
5870     }
5871
5872   /* if left is same as result */
5873   if (sameRegs (AOP (result), AOP (left)))
5874     {
5875       for (; size--; offset++)
5876         {
5877           if (AOP_TYPE (right) == AOP_LIT)
5878             {
5879               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5880                 {
5881                   /* dummy read of volatile operand */
5882                   if (isOperandVolatile (left, FALSE))
5883                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5884                   else
5885                     continue;
5886                 }
5887               else if (IS_AOP_PREG (left))
5888                 {
5889                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5890                   emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5891                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5892                 }
5893               else
5894                 emitcode ("orl", "%s,%s",
5895                           aopGet (AOP (left), offset, FALSE, TRUE),
5896                           aopGet (AOP (right), offset, FALSE, FALSE));
5897             }
5898           else
5899             {
5900               if (AOP_TYPE (left) == AOP_ACC)
5901                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5902               else
5903                 {
5904                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5905                   if (IS_AOP_PREG (left))
5906                     {
5907                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5908                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5909                     }
5910                   else
5911                     emitcode ("orl", "%s,a",
5912                               aopGet (AOP (left), offset, FALSE, TRUE));
5913                 }
5914             }
5915         }
5916     }
5917   else
5918     {
5919       // left & result in different registers
5920       if (AOP_TYPE (result) == AOP_CRY)
5921         {
5922           // result = bit
5923           // if(size), result in bit
5924           // if(!size && ifx), conditional oper: if(left | right)
5925           symbol *tlbl = newiTempLabel (NULL);
5926           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
5927           if (size)
5928             emitcode ("setb", "c");
5929           while (sizer--)
5930             {
5931               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5932                 emitcode ("orl", "a,%s",
5933                           aopGet (AOP (right), offset, FALSE, FALSE));
5934               } else {
5935                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5936                 emitcode ("orl", "a,%s",
5937                           aopGet (AOP (left), offset, FALSE, FALSE));
5938               }
5939               emitcode ("jnz", "%05d$", tlbl->key + 100);
5940               offset++;
5941             }
5942           if (size)
5943             {
5944               CLRC;
5945               emitcode ("", "%05d$:", tlbl->key + 100);
5946               outBitC (result);
5947             }
5948           else if (ifx)
5949             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5950           else
5951             emitcode ("", "%05d$:", tlbl->key + 100);
5952         }
5953       else
5954         for (; (size--); offset++)
5955           {
5956             // normal case
5957             // result = left & right
5958             if (AOP_TYPE (right) == AOP_LIT)
5959               {
5960                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5961                   {
5962                     aopPut (AOP (result),
5963                             aopGet (AOP (left), offset, FALSE, FALSE),
5964                             offset,
5965                             isOperandVolatile (result, FALSE));
5966                     continue;
5967                   }
5968               }
5969             // faster than result <- left, anl result,right
5970             // and better if result is SFR
5971             if (AOP_TYPE (left) == AOP_ACC)
5972               emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5973             else
5974               {
5975                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5976                 emitcode ("orl", "a,%s",
5977                           aopGet (AOP (left), offset, FALSE, FALSE));
5978               }
5979             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5980           }
5981     }
5982
5983 release:
5984   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5985   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5986   freeAsmop (result, NULL, ic, TRUE);
5987 }
5988
5989 /*-----------------------------------------------------------------*/
5990 /* genXor - code for xclusive or                                   */
5991 /*-----------------------------------------------------------------*/
5992 static void
5993 genXor (iCode * ic, iCode * ifx)
5994 {
5995   operand *left, *right, *result;
5996   int size, offset = 0;
5997   unsigned long lit = 0L;
5998
5999   D(emitcode (";     genXor",""));
6000
6001   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6002   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6003   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6004
6005 #ifdef DEBUG_TYPE
6006   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6007             AOP_TYPE (result),
6008             AOP_TYPE (left), AOP_TYPE (right));
6009   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6010             AOP_SIZE (result),
6011             AOP_SIZE (left), AOP_SIZE (right));
6012 #endif
6013
6014   /* if left is a literal & right is not ||
6015      if left needs acc & right does not */
6016   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6017       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6018     {
6019       operand *tmp = right;
6020       right = left;
6021       left = tmp;
6022     }
6023
6024   /* if result = right then exchange them */
6025   if (sameRegs (AOP (result), AOP (right)))
6026     {
6027       operand *tmp = right;
6028       right = left;
6029       left = tmp;
6030     }
6031
6032   /* if right is bit then exchange them */
6033   if (AOP_TYPE (right) == AOP_CRY &&
6034       AOP_TYPE (left) != AOP_CRY)
6035     {
6036       operand *tmp = right;
6037       right = left;
6038       left = tmp;
6039     }
6040   if (AOP_TYPE (right) == AOP_LIT)
6041     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6042
6043   size = AOP_SIZE (result);
6044
6045   // if(bit ^ yy)
6046   // xx = bit ^ yy;
6047   if (AOP_TYPE (left) == AOP_CRY)
6048     {
6049       if (AOP_TYPE (right) == AOP_LIT)
6050         {
6051           // c = bit & literal;
6052           if (lit >> 1)
6053             {
6054               // lit>>1  != 0 => result = 1
6055               if (AOP_TYPE (result) == AOP_CRY)
6056                 {
6057                   if (size)
6058                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6059                   else if (ifx)
6060                     continueIfTrue (ifx);
6061                   goto release;
6062                 }
6063               emitcode ("setb", "c");
6064             }
6065           else
6066             {
6067               // lit == (0 or 1)
6068               if (lit == 0)
6069                 {
6070                   // lit == 0, result = left
6071                   if (size && sameRegs (AOP (result), AOP (left)))
6072                     goto release;
6073                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6074                 }
6075               else
6076                 {
6077                   // lit == 1, result = not(left)
6078                   if (size && sameRegs (AOP (result), AOP (left)))
6079                     {
6080                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6081                       goto release;
6082                     }
6083                   else
6084                     {
6085                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6086                       emitcode ("cpl", "c");
6087                     }
6088                 }
6089             }
6090
6091         }
6092       else
6093         {
6094           // right != literal
6095           symbol *tlbl = newiTempLabel (NULL);
6096           if (AOP_TYPE (right) == AOP_CRY)
6097             {
6098               // c = bit ^ bit;
6099               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6100             }
6101           else
6102             {
6103               int sizer = AOP_SIZE (right);
6104               // c = bit ^ val
6105               // if val>>1 != 0, result = 1
6106               emitcode ("setb", "c");
6107               while (sizer)
6108                 {
6109                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6110                   if (sizer == 1)
6111                     // test the msb of the lsb
6112                     emitcode ("anl", "a,#0xfe");
6113                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6114                   sizer--;
6115                 }
6116               // val = (0,1)
6117               emitcode ("rrc", "a");
6118             }
6119           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6120           emitcode ("cpl", "c");
6121           emitcode ("", "%05d$:", (tlbl->key + 100));
6122         }
6123       // bit = c
6124       // val = c
6125       if (size)
6126         outBitC (result);
6127       // if(bit | ...)
6128       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6129         genIfxJump (ifx, "c", left, right, result);
6130       goto release;
6131     }
6132
6133   if (sameRegs (AOP (result), AOP (left)))
6134     {
6135       /* if left is same as result */
6136       for (; size--; offset++)
6137         {
6138           if (AOP_TYPE (right) == AOP_LIT)
6139             {
6140               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6141                 continue;
6142               else if (IS_AOP_PREG (left))
6143                 {
6144                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6145                   emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6146                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6147                 }
6148               else
6149                 emitcode ("xrl", "%s,%s",
6150                           aopGet (AOP (left), offset, FALSE, TRUE),
6151                           aopGet (AOP (right), offset, FALSE, FALSE));
6152             }
6153           else
6154             {
6155               if (AOP_TYPE (left) == AOP_ACC)
6156                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6157               else
6158                 {
6159                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6160                   if (IS_AOP_PREG (left))
6161                     {
6162                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6163                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6164                     }
6165                   else
6166                     emitcode ("xrl", "%s,a",
6167                               aopGet (AOP (left), offset, FALSE, TRUE));
6168                 }
6169             }
6170         }
6171     }
6172   else
6173     {
6174       // left & result in different registers
6175       if (AOP_TYPE (result) == AOP_CRY)
6176         {
6177           // result = bit
6178           // if(size), result in bit
6179           // if(!size && ifx), conditional oper: if(left ^ right)
6180           symbol *tlbl = newiTempLabel (NULL);
6181           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6182           if (size)
6183             emitcode ("setb", "c");
6184           while (sizer--)
6185             {
6186               if ((AOP_TYPE (right) == AOP_LIT) &&
6187                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6188                 {
6189                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6190                 }
6191               else
6192                 {
6193                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6194                     emitcode ("xrl", "a,%s",
6195                               aopGet (AOP (right), offset, FALSE, FALSE));
6196                   } else {
6197                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6198                     emitcode ("xrl", "a,%s",
6199                               aopGet (AOP (left), offset, FALSE, FALSE));
6200                   }
6201                 }
6202               emitcode ("jnz", "%05d$", tlbl->key + 100);
6203               offset++;
6204             }
6205           if (size)
6206             {
6207               CLRC;
6208               emitcode ("", "%05d$:", tlbl->key + 100);
6209               outBitC (result);
6210             }
6211           else if (ifx)
6212             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6213         }
6214       else
6215         for (; (size--); offset++)
6216           {
6217             // normal case
6218             // result = left & right
6219             if (AOP_TYPE (right) == AOP_LIT)
6220               {
6221                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6222                   {
6223                     aopPut (AOP (result),
6224                             aopGet (AOP (left), offset, FALSE, FALSE),
6225                             offset,
6226                             isOperandVolatile (result, FALSE));
6227                     continue;
6228                   }
6229               }
6230             // faster than result <- left, anl result,right
6231             // and better if result is SFR
6232             if (AOP_TYPE (left) == AOP_ACC)
6233               emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6234             else
6235               {
6236                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6237                 emitcode ("xrl", "a,%s",
6238                           aopGet (AOP (left), offset, FALSE, TRUE));
6239               }
6240             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6241           }
6242     }
6243
6244 release:
6245   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6246   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6247   freeAsmop (result, NULL, ic, TRUE);
6248 }
6249
6250 /*-----------------------------------------------------------------*/
6251 /* genInline - write the inline code out                           */
6252 /*-----------------------------------------------------------------*/
6253 static void
6254 genInline (iCode * ic)
6255 {
6256   char *buffer, *bp, *bp1;
6257
6258   D(emitcode (";     genInline",""));
6259
6260   _G.inLine += (!options.asmpeep);
6261
6262   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6263   strcpy (buffer, IC_INLINE (ic));
6264
6265   /* emit each line as a code */
6266   while (*bp)
6267     {
6268       if (*bp == '\n')
6269         {
6270           *bp++ = '\0';
6271           emitcode (bp1, "");
6272           bp1 = bp;
6273         }
6274       else
6275         {
6276           if (*bp == ':')
6277             {
6278               bp++;
6279               *bp = '\0';
6280               bp++;
6281               emitcode (bp1, "");
6282               bp1 = bp;
6283             }
6284           else
6285             bp++;
6286         }
6287     }
6288   if (bp1 != bp)
6289     emitcode (bp1, "");
6290   /*     emitcode("",buffer); */
6291   _G.inLine -= (!options.asmpeep);
6292 }
6293
6294 /*-----------------------------------------------------------------*/
6295 /* genRRC - rotate right with carry                                */
6296 /*-----------------------------------------------------------------*/
6297 static void
6298 genRRC (iCode * ic)
6299 {
6300   operand *left, *result;
6301   int size, offset = 0;
6302   char *l;
6303
6304   D(emitcode (";     genRRC",""));
6305
6306   /* rotate right with carry */
6307   left = IC_LEFT (ic);
6308   result = IC_RESULT (ic);
6309   aopOp (left, ic, FALSE);
6310   aopOp (result, ic, FALSE);
6311
6312   /* move it to the result */
6313   size = AOP_SIZE (result);
6314   offset = size - 1;
6315   if (size == 1) { /* special case for 1 byte */
6316       l = aopGet (AOP (left), offset, FALSE, FALSE);
6317       MOVA (l);
6318       emitcode ("rr", "a");
6319       goto release;
6320   }
6321   CLRC;
6322   while (size--)
6323     {
6324       l = aopGet (AOP (left), offset, FALSE, FALSE);
6325       MOVA (l);
6326       emitcode ("rrc", "a");
6327       if (AOP_SIZE (result) > 1)
6328         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6329     }
6330   /* now we need to put the carry into the
6331      highest order byte of the result */
6332   if (AOP_SIZE (result) > 1)
6333     {
6334       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6335       MOVA (l);
6336     }
6337   emitcode ("mov", "acc.7,c");
6338  release:
6339   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6340   freeAsmop (left, NULL, ic, TRUE);
6341   freeAsmop (result, NULL, ic, TRUE);
6342 }
6343
6344 /*-----------------------------------------------------------------*/
6345 /* genRLC - generate code for rotate left with carry               */
6346 /*-----------------------------------------------------------------*/
6347 static void
6348 genRLC (iCode * ic)
6349 {
6350   operand *left, *result;
6351   int size, offset = 0;
6352   char *l;
6353
6354   D(emitcode (";     genRLC",""));
6355
6356   /* rotate right with carry */
6357   left = IC_LEFT (ic);
6358   result = IC_RESULT (ic);
6359   aopOp (left, ic, FALSE);
6360   aopOp (result, ic, FALSE);
6361
6362   /* move it to the result */
6363   size = AOP_SIZE (result);
6364   offset = 0;
6365   if (size--)
6366     {
6367       l = aopGet (AOP (left), offset, FALSE, FALSE);
6368       MOVA (l);
6369       if (size == 0) { /* special case for 1 byte */
6370               emitcode("rl","a");
6371               goto release;
6372       }
6373       emitcode ("add", "a,acc");
6374       if (AOP_SIZE (result) > 1)
6375         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6376       while (size--)
6377         {
6378           l = aopGet (AOP (left), offset, FALSE, FALSE);
6379           MOVA (l);
6380           emitcode ("rlc", "a");
6381           if (AOP_SIZE (result) > 1)
6382             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6383         }
6384     }
6385   /* now we need to put the carry into the
6386      highest order byte of the result */
6387   if (AOP_SIZE (result) > 1)
6388     {
6389       l = aopGet (AOP (result), 0, FALSE, FALSE);
6390       MOVA (l);
6391     }
6392   emitcode ("mov", "acc.0,c");
6393  release:
6394   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6395   freeAsmop (left, NULL, ic, TRUE);
6396   freeAsmop (result, NULL, ic, TRUE);
6397 }
6398
6399 /*-----------------------------------------------------------------*/
6400 /* genGetHbit - generates code get highest order bit               */
6401 /*-----------------------------------------------------------------*/
6402 static void
6403 genGetHbit (iCode * ic)
6404 {
6405   operand *left, *result;
6406
6407   D(emitcode (";     genGetHbit",""));
6408
6409   left = IC_LEFT (ic);
6410   result = IC_RESULT (ic);
6411   aopOp (left, ic, FALSE);
6412   aopOp (result, ic, FALSE);
6413
6414   /* get the highest order byte into a */
6415   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6416   if (AOP_TYPE (result) == AOP_CRY)
6417     {
6418       emitcode ("rlc", "a");
6419       outBitC (result);
6420     }
6421   else
6422     {
6423       emitcode ("rl", "a");
6424       emitcode ("anl", "a,#0x01");
6425       outAcc (result);
6426     }
6427
6428
6429   freeAsmop (left, NULL, ic, TRUE);
6430   freeAsmop (result, NULL, ic, TRUE);
6431 }
6432
6433 /*-----------------------------------------------------------------*/
6434 /* genSwap - generates code to swap nibbles or bytes               */
6435 /*-----------------------------------------------------------------*/
6436 static void
6437 genSwap (iCode * ic)
6438 {
6439   operand *left, *result;
6440
6441   D(emitcode (";     genSwap",""));
6442
6443   left = IC_LEFT (ic);
6444   result = IC_RESULT (ic);
6445   aopOp (left, ic, FALSE);
6446   aopOp (result, ic, FALSE);
6447
6448   switch (AOP_SIZE (left))
6449     {
6450     case 1: /* swap nibbles in byte */
6451       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6452       emitcode ("swap", "a");
6453       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6454       break;
6455     case 2: /* swap bytes in word */
6456       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6457         {
6458           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6459           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6460                   0, isOperandVolatile (result, FALSE));
6461           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6462         }
6463       else if (operandsEqu (left, result))
6464         {
6465           char * reg = "a";
6466           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6467           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6468             {
6469               emitcode ("mov", "b,a");
6470               reg = "b";
6471             }
6472           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6473                   0, isOperandVolatile (result, FALSE));
6474           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6475         }
6476       else
6477         {
6478           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6479                   0, isOperandVolatile (result, FALSE));
6480           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6481                   1, isOperandVolatile (result, FALSE));
6482         }
6483       break;
6484     default:
6485       wassertl(FALSE, "unsupported SWAP operand size");
6486     }
6487
6488   freeAsmop (left, NULL, ic, TRUE);
6489   freeAsmop (result, NULL, ic, TRUE);
6490 }
6491
6492
6493 /*-----------------------------------------------------------------*/
6494 /* AccRol - rotate left accumulator by known count                 */
6495 /*-----------------------------------------------------------------*/
6496 static void
6497 AccRol (int shCount)
6498 {
6499   shCount &= 0x0007;            // shCount : 0..7
6500
6501   switch (shCount)
6502     {
6503     case 0:
6504       break;
6505     case 1:
6506       emitcode ("rl", "a");
6507       break;
6508     case 2:
6509       emitcode ("rl", "a");
6510       emitcode ("rl", "a");
6511       break;
6512     case 3:
6513       emitcode ("swap", "a");
6514       emitcode ("rr", "a");
6515       break;
6516     case 4:
6517       emitcode ("swap", "a");
6518       break;
6519     case 5:
6520       emitcode ("swap", "a");
6521       emitcode ("rl", "a");
6522       break;
6523     case 6:
6524       emitcode ("rr", "a");
6525       emitcode ("rr", "a");
6526       break;
6527     case 7:
6528       emitcode ("rr", "a");
6529       break;
6530     }
6531 }
6532
6533 /*-----------------------------------------------------------------*/
6534 /* AccLsh - left shift accumulator by known count                  */
6535 /*-----------------------------------------------------------------*/
6536 static void
6537 AccLsh (int shCount)
6538 {
6539   if (shCount != 0)
6540     {
6541       if (shCount == 1)
6542         emitcode ("add", "a,acc");
6543       else if (shCount == 2)
6544         {
6545           emitcode ("add", "a,acc");
6546           emitcode ("add", "a,acc");
6547         }
6548       else
6549         {
6550           /* rotate left accumulator */
6551           AccRol (shCount);
6552           /* and kill the lower order bits */
6553           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6554         }
6555     }
6556 }
6557
6558 /*-----------------------------------------------------------------*/
6559 /* AccRsh - right shift accumulator by known count                 */
6560 /*-----------------------------------------------------------------*/
6561 static void
6562 AccRsh (int shCount)
6563 {
6564   if (shCount != 0)
6565     {
6566       if (shCount == 1)
6567         {
6568           CLRC;
6569           emitcode ("rrc", "a");
6570         }
6571       else
6572         {
6573           /* rotate right accumulator */
6574           AccRol (8 - shCount);
6575           /* and kill the higher order bits */
6576           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6577         }
6578     }
6579 }
6580
6581 /*-----------------------------------------------------------------*/
6582 /* AccSRsh - signed right shift accumulator by known count                 */
6583 /*-----------------------------------------------------------------*/
6584 static void
6585 AccSRsh (int shCount)
6586 {
6587   symbol *tlbl;
6588   if (shCount != 0)
6589     {
6590       if (shCount == 1)
6591         {
6592           emitcode ("mov", "c,acc.7");
6593           emitcode ("rrc", "a");
6594         }
6595       else if (shCount == 2)
6596         {
6597           emitcode ("mov", "c,acc.7");
6598           emitcode ("rrc", "a");
6599           emitcode ("mov", "c,acc.7");
6600           emitcode ("rrc", "a");
6601         }
6602       else
6603         {
6604           tlbl = newiTempLabel (NULL);
6605           /* rotate right accumulator */
6606           AccRol (8 - shCount);
6607           /* and kill the higher order bits */
6608           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6609           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6610           emitcode ("orl", "a,#0x%02x",
6611                     (unsigned char) ~SRMask[shCount]);
6612           emitcode ("", "%05d$:", tlbl->key + 100);
6613         }
6614     }
6615 }
6616
6617 /*-----------------------------------------------------------------*/
6618 /* shiftR1Left2Result - shift right one byte from left to result   */
6619 /*-----------------------------------------------------------------*/
6620 static void
6621 shiftR1Left2Result (operand * left, int offl,
6622                     operand * result, int offr,
6623                     int shCount, int sign)
6624 {
6625   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6626   /* shift right accumulator */
6627   if (sign)
6628     AccSRsh (shCount);
6629   else
6630     AccRsh (shCount);
6631   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6632 }
6633
6634 /*-----------------------------------------------------------------*/
6635 /* shiftL1Left2Result - shift left one byte from left to result    */
6636 /*-----------------------------------------------------------------*/
6637 static void
6638 shiftL1Left2Result (operand * left, int offl,
6639                     operand * result, int offr, int shCount)
6640 {
6641   char *l;
6642   l = aopGet (AOP (left), offl, FALSE, FALSE);
6643   MOVA (l);
6644   /* shift left accumulator */
6645   AccLsh (shCount);
6646   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6647 }
6648
6649 /*-----------------------------------------------------------------*/
6650 /* movLeft2Result - move byte from left to result                  */
6651 /*-----------------------------------------------------------------*/
6652 static void
6653 movLeft2Result (operand * left, int offl,
6654                 operand * result, int offr, int sign)
6655 {
6656   char *l;
6657   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
6658     {
6659       l = aopGet (AOP (left), offl, FALSE, FALSE);
6660
6661       if (*l == '@' && (IS_AOP_PREG (result)))
6662         {
6663           emitcode ("mov", "a,%s", l);
6664           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6665         }
6666       else
6667         {
6668           if (!sign)
6669             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
6670           else
6671             {
6672               /* MSB sign in acc.7 ! */
6673               if (getDataSize (left) == offl + 1)
6674                 {
6675                   emitcode ("mov", "a,%s", l);
6676                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6677                 }
6678             }
6679         }
6680     }
6681 }
6682
6683 /*-----------------------------------------------------------------*/
6684 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
6685 /*-----------------------------------------------------------------*/
6686 static void
6687 AccAXRrl1 (char *x)
6688 {
6689   emitcode ("rrc", "a");
6690   emitcode ("xch", "a,%s", x);
6691   emitcode ("rrc", "a");
6692   emitcode ("xch", "a,%s", x);
6693 }
6694
6695 /*-----------------------------------------------------------------*/
6696 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
6697 /*-----------------------------------------------------------------*/
6698 static void
6699 AccAXLrl1 (char *x)
6700 {
6701   emitcode ("xch", "a,%s", x);
6702   emitcode ("rlc", "a");
6703   emitcode ("xch", "a,%s", x);
6704   emitcode ("rlc", "a");
6705 }
6706
6707 /*-----------------------------------------------------------------*/
6708 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
6709 /*-----------------------------------------------------------------*/
6710 static void
6711 AccAXLsh1 (char *x)
6712 {
6713   emitcode ("xch", "a,%s", x);
6714   emitcode ("add", "a,acc");
6715   emitcode ("xch", "a,%s", x);
6716   emitcode ("rlc", "a");
6717 }
6718
6719 /*-----------------------------------------------------------------*/
6720 /* AccAXLsh - left shift a:x by known count (0..7)                 */
6721 /*-----------------------------------------------------------------*/
6722 static void
6723 AccAXLsh (char *x, int shCount)
6724 {
6725   switch (shCount)
6726     {
6727     case 0:
6728       break;
6729     case 1:
6730       AccAXLsh1 (x);
6731       break;
6732     case 2:
6733       AccAXLsh1 (x);
6734       AccAXLsh1 (x);
6735       break;
6736     case 3:
6737     case 4:
6738     case 5:                     // AAAAABBB:CCCCCDDD
6739
6740       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
6741
6742       emitcode ("anl", "a,#0x%02x",
6743                 SLMask[shCount]);       // BBB00000:CCCCCDDD
6744
6745       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
6746
6747       AccRol (shCount);         // DDDCCCCC:BBB00000
6748
6749       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
6750
6751       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
6752
6753       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
6754
6755       emitcode ("anl", "a,#0x%02x",
6756                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
6757
6758       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
6759
6760       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
6761
6762       break;
6763     case 6:                     // AAAAAABB:CCCCCCDD
6764       emitcode ("anl", "a,#0x%02x",
6765                 SRMask[shCount]);       // 000000BB:CCCCCCDD
6766       emitcode ("mov", "c,acc.0");      // c = B
6767       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
6768 #if 0 // REMOVE ME
6769       AccAXRrl1 (x);            // BCCCCCCD:D000000B
6770       AccAXRrl1 (x);            // BBCCCCCC:DD000000
6771 #else
6772       emitcode("rrc","a");
6773       emitcode("xch","a,%s", x);
6774       emitcode("rrc","a");
6775       emitcode("mov","c,acc.0"); //<< get correct bit
6776       emitcode("xch","a,%s", x);
6777
6778       emitcode("rrc","a");
6779       emitcode("xch","a,%s", x);
6780       emitcode("rrc","a");
6781       emitcode("xch","a,%s", x);
6782 #endif
6783       break;
6784     case 7:                     // a:x <<= 7
6785
6786       emitcode ("anl", "a,#0x%02x",
6787                 SRMask[shCount]);       // 0000000B:CCCCCCCD
6788
6789       emitcode ("mov", "c,acc.0");      // c = B
6790
6791       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
6792
6793       AccAXRrl1 (x);            // BCCCCCCC:D0000000
6794
6795       break;
6796     default:
6797       break;
6798     }
6799 }
6800
6801 /*-----------------------------------------------------------------*/
6802 /* AccAXRsh - right shift a:x known count (0..7)                   */
6803 /*-----------------------------------------------------------------*/
6804 static void
6805 AccAXRsh (char *x, int shCount)
6806 {
6807   switch (shCount)
6808     {
6809     case 0:
6810       break;
6811     case 1:
6812       CLRC;
6813       AccAXRrl1 (x);            // 0->a:x
6814
6815       break;
6816     case 2:
6817       CLRC;
6818       AccAXRrl1 (x);            // 0->a:x
6819
6820       CLRC;
6821       AccAXRrl1 (x);            // 0->a:x
6822
6823       break;
6824     case 3:
6825     case 4:
6826     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6827
6828       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
6829
6830       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6831
6832       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6833
6834       emitcode ("anl", "a,#0x%02x",
6835                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6836
6837       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6838
6839       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6840
6841       emitcode ("anl", "a,#0x%02x",
6842                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6843
6844       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6845
6846       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6847
6848       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
6849
6850       break;
6851     case 6:                     // AABBBBBB:CCDDDDDD
6852
6853       emitcode ("mov", "c,acc.7");
6854       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6855
6856       emitcode ("mov", "c,acc.7");
6857       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6858
6859       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6860
6861       emitcode ("anl", "a,#0x%02x",
6862                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6863
6864       break;
6865     case 7:                     // ABBBBBBB:CDDDDDDD
6866
6867       emitcode ("mov", "c,acc.7");      // c = A
6868
6869       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6870
6871       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6872
6873       emitcode ("anl", "a,#0x%02x",
6874                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6875
6876       break;
6877     default:
6878       break;
6879     }
6880 }
6881
6882 /*-----------------------------------------------------------------*/
6883 /* AccAXRshS - right shift signed a:x known count (0..7)           */
6884 /*-----------------------------------------------------------------*/
6885 static void
6886 AccAXRshS (char *x, int shCount)
6887 {
6888   symbol *tlbl;
6889   switch (shCount)
6890     {
6891     case 0:
6892       break;
6893     case 1:
6894       emitcode ("mov", "c,acc.7");
6895       AccAXRrl1 (x);            // s->a:x
6896
6897       break;
6898     case 2:
6899       emitcode ("mov", "c,acc.7");
6900       AccAXRrl1 (x);            // s->a:x
6901
6902       emitcode ("mov", "c,acc.7");
6903       AccAXRrl1 (x);            // s->a:x
6904
6905       break;
6906     case 3:
6907     case 4:
6908     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6909
6910       tlbl = newiTempLabel (NULL);
6911       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
6912
6913       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6914
6915       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6916
6917       emitcode ("anl", "a,#0x%02x",
6918                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6919
6920       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6921
6922       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6923
6924       emitcode ("anl", "a,#0x%02x",
6925                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6926
6927       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6928
6929       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6930
6931       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
6932
6933       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6934       emitcode ("orl", "a,#0x%02x",
6935                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
6936
6937       emitcode ("", "%05d$:", tlbl->key + 100);
6938       break;                    // SSSSAAAA:BBBCCCCC
6939
6940     case 6:                     // AABBBBBB:CCDDDDDD
6941
6942       tlbl = newiTempLabel (NULL);
6943       emitcode ("mov", "c,acc.7");
6944       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6945
6946       emitcode ("mov", "c,acc.7");
6947       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6948
6949       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6950
6951       emitcode ("anl", "a,#0x%02x",
6952                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6953
6954       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6955       emitcode ("orl", "a,#0x%02x",
6956                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
6957
6958       emitcode ("", "%05d$:", tlbl->key + 100);
6959       break;
6960     case 7:                     // ABBBBBBB:CDDDDDDD
6961
6962       tlbl = newiTempLabel (NULL);
6963       emitcode ("mov", "c,acc.7");      // c = A
6964
6965       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6966
6967       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6968
6969       emitcode ("anl", "a,#0x%02x",
6970                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6971
6972       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6973       emitcode ("orl", "a,#0x%02x",
6974                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
6975
6976       emitcode ("", "%05d$:", tlbl->key + 100);
6977       break;
6978     default:
6979       break;
6980     }
6981 }
6982
6983 /*-----------------------------------------------------------------*/
6984 /* shiftL2Left2Result - shift left two bytes from left to result   */
6985 /*-----------------------------------------------------------------*/
6986 static void
6987 shiftL2Left2Result (operand * left, int offl,
6988                     operand * result, int offr, int shCount)
6989 {
6990   if (sameRegs (AOP (result), AOP (left)) &&
6991       ((offl + MSB16) == offr))
6992     {
6993       /* don't crash result[offr] */
6994       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6995       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
6996     }
6997   else
6998     {
6999       movLeft2Result (left, offl, result, offr, 0);
7000       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7001     }
7002   /* ax << shCount (x = lsb(result)) */
7003   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7004   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7005 }
7006
7007
7008 /*-----------------------------------------------------------------*/
7009 /* shiftR2Left2Result - shift right two bytes from left to result  */
7010 /*-----------------------------------------------------------------*/
7011 static void
7012 shiftR2Left2Result (operand * left, int offl,
7013                     operand * result, int offr,
7014                     int shCount, int sign)
7015 {
7016   if (sameRegs (AOP (result), AOP (left)) &&
7017       ((offl + MSB16) == offr))
7018     {
7019       /* don't crash result[offr] */
7020       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7021       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7022     }
7023   else
7024     {
7025       movLeft2Result (left, offl, result, offr, 0);
7026       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7027     }
7028   /* a:x >> shCount (x = lsb(result)) */
7029   if (sign)
7030     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7031   else
7032     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7033   if (getDataSize (result) > 1)
7034     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7035 }
7036
7037 /*-----------------------------------------------------------------*/
7038 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7039 /*-----------------------------------------------------------------*/
7040 static void
7041 shiftLLeftOrResult (operand * left, int offl,
7042                     operand * result, int offr, int shCount)
7043 {
7044   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7045   /* shift left accumulator */
7046   AccLsh (shCount);
7047   /* or with result */
7048   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7049   /* back to result */
7050   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7051 }
7052
7053 /*-----------------------------------------------------------------*/
7054 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7055 /*-----------------------------------------------------------------*/
7056 static void
7057 shiftRLeftOrResult (operand * left, int offl,
7058                     operand * result, int offr, int shCount)
7059 {
7060   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7061   /* shift right accumulator */
7062   AccRsh (shCount);
7063   /* or with result */
7064   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7065   /* back to result */
7066   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7067 }
7068
7069 /*-----------------------------------------------------------------*/
7070 /* genlshOne - left shift a one byte quantity by known count       */
7071 /*-----------------------------------------------------------------*/
7072 static void
7073 genlshOne (operand * result, operand * left, int shCount)
7074 {
7075   D(emitcode (";     genlshOne",""));
7076
7077   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7078 }
7079
7080 /*-----------------------------------------------------------------*/
7081 /* genlshTwo - left shift two bytes by known amount != 0           */
7082 /*-----------------------------------------------------------------*/
7083 static void
7084 genlshTwo (operand * result, operand * left, int shCount)
7085 {
7086   int size;
7087
7088   D(emitcode (";     genlshTwo",""));
7089
7090   size = getDataSize (result);
7091
7092   /* if shCount >= 8 */
7093   if (shCount >= 8)
7094     {
7095       shCount -= 8;
7096
7097       if (size > 1)
7098         {
7099           if (shCount)
7100             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7101           else
7102             movLeft2Result (left, LSB, result, MSB16, 0);
7103         }
7104       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7105     }
7106
7107   /*  1 <= shCount <= 7 */
7108   else
7109     {
7110       if (size == 1)
7111         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7112       else
7113         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7114     }
7115 }
7116
7117 /*-----------------------------------------------------------------*/
7118 /* shiftLLong - shift left one long from left to result            */
7119 /* offl = LSB or MSB16                                             */
7120 /*-----------------------------------------------------------------*/
7121 static void
7122 shiftLLong (operand * left, operand * result, int offr)
7123 {
7124   char *l;
7125   int size = AOP_SIZE (result);
7126
7127   if (size >= LSB + offr)
7128     {
7129       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7130       MOVA (l);
7131       emitcode ("add", "a,acc");
7132       if (sameRegs (AOP (left), AOP (result)) &&
7133           size >= MSB16 + offr && offr != LSB)
7134         emitcode ("xch", "a,%s",
7135                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7136       else
7137         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7138     }
7139
7140   if (size >= MSB16 + offr)
7141     {
7142       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7143         {
7144           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7145           MOVA (l);
7146         }
7147       emitcode ("rlc", "a");
7148       if (sameRegs (AOP (left), AOP (result)) &&
7149           size >= MSB24 + offr && offr != LSB)
7150         emitcode ("xch", "a,%s",
7151                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7152       else
7153         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7154     }
7155
7156   if (size >= MSB24 + offr)
7157     {
7158       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7159         {
7160           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7161           MOVA (l);
7162         }
7163       emitcode ("rlc", "a");
7164       if (sameRegs (AOP (left), AOP (result)) &&
7165           size >= MSB32 + offr && offr != LSB)
7166         emitcode ("xch", "a,%s",
7167                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7168       else
7169         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7170     }
7171
7172   if (size > MSB32 + offr)
7173     {
7174       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7175         {
7176           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7177           MOVA (l);
7178         }
7179       emitcode ("rlc", "a");
7180       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7181     }
7182   if (offr != LSB)
7183     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7184 }
7185
7186 /*-----------------------------------------------------------------*/
7187 /* genlshFour - shift four byte by a known amount != 0             */
7188 /*-----------------------------------------------------------------*/
7189 static void
7190 genlshFour (operand * result, operand * left, int shCount)
7191 {
7192   int size;
7193
7194   D(emitcode (";     genlshFour",""));
7195
7196   size = AOP_SIZE (result);
7197
7198   /* if shifting more that 3 bytes */
7199   if (shCount >= 24)
7200     {
7201       shCount -= 24;
7202       if (shCount)
7203         /* lowest order of left goes to the highest
7204            order of the destination */
7205         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7206       else
7207         movLeft2Result (left, LSB, result, MSB32, 0);
7208       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7209       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7210       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7211       return;
7212     }
7213
7214   /* more than two bytes */
7215   else if (shCount >= 16)
7216     {
7217       /* lower order two bytes goes to higher order two bytes */
7218       shCount -= 16;
7219       /* if some more remaining */
7220       if (shCount)
7221         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7222       else
7223         {
7224           movLeft2Result (left, MSB16, result, MSB32, 0);
7225           movLeft2Result (left, LSB, result, MSB24, 0);
7226         }
7227       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7228       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7229       return;
7230     }
7231
7232   /* if more than 1 byte */
7233   else if (shCount >= 8)
7234     {
7235       /* lower order three bytes goes to higher order  three bytes */
7236       shCount -= 8;
7237       if (size == 2)
7238         {
7239           if (shCount)
7240             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7241           else
7242             movLeft2Result (left, LSB, result, MSB16, 0);
7243         }
7244       else
7245         {                       /* size = 4 */
7246           if (shCount == 0)
7247             {
7248               movLeft2Result (left, MSB24, result, MSB32, 0);
7249               movLeft2Result (left, MSB16, result, MSB24, 0);
7250               movLeft2Result (left, LSB, result, MSB16, 0);
7251               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7252             }
7253           else if (shCount == 1)
7254             shiftLLong (left, result, MSB16);
7255           else
7256             {
7257               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7258               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7259               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7260               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7261             }
7262         }
7263     }
7264
7265   /* 1 <= shCount <= 7 */
7266   else if (shCount <= 2)
7267     {
7268       shiftLLong (left, result, LSB);
7269       if (shCount == 2)
7270         shiftLLong (result, result, LSB);
7271     }
7272   /* 3 <= shCount <= 7, optimize */
7273   else
7274     {
7275       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7276       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7277       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7278     }
7279 }
7280
7281 /*-----------------------------------------------------------------*/
7282 /* genLeftShiftLiteral - left shifting by known count              */
7283 /*-----------------------------------------------------------------*/
7284 static void
7285 genLeftShiftLiteral (operand * left,
7286                      operand * right,
7287                      operand * result,
7288                      iCode * ic)
7289 {
7290   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7291   int size;
7292
7293   D(emitcode (";     genLeftShiftLiteral",""));
7294
7295   freeAsmop (right, NULL, ic, TRUE);
7296
7297   aopOp (left, ic, FALSE);
7298   aopOp (result, ic, FALSE);
7299
7300   size = getSize (operandType (result));
7301
7302 #if VIEW_SIZE
7303   emitcode ("; shift left ", "result %d, left %d", size,
7304             AOP_SIZE (left));
7305 #endif
7306
7307   /* I suppose that the left size >= result size */
7308   if (shCount == 0)
7309     {
7310       while (size--)
7311         {
7312           movLeft2Result (left, size, result, size, 0);
7313         }
7314     }
7315
7316   else if (shCount >= (size * 8))
7317     while (size--)
7318       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7319   else
7320     {
7321       switch (size)
7322         {
7323         case 1:
7324           genlshOne (result, left, shCount);
7325           break;
7326
7327         case 2:
7328           genlshTwo (result, left, shCount);
7329           break;
7330
7331         case 4:
7332           genlshFour (result, left, shCount);
7333           break;
7334         default:
7335           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7336                   "*** ack! mystery literal shift!\n");
7337           break;
7338         }
7339     }
7340   freeAsmop (left, NULL, ic, TRUE);
7341   freeAsmop (result, NULL, ic, TRUE);
7342 }
7343
7344 /*-----------------------------------------------------------------*/
7345 /* genLeftShift - generates code for left shifting                 */
7346 /*-----------------------------------------------------------------*/
7347 static void
7348 genLeftShift (iCode * ic)
7349 {
7350   operand *left, *right, *result;
7351   int size, offset;
7352   char *l;
7353   symbol *tlbl, *tlbl1;
7354
7355   D(emitcode (";     genLeftShift",""));
7356
7357   right = IC_RIGHT (ic);
7358   left = IC_LEFT (ic);
7359   result = IC_RESULT (ic);
7360
7361   aopOp (right, ic, FALSE);
7362
7363   /* if the shift count is known then do it
7364      as efficiently as possible */
7365   if (AOP_TYPE (right) == AOP_LIT)
7366     {
7367       genLeftShiftLiteral (left, right, result, ic);
7368       return;
7369     }
7370
7371   /* shift count is unknown then we have to form
7372      a loop get the loop count in B : Note: we take
7373      only the lower order byte since shifting
7374      more that 32 bits make no sense anyway, ( the
7375      largest size of an object can be only 32 bits ) */
7376
7377   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7378   emitcode ("inc", "b");
7379   freeAsmop (right, NULL, ic, TRUE);
7380   aopOp (left, ic, FALSE);
7381   aopOp (result, ic, FALSE);
7382
7383   /* now move the left to the result if they are not the
7384      same */
7385   if (!sameRegs (AOP (left), AOP (result)) &&
7386       AOP_SIZE (result) > 1)
7387     {
7388
7389       size = AOP_SIZE (result);
7390       offset = 0;
7391       while (size--)
7392         {
7393           l = aopGet (AOP (left), offset, FALSE, TRUE);
7394           if (*l == '@' && (IS_AOP_PREG (result)))
7395             {
7396
7397               emitcode ("mov", "a,%s", l);
7398               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7399             }
7400           else
7401             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7402           offset++;
7403         }
7404     }
7405
7406   tlbl = newiTempLabel (NULL);
7407   size = AOP_SIZE (result);
7408   offset = 0;
7409   tlbl1 = newiTempLabel (NULL);
7410
7411   /* if it is only one byte then */
7412   if (size == 1)
7413     {
7414       symbol *tlbl1 = newiTempLabel (NULL);
7415
7416       l = aopGet (AOP (left), 0, FALSE, FALSE);
7417       MOVA (l);
7418       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7419       emitcode ("", "%05d$:", tlbl->key + 100);
7420       emitcode ("add", "a,acc");
7421       emitcode ("", "%05d$:", tlbl1->key + 100);
7422       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7423       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7424       goto release;
7425     }
7426
7427   reAdjustPreg (AOP (result));
7428
7429   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7430   emitcode ("", "%05d$:", tlbl->key + 100);
7431   l = aopGet (AOP (result), offset, FALSE, FALSE);
7432   MOVA (l);
7433   emitcode ("add", "a,acc");
7434   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7435   while (--size)
7436     {
7437       l = aopGet (AOP (result), offset, FALSE, FALSE);
7438       MOVA (l);
7439       emitcode ("rlc", "a");
7440       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7441     }
7442   reAdjustPreg (AOP (result));
7443
7444   emitcode ("", "%05d$:", tlbl1->key + 100);
7445   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7446 release:
7447   freeAsmop (left, NULL, ic, TRUE);
7448   freeAsmop (result, NULL, ic, TRUE);
7449 }
7450
7451 /*-----------------------------------------------------------------*/
7452 /* genrshOne - right shift a one byte quantity by known count      */
7453 /*-----------------------------------------------------------------*/
7454 static void
7455 genrshOne (operand * result, operand * left,
7456            int shCount, int sign)
7457 {
7458   D(emitcode (";     genrshOne",""));
7459
7460   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7461 }
7462
7463 /*-----------------------------------------------------------------*/
7464 /* genrshTwo - right shift two bytes by known amount != 0          */
7465 /*-----------------------------------------------------------------*/
7466 static void
7467 genrshTwo (operand * result, operand * left,
7468            int shCount, int sign)
7469 {
7470   D(emitcode (";     genrshTwo",""));
7471
7472   /* if shCount >= 8 */
7473   if (shCount >= 8)
7474     {
7475       shCount -= 8;
7476       if (shCount)
7477         shiftR1Left2Result (left, MSB16, result, LSB,
7478                             shCount, sign);
7479       else
7480         movLeft2Result (left, MSB16, result, LSB, sign);
7481       addSign (result, MSB16, sign);
7482     }
7483
7484   /*  1 <= shCount <= 7 */
7485   else
7486     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7487 }
7488
7489 /*-----------------------------------------------------------------*/
7490 /* shiftRLong - shift right one long from left to result           */
7491 /* offl = LSB or MSB16                                             */
7492 /*-----------------------------------------------------------------*/
7493 static void
7494 shiftRLong (operand * left, int offl,
7495             operand * result, int sign)
7496 {
7497   int isSameRegs=sameRegs(AOP(left),AOP(result));
7498
7499   if (isSameRegs && offl>1) {
7500     // we are in big trouble, but this shouldn't happen
7501     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7502   }
7503
7504   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7505
7506   if (offl==MSB16) {
7507     // shift is > 8
7508     if (sign) {
7509       emitcode ("rlc", "a");
7510       emitcode ("subb", "a,acc");
7511       if (isSameRegs)
7512         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7513       else {
7514         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7515         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7516       }
7517     } else {
7518       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7519     }
7520   }
7521
7522   if (!sign) {
7523     emitcode ("clr", "c");
7524   } else {
7525     emitcode ("mov", "c,acc.7");
7526   }
7527
7528   emitcode ("rrc", "a");
7529
7530   if (isSameRegs && offl==MSB16) {
7531     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7532   } else {
7533     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7534     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7535   }
7536
7537   emitcode ("rrc", "a");
7538   if (isSameRegs && offl==1) {
7539     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7540   } else {
7541     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7542     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7543   }
7544   emitcode ("rrc", "a");
7545   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7546
7547   if (offl == LSB)
7548     {
7549       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7550       emitcode ("rrc", "a");
7551       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7552     }
7553 }
7554
7555 /*-----------------------------------------------------------------*/
7556 /* genrshFour - shift four byte by a known amount != 0             */
7557 /*-----------------------------------------------------------------*/
7558 static void
7559 genrshFour (operand * result, operand * left,
7560             int shCount, int sign)
7561 {
7562   D(emitcode (";     genrshFour",""));
7563
7564   /* if shifting more that 3 bytes */
7565   if (shCount >= 24)
7566     {
7567       shCount -= 24;
7568       if (shCount)
7569         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7570       else
7571         movLeft2Result (left, MSB32, result, LSB, sign);
7572       addSign (result, MSB16, sign);
7573     }
7574   else if (shCount >= 16)
7575     {
7576       shCount -= 16;
7577       if (shCount)
7578         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7579       else
7580         {
7581           movLeft2Result (left, MSB24, result, LSB, 0);
7582           movLeft2Result (left, MSB32, result, MSB16, sign);
7583         }
7584       addSign (result, MSB24, sign);
7585     }
7586   else if (shCount >= 8)
7587     {
7588       shCount -= 8;
7589       if (shCount == 1)
7590         shiftRLong (left, MSB16, result, sign);
7591       else if (shCount == 0)
7592         {
7593           movLeft2Result (left, MSB16, result, LSB, 0);
7594           movLeft2Result (left, MSB24, result, MSB16, 0);
7595           movLeft2Result (left, MSB32, result, MSB24, sign);
7596           addSign (result, MSB32, sign);
7597         }
7598       else
7599         {
7600           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7601           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7602           /* the last shift is signed */
7603           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7604           addSign (result, MSB32, sign);
7605         }
7606     }
7607   else
7608     {                           /* 1 <= shCount <= 7 */
7609       if (shCount <= 2)
7610         {
7611           shiftRLong (left, LSB, result, sign);
7612           if (shCount == 2)
7613             shiftRLong (result, LSB, result, sign);
7614         }
7615       else
7616         {
7617           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7618           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7619           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7620         }
7621     }
7622 }
7623
7624 /*-----------------------------------------------------------------*/
7625 /* genRightShiftLiteral - right shifting by known count            */
7626 /*-----------------------------------------------------------------*/
7627 static void
7628 genRightShiftLiteral (operand * left,
7629                       operand * right,
7630                       operand * result,
7631                       iCode * ic,
7632                       int sign)
7633 {
7634   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7635   int size;
7636
7637   D(emitcode (";     genRightShiftLiteral",""));
7638
7639   freeAsmop (right, NULL, ic, TRUE);
7640
7641   aopOp (left, ic, FALSE);
7642   aopOp (result, ic, FALSE);
7643
7644 #if VIEW_SIZE
7645   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
7646             AOP_SIZE (left));
7647 #endif
7648
7649   size = getDataSize (left);
7650   /* test the LEFT size !!! */
7651
7652   /* I suppose that the left size >= result size */
7653   if (shCount == 0)
7654     {
7655       size = getDataSize (result);
7656       while (size--)
7657         movLeft2Result (left, size, result, size, 0);
7658     }
7659
7660   else if (shCount >= (size * 8))
7661     {
7662       if (sign) {
7663         /* get sign in acc.7 */
7664         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
7665       }
7666       addSign (result, LSB, sign);
7667     }
7668   else
7669     {
7670       switch (size)
7671         {
7672         case 1:
7673           genrshOne (result, left, shCount, sign);
7674           break;
7675
7676         case 2:
7677           genrshTwo (result, left, shCount, sign);
7678           break;
7679
7680         case 4:
7681           genrshFour (result, left, shCount, sign);
7682           break;
7683         default:
7684           break;
7685         }
7686     }
7687   freeAsmop (left, NULL, ic, TRUE);
7688   freeAsmop (result, NULL, ic, TRUE);
7689 }
7690
7691 /*-----------------------------------------------------------------*/
7692 /* genSignedRightShift - right shift of signed number              */
7693 /*-----------------------------------------------------------------*/
7694 static void
7695 genSignedRightShift (iCode * ic)
7696 {
7697   operand *right, *left, *result;
7698   int size, offset;
7699   char *l;
7700   symbol *tlbl, *tlbl1;
7701
7702   D(emitcode (";     genSignedRightShift",""));
7703
7704   /* we do it the hard way put the shift count in b
7705      and loop thru preserving the sign */
7706
7707   right = IC_RIGHT (ic);
7708   left = IC_LEFT (ic);
7709   result = IC_RESULT (ic);
7710
7711   aopOp (right, ic, FALSE);
7712
7713
7714   if (AOP_TYPE (right) == AOP_LIT)
7715     {
7716       genRightShiftLiteral (left, right, result, ic, 1);
7717       return;
7718     }
7719   /* shift count is unknown then we have to form
7720      a loop get the loop count in B : Note: we take
7721      only the lower order byte since shifting
7722      more that 32 bits make no sense anyway, ( the
7723      largest size of an object can be only 32 bits ) */
7724
7725   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7726   emitcode ("inc", "b");
7727   freeAsmop (right, NULL, ic, TRUE);
7728   aopOp (left, ic, FALSE);
7729   aopOp (result, ic, FALSE);
7730
7731   /* now move the left to the result if they are not the
7732      same */
7733   if (!sameRegs (AOP (left), AOP (result)) &&
7734       AOP_SIZE (result) > 1)
7735     {
7736
7737       size = AOP_SIZE (result);
7738       offset = 0;
7739       while (size--)
7740         {
7741           l = aopGet (AOP (left), offset, FALSE, TRUE);
7742           if (*l == '@' && IS_AOP_PREG (result))
7743             {
7744
7745               emitcode ("mov", "a,%s", l);
7746               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7747             }
7748           else
7749             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7750           offset++;
7751         }
7752     }
7753
7754   /* mov the highest order bit to OVR */
7755   tlbl = newiTempLabel (NULL);
7756   tlbl1 = newiTempLabel (NULL);
7757
7758   size = AOP_SIZE (result);
7759   offset = size - 1;
7760   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
7761   emitcode ("rlc", "a");
7762   emitcode ("mov", "ov,c");
7763   /* if it is only one byte then */
7764   if (size == 1)
7765     {
7766       l = aopGet (AOP (left), 0, FALSE, FALSE);
7767       MOVA (l);
7768       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7769       emitcode ("", "%05d$:", tlbl->key + 100);
7770       emitcode ("mov", "c,ov");
7771       emitcode ("rrc", "a");
7772       emitcode ("", "%05d$:", tlbl1->key + 100);
7773       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7774       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7775       goto release;
7776     }
7777
7778   reAdjustPreg (AOP (result));
7779   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7780   emitcode ("", "%05d$:", tlbl->key + 100);
7781   emitcode ("mov", "c,ov");
7782   while (size--)
7783     {
7784       l = aopGet (AOP (result), offset, FALSE, FALSE);
7785       MOVA (l);
7786       emitcode ("rrc", "a");
7787       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7788     }
7789   reAdjustPreg (AOP (result));
7790   emitcode ("", "%05d$:", tlbl1->key + 100);
7791   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7792
7793 release:
7794   freeAsmop (left, NULL, ic, TRUE);
7795   freeAsmop (result, NULL, ic, TRUE);
7796 }
7797
7798 /*-----------------------------------------------------------------*/
7799 /* genRightShift - generate code for right shifting                */
7800 /*-----------------------------------------------------------------*/
7801 static void
7802 genRightShift (iCode * ic)
7803 {
7804   operand *right, *left, *result;
7805   sym_link *letype;
7806   int size, offset;
7807   char *l;
7808   symbol *tlbl, *tlbl1;
7809
7810   D(emitcode (";     genRightShift",""));
7811
7812   /* if signed then we do it the hard way preserve the
7813      sign bit moving it inwards */
7814   letype = getSpec (operandType (IC_LEFT (ic)));
7815
7816   if (!SPEC_USIGN (letype))
7817     {
7818       genSignedRightShift (ic);
7819       return;
7820     }
7821
7822   /* signed & unsigned types are treated the same : i.e. the
7823      signed is NOT propagated inwards : quoting from the
7824      ANSI - standard : "for E1 >> E2, is equivalent to division
7825      by 2**E2 if unsigned or if it has a non-negative value,
7826      otherwise the result is implementation defined ", MY definition
7827      is that the sign does not get propagated */
7828
7829   right = IC_RIGHT (ic);
7830   left = IC_LEFT (ic);
7831   result = IC_RESULT (ic);
7832
7833   aopOp (right, ic, FALSE);
7834
7835   /* if the shift count is known then do it
7836      as efficiently as possible */
7837   if (AOP_TYPE (right) == AOP_LIT)
7838     {
7839       genRightShiftLiteral (left, right, result, ic, 0);
7840       return;
7841     }
7842
7843   /* shift count is unknown then we have to form
7844      a loop get the loop count in B : Note: we take
7845      only the lower order byte since shifting
7846      more that 32 bits make no sense anyway, ( the
7847      largest size of an object can be only 32 bits ) */
7848
7849   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7850   emitcode ("inc", "b");
7851   freeAsmop (right, NULL, ic, TRUE);
7852   aopOp (left, ic, FALSE);
7853   aopOp (result, ic, FALSE);
7854
7855   /* now move the left to the result if they are not the
7856      same */
7857   if (!sameRegs (AOP (left), AOP (result)) &&
7858       AOP_SIZE (result) > 1)
7859     {
7860
7861       size = AOP_SIZE (result);
7862       offset = 0;
7863       while (size--)
7864         {
7865           l = aopGet (AOP (left), offset, FALSE, TRUE);
7866           if (*l == '@' && IS_AOP_PREG (result))
7867             {
7868
7869               emitcode ("mov", "a,%s", l);
7870               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7871             }
7872           else
7873             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7874           offset++;
7875         }
7876     }
7877
7878   tlbl = newiTempLabel (NULL);
7879   tlbl1 = newiTempLabel (NULL);
7880   size = AOP_SIZE (result);
7881   offset = size - 1;
7882
7883   /* if it is only one byte then */
7884   if (size == 1)
7885     {
7886       l = aopGet (AOP (left), 0, FALSE, FALSE);
7887       MOVA (l);
7888       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7889       emitcode ("", "%05d$:", tlbl->key + 100);
7890       CLRC;
7891       emitcode ("rrc", "a");
7892       emitcode ("", "%05d$:", tlbl1->key + 100);
7893       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7894       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7895       goto release;
7896     }
7897
7898   reAdjustPreg (AOP (result));
7899   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7900   emitcode ("", "%05d$:", tlbl->key + 100);
7901   CLRC;
7902   while (size--)
7903     {
7904       l = aopGet (AOP (result), offset, FALSE, FALSE);
7905       MOVA (l);
7906       emitcode ("rrc", "a");
7907       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7908     }
7909   reAdjustPreg (AOP (result));
7910
7911   emitcode ("", "%05d$:", tlbl1->key + 100);
7912   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7913
7914 release:
7915   freeAsmop (left, NULL, ic, TRUE);
7916   freeAsmop (result, NULL, ic, TRUE);
7917 }
7918
7919 /*-----------------------------------------------------------------*/
7920 /* emitPtrByteGet - emits code to get a byte into A through a      */
7921 /*                  pointer register (R0, R1, or DPTR). The        */
7922 /*                  original value of A can be preserved in B.     */
7923 /*-----------------------------------------------------------------*/
7924 static void
7925 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
7926 {
7927   switch (p_type)
7928     {
7929     case IPOINTER:
7930     case POINTER:
7931       if (preserveAinB)
7932         emitcode ("mov", "b,a");
7933       emitcode ("mov", "a,@%s", rname);
7934       break;
7935
7936     case PPOINTER:
7937       if (preserveAinB)
7938         emitcode ("mov", "b,a");
7939       emitcode ("movx", "a,@%s", rname);
7940       break;
7941
7942     case FPOINTER:
7943       if (preserveAinB)
7944         emitcode ("mov", "b,a");
7945       emitcode ("movx", "a,@dptr");
7946       break;
7947
7948     case CPOINTER:
7949       if (preserveAinB)
7950         emitcode ("mov", "b,a");
7951       emitcode ("clr", "a");
7952       emitcode ("movc", "a,@a+dptr");
7953       break;
7954
7955     case GPOINTER:
7956       if (preserveAinB)
7957         {
7958           emitcode ("push", "b");
7959           emitcode ("push", "acc");
7960         }
7961       emitcode ("lcall", "__gptrget");
7962       if (preserveAinB)
7963         emitcode ("pop", "b");
7964       break;
7965     }
7966 }
7967
7968 /*-----------------------------------------------------------------*/
7969 /* emitPtrByteSet - emits code to set a byte from src through a    */
7970 /*                  pointer register (R0, R1, or DPTR).            */
7971 /*-----------------------------------------------------------------*/
7972 static void
7973 emitPtrByteSet (char *rname, int p_type, char *src)
7974 {
7975   switch (p_type)
7976     {
7977     case IPOINTER:
7978     case POINTER:
7979       if (*src=='@')
7980         {
7981           MOVA (src);
7982           emitcode ("mov", "@%s,a", rname);
7983         }
7984       else
7985         emitcode ("mov", "@%s,%s", rname, src);
7986       break;
7987
7988     case PPOINTER:
7989       MOVA (src);
7990       emitcode ("movx", "@%s,a", rname);
7991       break;
7992
7993     case FPOINTER:
7994       MOVA (src);
7995       emitcode ("movx", "@dptr,a");
7996       break;
7997
7998     case GPOINTER:
7999       MOVA (src);
8000       emitcode ("lcall", "__gptrput");
8001       break;
8002     }
8003 }
8004
8005 /*-----------------------------------------------------------------*/
8006 /* genUnpackBits - generates code for unpacking bits               */
8007 /*-----------------------------------------------------------------*/
8008 static void
8009 genUnpackBits (operand * result, char *rname, int ptype)
8010 {
8011   int offset = 0;       /* result byte offset */
8012   int rsize;            /* result size */
8013   int rlen = 0;         /* remaining bitfield length */
8014   sym_link *etype;      /* bitfield type information */
8015   int blen;             /* bitfield length */
8016   int bstr;             /* bitfield starting bit within byte */
8017
8018   D(emitcode (";     genUnpackBits",""));
8019
8020   etype = getSpec (operandType (result));
8021   rsize = getSize (operandType (result));
8022   blen = SPEC_BLEN (etype);
8023   bstr = SPEC_BSTR (etype);
8024
8025   /* If the bitfield length is less than a byte */
8026   if (blen < 8)
8027     {
8028       emitPtrByteGet (rname, ptype, FALSE);
8029       AccRsh (bstr);
8030       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8031       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8032       goto finish;
8033     }
8034
8035   /* Bit field did not fit in a byte. Copy all
8036      but the partial byte at the end.  */
8037   for (rlen=blen;rlen>=8;rlen-=8)
8038     {
8039       emitPtrByteGet (rname, ptype, FALSE);
8040       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8041       if (rlen>8)
8042         emitcode ("inc", "%s", rname);
8043     }
8044
8045   /* Handle the partial byte at the end */
8046   if (rlen)
8047     {
8048       emitPtrByteGet (rname, ptype, FALSE);
8049       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8050       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8051     }
8052
8053 finish:
8054   if (offset < rsize)
8055     {
8056       rsize -= offset;
8057       while (rsize--)
8058         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8059     }
8060 }
8061
8062
8063 /*-----------------------------------------------------------------*/
8064 /* genDataPointerGet - generates code when ptr offset is known     */
8065 /*-----------------------------------------------------------------*/
8066 static void
8067 genDataPointerGet (operand * left,
8068                    operand * result,
8069                    iCode * ic)
8070 {
8071   char *l;
8072   char buffer[256];
8073   int size, offset = 0;
8074
8075   D(emitcode (";     genDataPointerGet",""));
8076
8077   aopOp (result, ic, TRUE);
8078
8079   /* get the string representation of the name */
8080   l = aopGet (AOP (left), 0, FALSE, TRUE);
8081   size = AOP_SIZE (result);
8082   while (size--)
8083     {
8084       if (offset)
8085         sprintf (buffer, "(%s + %d)", l + 1, offset);
8086       else
8087         sprintf (buffer, "%s", l + 1);
8088       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8089     }
8090
8091   freeAsmop (left, NULL, ic, TRUE);
8092   freeAsmop (result, NULL, ic, TRUE);
8093 }
8094
8095 /*-----------------------------------------------------------------*/
8096 /* genNearPointerGet - emitcode for near pointer fetch             */
8097 /*-----------------------------------------------------------------*/
8098 static void
8099 genNearPointerGet (operand * left,
8100                    operand * result,
8101                    iCode * ic,
8102                    iCode * pi)
8103 {
8104   asmop *aop = NULL;
8105   regs *preg = NULL;
8106   char *rname;
8107   sym_link *rtype, *retype;
8108   sym_link *ltype = operandType (left);
8109   char buffer[80];
8110
8111   D(emitcode (";     genNearPointerGet",""));
8112
8113   rtype = operandType (result);
8114   retype = getSpec (rtype);
8115
8116   aopOp (left, ic, FALSE);
8117
8118   /* if left is rematerialisable and
8119      result is not bitfield variable type and
8120      the left is pointer to data space i.e
8121      lower 128 bytes of space */
8122   if (AOP_TYPE (left) == AOP_IMMD &&
8123       !IS_BITFIELD (retype) &&
8124       DCL_TYPE (ltype) == POINTER)
8125     {
8126       genDataPointerGet (left, result, ic);
8127       return;
8128     }
8129
8130  /* if the value is already in a pointer register
8131      then don't need anything more */
8132   if (!AOP_INPREG (AOP (left)))
8133     {
8134       if (IS_AOP_PREG (left))
8135         {
8136           // Aha, it is a pointer, just in disguise.
8137           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8138           if (*rname != '@')
8139             {
8140               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8141                       __FILE__, __LINE__);
8142             }
8143           else
8144             {
8145               // Expected case.
8146               emitcode ("mov", "a%s,%s", rname + 1, rname);
8147               rname++;  // skip the '@'.
8148             }
8149         }
8150       else
8151         {
8152           /* otherwise get a free pointer register */
8153           aop = newAsmop (0);
8154           preg = getFreePtr (ic, &aop, FALSE);
8155           emitcode ("mov", "%s,%s",
8156                     preg->name,
8157                     aopGet (AOP (left), 0, FALSE, TRUE));
8158           rname = preg->name;
8159         }
8160     }
8161   else
8162     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8163
8164   //aopOp (result, ic, FALSE);
8165   aopOp (result, ic, result?TRUE:FALSE);
8166
8167   /* if bitfield then unpack the bits */
8168   if (IS_BITFIELD (retype))
8169     genUnpackBits (result, rname, POINTER);
8170   else
8171     {
8172       /* we have can just get the values */
8173       int size = AOP_SIZE (result);
8174       int offset = 0;
8175
8176       while (size--)
8177         {
8178           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8179             {
8180
8181               emitcode ("mov", "a,@%s", rname);
8182               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8183             }
8184           else
8185             {
8186               sprintf (buffer, "@%s", rname);
8187               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8188             }
8189           offset++;
8190           if (size || pi)
8191             emitcode ("inc", "%s", rname);
8192         }
8193     }
8194
8195   /* now some housekeeping stuff */
8196   if (aop)       /* we had to allocate for this iCode */
8197     {
8198       if (pi) { /* post increment present */
8199         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8200       }
8201       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8202     }
8203   else
8204     {
8205       /* we did not allocate which means left
8206          already in a pointer register, then
8207          if size > 0 && this could be used again
8208          we have to point it back to where it
8209          belongs */
8210       if ((AOP_SIZE (result) > 1 &&
8211            !OP_SYMBOL (left)->remat &&
8212            (OP_SYMBOL (left)->liveTo > ic->seq ||
8213             ic->depth)) &&
8214           !pi)
8215         {
8216           int size = AOP_SIZE (result) - 1;
8217           while (size--)
8218             emitcode ("dec", "%s", rname);
8219         }
8220     }
8221
8222   /* done */
8223   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8224   freeAsmop (left, NULL, ic, TRUE);
8225   if (pi) pi->generated = 1;
8226 }
8227
8228 /*-----------------------------------------------------------------*/
8229 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8230 /*-----------------------------------------------------------------*/
8231 static void
8232 genPagedPointerGet (operand * left,
8233                     operand * result,
8234                     iCode * ic,
8235                     iCode *pi)
8236 {
8237   asmop *aop = NULL;
8238   regs *preg = NULL;
8239   char *rname;
8240   sym_link *rtype, *retype;
8241
8242   D(emitcode (";     genPagedPointerGet",""));
8243
8244   rtype = operandType (result);
8245   retype = getSpec (rtype);
8246
8247   aopOp (left, ic, FALSE);
8248
8249   /* if the value is already in a pointer register
8250      then don't need anything more */
8251   if (!AOP_INPREG (AOP (left)))
8252     {
8253       /* otherwise get a free pointer register */
8254       aop = newAsmop (0);
8255       preg = getFreePtr (ic, &aop, FALSE);
8256       emitcode ("mov", "%s,%s",
8257                 preg->name,
8258                 aopGet (AOP (left), 0, FALSE, TRUE));
8259       rname = preg->name;
8260     }
8261   else
8262     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8263
8264   aopOp (result, ic, FALSE);
8265
8266   /* if bitfield then unpack the bits */
8267   if (IS_BITFIELD (retype))
8268     genUnpackBits (result, rname, PPOINTER);
8269   else
8270     {
8271       /* we have can just get the values */
8272       int size = AOP_SIZE (result);
8273       int offset = 0;
8274
8275       while (size--)
8276         {
8277
8278           emitcode ("movx", "a,@%s", rname);
8279           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8280
8281           offset++;
8282
8283           if (size || pi)
8284             emitcode ("inc", "%s", rname);
8285         }
8286     }
8287
8288   /* now some housekeeping stuff */
8289   if (aop) /* we had to allocate for this iCode */
8290     {
8291       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8292       freeAsmop (NULL, aop, ic, TRUE);
8293     }
8294   else
8295     {
8296       /* we did not allocate which means left
8297          already in a pointer register, then
8298          if size > 0 && this could be used again
8299          we have to point it back to where it
8300          belongs */
8301       if ((AOP_SIZE (result) > 1 &&
8302            !OP_SYMBOL (left)->remat &&
8303            (OP_SYMBOL (left)->liveTo > ic->seq ||
8304             ic->depth)) &&
8305           !pi)
8306         {
8307           int size = AOP_SIZE (result) - 1;
8308           while (size--)
8309             emitcode ("dec", "%s", rname);
8310         }
8311     }
8312
8313   /* done */
8314   freeAsmop (left, NULL, ic, TRUE);
8315   freeAsmop (result, NULL, ic, TRUE);
8316   if (pi) pi->generated = 1;
8317
8318 }
8319
8320 /*--------------------------------------------------------------------*/
8321 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8322 /*--------------------------------------------------------------------*/
8323 static void
8324 loadDptrFromOperand (operand *op, bool loadBToo)
8325 {
8326   if (AOP_TYPE (op) != AOP_STR)
8327     {
8328       /* if this is remateriazable */
8329       if (AOP_TYPE (op) == AOP_IMMD)
8330         {
8331           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8332           if (loadBToo)
8333             {
8334               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8335                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8336               else
8337                 {
8338                   wassertl(FALSE, "need pointerCode");
8339                   emitcode ("", "; mov b,???");
8340                   /* genPointerGet and genPointerSet originally did different
8341                   ** things for this case. Both seem wrong.
8342                   ** from genPointerGet:
8343                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8344                   ** from genPointerSet:
8345                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8346                   */
8347                 }
8348             }
8349         }
8350       else if (AOP_TYPE (op) == AOP_DPTR)
8351         {
8352           if (loadBToo)
8353             {
8354               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8355               emitcode ("push", "acc");
8356               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8357               emitcode ("push", "acc");
8358               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8359               emitcode ("pop", "dph");
8360               emitcode ("pop", "dpl");
8361             }
8362           else
8363             {
8364               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8365               emitcode ("push", "acc");
8366               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8367               emitcode ("pop", "dpl");
8368             }
8369         }
8370       else
8371         {                       /* we need to get it byte by byte */
8372           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8373           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8374           if (loadBToo)
8375             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8376         }
8377     }
8378 }
8379
8380 /*-----------------------------------------------------------------*/
8381 /* genFarPointerGet - gget value from far space                    */
8382 /*-----------------------------------------------------------------*/
8383 static void
8384 genFarPointerGet (operand * left,
8385                   operand * result, iCode * ic, iCode * pi)
8386 {
8387   int size, offset;
8388   sym_link *retype = getSpec (operandType (result));
8389
8390   D(emitcode (";     genFarPointerGet",""));
8391
8392   aopOp (left, ic, FALSE);
8393   loadDptrFromOperand (left, FALSE);
8394
8395   /* so dptr now contains the address */
8396   aopOp (result, ic, FALSE);
8397
8398   /* if bit then unpack */
8399   if (IS_BITFIELD (retype))
8400     genUnpackBits (result, "dptr", FPOINTER);
8401   else
8402     {
8403       size = AOP_SIZE (result);
8404       offset = 0;
8405
8406       while (size--)
8407         {
8408           emitcode ("movx", "a,@dptr");
8409           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8410           if (size || pi)
8411             emitcode ("inc", "dptr");
8412         }
8413     }
8414
8415   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8416     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8417     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8418     pi->generated = 1;
8419   }
8420   freeAsmop (left, NULL, ic, TRUE);
8421   freeAsmop (result, NULL, ic, TRUE);
8422 }
8423
8424 /*-----------------------------------------------------------------*/
8425 /* genCodePointerGet - gget value from code space                  */
8426 /*-----------------------------------------------------------------*/
8427 static void
8428 genCodePointerGet (operand * left,
8429                     operand * result, iCode * ic, iCode *pi)
8430 {
8431   int size, offset;
8432   sym_link *retype = getSpec (operandType (result));
8433
8434   D(emitcode (";     genCodePointerGet",""));
8435
8436   aopOp (left, ic, FALSE);
8437   loadDptrFromOperand (left, FALSE);
8438
8439   /* so dptr now contains the address */
8440   aopOp (result, ic, FALSE);
8441
8442   /* if bit then unpack */
8443   if (IS_BITFIELD (retype))
8444     genUnpackBits (result, "dptr", CPOINTER);
8445   else
8446     {
8447       size = AOP_SIZE (result);
8448       offset = 0;
8449
8450       while (size--)
8451         {
8452           if (pi)
8453             {
8454               emitcode ("clr", "a");
8455               emitcode ("movc", "a,@a+dptr");
8456               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8457               emitcode ("inc", "dptr");
8458             }
8459           else
8460             {
8461               emitcode ("mov", "a,#0x%02x", offset);
8462               emitcode ("movc", "a,@a+dptr");
8463               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8464             }
8465         }
8466     }
8467
8468   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8469     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8470     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8471     pi->generated = 1;
8472   }
8473   freeAsmop (left, NULL, ic, TRUE);
8474   freeAsmop (result, NULL, ic, TRUE);
8475 }
8476
8477 /*-----------------------------------------------------------------*/
8478 /* genGenPointerGet - gget value from generic pointer space        */
8479 /*-----------------------------------------------------------------*/
8480 static void
8481 genGenPointerGet (operand * left,
8482                   operand * result, iCode * ic, iCode *pi)
8483 {
8484   int size, offset;
8485   sym_link *retype = getSpec (operandType (result));
8486
8487   D(emitcode (";     genGenPointerGet",""));
8488
8489   aopOp (left, ic, FALSE);
8490   loadDptrFromOperand (left, TRUE);
8491
8492   /* so dptr know contains the address */
8493   aopOp (result, ic, FALSE);
8494
8495   /* if bit then unpack */
8496   if (IS_BITFIELD (retype))
8497     genUnpackBits (result, "dptr", GPOINTER);
8498   else
8499     {
8500       size = AOP_SIZE (result);
8501       offset = 0;
8502
8503       while (size--)
8504         {
8505           emitcode ("lcall", "__gptrget");
8506           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8507           if (size || pi)
8508             emitcode ("inc", "dptr");
8509         }
8510     }
8511
8512   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8513     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8514     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8515     pi->generated = 1;
8516   }
8517   freeAsmop (left, NULL, ic, TRUE);
8518   freeAsmop (result, NULL, ic, TRUE);
8519 }
8520
8521 /*-----------------------------------------------------------------*/
8522 /* genPointerGet - generate code for pointer get                   */
8523 /*-----------------------------------------------------------------*/
8524 static void
8525 genPointerGet (iCode * ic, iCode *pi)
8526 {
8527   operand *left, *result;
8528   sym_link *type, *etype;
8529   int p_type;
8530
8531   D(emitcode (";     genPointerGet",""));
8532
8533   left = IC_LEFT (ic);
8534   result = IC_RESULT (ic);
8535
8536   /* depending on the type of pointer we need to
8537      move it to the correct pointer register */
8538   type = operandType (left);
8539   etype = getSpec (type);
8540   /* if left is of type of pointer then it is simple */
8541   if (IS_PTR (type) && !IS_FUNC (type->next))
8542     p_type = DCL_TYPE (type);
8543   else
8544     {
8545       /* we have to go by the storage class */
8546       p_type = PTR_TYPE (SPEC_OCLS (etype));
8547     }
8548
8549   /* special case when cast remat */
8550   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8551       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8552           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8553           type = operandType (left);
8554           p_type = DCL_TYPE (type);
8555   }
8556   /* now that we have the pointer type we assign
8557      the pointer values */
8558   switch (p_type)
8559     {
8560
8561     case POINTER:
8562     case IPOINTER:
8563       genNearPointerGet (left, result, ic, pi);
8564       break;
8565
8566     case PPOINTER:
8567       genPagedPointerGet (left, result, ic, pi);
8568       break;
8569
8570     case FPOINTER:
8571       genFarPointerGet (left, result, ic, pi);
8572       break;
8573
8574     case CPOINTER:
8575       genCodePointerGet (left, result, ic, pi);
8576       break;
8577
8578     case GPOINTER:
8579       genGenPointerGet (left, result, ic, pi);
8580       break;
8581     }
8582
8583 }
8584
8585
8586
8587 /*-----------------------------------------------------------------*/
8588 /* genPackBits - generates code for packed bit storage             */
8589 /*-----------------------------------------------------------------*/
8590 static void
8591 genPackBits (sym_link * etype,
8592              operand * right,
8593              char *rname, int p_type)
8594 {
8595   int offset = 0;       /* source byte offset */
8596   int rlen = 0;         /* remaining bitfield length */
8597   int blen;             /* bitfield length */
8598   int bstr;             /* bitfield starting bit within byte */
8599   int litval;           /* source literal value (if AOP_LIT) */
8600   unsigned char mask;   /* bitmask within current byte */
8601
8602   D(emitcode (";     genPackBits",""));
8603
8604   blen = SPEC_BLEN (etype);
8605   bstr = SPEC_BSTR (etype);
8606
8607   /* If the bitfield length is less than a byte */
8608   if (blen < 8)
8609     {
8610       mask = ((unsigned char) (0xFF << (blen + bstr)) |
8611               (unsigned char) (0xFF >> (8 - bstr)));
8612
8613       if (AOP_TYPE (right) == AOP_LIT)
8614         {
8615           /* Case with a bitfield length <8 and literal source
8616           */
8617           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8618           litval <<= bstr;
8619           litval &= (~mask) & 0xff;
8620           emitPtrByteGet (rname, p_type, FALSE);
8621           if ((mask|litval)!=0xff)
8622             emitcode ("anl","a,#0x%02x", mask);
8623           if (litval)
8624             emitcode ("orl","a,#0x%02x", litval);
8625         }
8626       else
8627         {
8628           if ((blen==1) && (p_type!=GPOINTER))
8629             {
8630               /* Case with a bitfield length == 1 and no generic pointer
8631               */
8632               if (AOP_TYPE (right) == AOP_CRY)
8633                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
8634               else
8635                 {
8636                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8637                   emitcode ("rrc","a");
8638                 }
8639               emitPtrByteGet (rname, p_type, FALSE);
8640               emitcode ("mov","acc.%d,c",bstr);
8641             }
8642           else
8643             {
8644               /* Case with a bitfield length < 8 and arbitrary source
8645               */
8646               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8647               /* shift and mask source value */
8648               AccLsh (bstr);
8649               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8650
8651               /* transfer A to B and get next byte */
8652               emitPtrByteGet (rname, p_type, TRUE);
8653
8654               emitcode ("anl", "a,#0x%02x", mask);
8655               emitcode ("orl", "a,b");
8656               if (p_type == GPOINTER)
8657                 emitcode ("pop", "b");
8658            }
8659         }
8660
8661       emitPtrByteSet (rname, p_type, "a");
8662       return;
8663     }
8664
8665   /* Bit length is greater than 7 bits. In this case, copy  */
8666   /* all except the partial byte at the end                 */
8667   for (rlen=blen;rlen>=8;rlen-=8)
8668     {
8669       emitPtrByteSet (rname, p_type,
8670                       aopGet (AOP (right), offset++, FALSE, TRUE) );
8671       if (rlen>8)
8672         emitcode ("inc", "%s", rname);
8673     }
8674
8675   /* If there was a partial byte at the end */
8676   if (rlen)
8677     {
8678       mask = (((unsigned char) -1 << rlen) & 0xff);
8679
8680       if (AOP_TYPE (right) == AOP_LIT)
8681         {
8682           /* Case with partial byte and literal source
8683           */
8684           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8685           litval >>= (blen-rlen);
8686           litval &= (~mask) & 0xff;
8687           emitPtrByteGet (rname, p_type, FALSE);
8688           if ((mask|litval)!=0xff)
8689             emitcode ("anl","a,#0x%02x", mask);
8690           if (litval)
8691             emitcode ("orl","a,#0x%02x", litval);
8692         }
8693       else
8694         {
8695           /* Case with partial byte and arbitrary source
8696           */
8697           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
8698           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8699
8700           /* transfer A to B and get next byte */
8701           emitPtrByteGet (rname, p_type, TRUE);
8702
8703           emitcode ("anl", "a,#0x%02x", mask);
8704           emitcode ("orl", "a,b");
8705           if (p_type == GPOINTER)
8706             emitcode ("pop", "b");
8707         }
8708       emitPtrByteSet (rname, p_type, "a");
8709     }
8710
8711 }
8712
8713
8714 /*-----------------------------------------------------------------*/
8715 /* genDataPointerSet - remat pointer to data space                 */
8716 /*-----------------------------------------------------------------*/
8717 static void
8718 genDataPointerSet (operand * right,
8719                    operand * result,
8720                    iCode * ic)
8721 {
8722   int size, offset = 0;
8723   char *l, buffer[256];
8724
8725   D(emitcode (";     genDataPointerSet",""));
8726
8727   aopOp (right, ic, FALSE);
8728
8729   l = aopGet (AOP (result), 0, FALSE, TRUE);
8730   size = AOP_SIZE (right);
8731   while (size--)
8732     {
8733       if (offset)
8734         sprintf (buffer, "(%s + %d)", l + 1, offset);
8735       else
8736         sprintf (buffer, "%s", l + 1);
8737       emitcode ("mov", "%s,%s", buffer,
8738                 aopGet (AOP (right), offset++, FALSE, FALSE));
8739     }
8740
8741   freeAsmop (right, NULL, ic, TRUE);
8742   freeAsmop (result, NULL, ic, TRUE);
8743 }
8744
8745 /*-----------------------------------------------------------------*/
8746 /* genNearPointerSet - emitcode for near pointer put                */
8747 /*-----------------------------------------------------------------*/
8748 static void
8749 genNearPointerSet (operand * right,
8750                    operand * result,
8751                    iCode * ic,
8752                    iCode * pi)
8753 {
8754   asmop *aop = NULL;
8755   regs *preg = NULL;
8756   char *rname, *l;
8757   sym_link *retype, *letype;
8758   sym_link *ptype = operandType (result);
8759
8760   D(emitcode (";     genNearPointerSet",""));
8761
8762   retype = getSpec (operandType (right));
8763   letype = getSpec (ptype);
8764   aopOp (result, ic, FALSE);
8765
8766   /* if the result is rematerializable &
8767      in data space & not a bit variable */
8768   if (AOP_TYPE (result) == AOP_IMMD &&
8769       DCL_TYPE (ptype) == POINTER &&
8770       !IS_BITVAR (retype) &&
8771       !IS_BITVAR (letype))
8772     {
8773       genDataPointerSet (right, result, ic);
8774       return;
8775     }
8776
8777   /* if the value is already in a pointer register
8778      then don't need anything more */
8779   if (!AOP_INPREG (AOP (result)))
8780     {
8781         if (
8782             //AOP_TYPE (result) == AOP_STK
8783             IS_AOP_PREG(result)
8784             )
8785         {
8786             // Aha, it is a pointer, just in disguise.
8787             rname = aopGet (AOP (result), 0, FALSE, FALSE);
8788             if (*rname != '@')
8789             {
8790                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8791                         __FILE__, __LINE__);
8792             }
8793             else
8794             {
8795                 // Expected case.
8796                 emitcode ("mov", "a%s,%s", rname + 1, rname);
8797                 rname++;  // skip the '@'.
8798             }
8799         }
8800         else
8801         {
8802             /* otherwise get a free pointer register */
8803             aop = newAsmop (0);
8804             preg = getFreePtr (ic, &aop, FALSE);
8805             emitcode ("mov", "%s,%s",
8806                       preg->name,
8807                       aopGet (AOP (result), 0, FALSE, TRUE));
8808             rname = preg->name;
8809         }
8810     }
8811     else
8812     {
8813         rname = aopGet (AOP (result), 0, FALSE, FALSE);
8814     }
8815
8816   aopOp (right, ic, FALSE);
8817
8818   /* if bitfield then unpack the bits */
8819   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8820     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
8821   else
8822     {
8823       /* we have can just get the values */
8824       int size = AOP_SIZE (right);
8825       int offset = 0;
8826
8827       while (size--)
8828         {
8829           l = aopGet (AOP (right), offset, FALSE, TRUE);
8830           if (*l == '@')
8831             {
8832               MOVA (l);
8833               emitcode ("mov", "@%s,a", rname);
8834             }
8835           else
8836             emitcode ("mov", "@%s,%s", rname, l);
8837           if (size || pi)
8838             emitcode ("inc", "%s", rname);
8839           offset++;
8840         }
8841     }
8842
8843   /* now some housekeeping stuff */
8844   if (aop) /* we had to allocate for this iCode */
8845     {
8846       if (pi)
8847         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8848       freeAsmop (NULL, aop, ic, TRUE);
8849     }
8850   else
8851     {
8852       /* we did not allocate which means left
8853          already in a pointer register, then
8854          if size > 0 && this could be used again
8855          we have to point it back to where it
8856          belongs */
8857       if ((AOP_SIZE (right) > 1 &&
8858            !OP_SYMBOL (result)->remat &&
8859            (OP_SYMBOL (result)->liveTo > ic->seq ||
8860             ic->depth)) &&
8861           !pi)
8862         {
8863           int size = AOP_SIZE (right) - 1;
8864           while (size--)
8865             emitcode ("dec", "%s", rname);
8866         }
8867     }
8868
8869   /* done */
8870   if (pi) pi->generated = 1;
8871   freeAsmop (result, NULL, ic, TRUE);
8872   freeAsmop (right, NULL, ic, TRUE);
8873 }
8874
8875 /*-----------------------------------------------------------------*/
8876 /* genPagedPointerSet - emitcode for Paged pointer put             */
8877 /*-----------------------------------------------------------------*/
8878 static void
8879 genPagedPointerSet (operand * right,
8880                     operand * result,
8881                     iCode * ic,
8882                     iCode * pi)
8883 {
8884   asmop *aop = NULL;
8885   regs *preg = NULL;
8886   char *rname, *l;
8887   sym_link *retype, *letype;
8888
8889   D(emitcode (";     genPagedPointerSet",""));
8890
8891   retype = getSpec (operandType (right));
8892   letype = getSpec (operandType (result));
8893
8894   aopOp (result, ic, FALSE);
8895
8896   /* if the value is already in a pointer register
8897      then don't need anything more */
8898   if (!AOP_INPREG (AOP (result)))
8899     {
8900       /* otherwise get a free pointer register */
8901       aop = newAsmop (0);
8902       preg = getFreePtr (ic, &aop, FALSE);
8903       emitcode ("mov", "%s,%s",
8904                 preg->name,
8905                 aopGet (AOP (result), 0, FALSE, TRUE));
8906       rname = preg->name;
8907     }
8908   else
8909     rname = aopGet (AOP (result), 0, FALSE, FALSE);
8910
8911   aopOp (right, ic, FALSE);
8912
8913   /* if bitfield then unpack the bits */
8914   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8915     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
8916   else
8917     {
8918       /* we have can just get the values */
8919       int size = AOP_SIZE (right);
8920       int offset = 0;
8921
8922       while (size--)
8923         {
8924           l = aopGet (AOP (right), offset, FALSE, TRUE);
8925
8926           MOVA (l);
8927           emitcode ("movx", "@%s,a", rname);
8928
8929           if (size || pi)
8930             emitcode ("inc", "%s", rname);
8931
8932           offset++;
8933         }
8934     }
8935
8936   /* now some housekeeping stuff */
8937   if (aop) /* we had to allocate for this iCode */
8938     {
8939       if (pi)
8940         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8941       freeAsmop (NULL, aop, ic, TRUE);
8942     }
8943   else
8944     {
8945       /* we did not allocate which means left
8946          already in a pointer register, then
8947          if size > 0 && this could be used again
8948          we have to point it back to where it
8949          belongs */
8950       if (AOP_SIZE (right) > 1 &&
8951           !OP_SYMBOL (result)->remat &&
8952           (OP_SYMBOL (result)->liveTo > ic->seq ||
8953            ic->depth))
8954         {
8955           int size = AOP_SIZE (right) - 1;
8956           while (size--)
8957             emitcode ("dec", "%s", rname);
8958         }
8959     }
8960
8961   /* done */
8962   if (pi) pi->generated = 1;
8963   freeAsmop (result, NULL, ic, TRUE);
8964   freeAsmop (right, NULL, ic, TRUE);
8965
8966
8967 }
8968
8969 /*-----------------------------------------------------------------*/
8970 /* genFarPointerSet - set value from far space                     */
8971 /*-----------------------------------------------------------------*/
8972 static void
8973 genFarPointerSet (operand * right,
8974                   operand * result, iCode * ic, iCode * pi)
8975 {
8976   int size, offset;
8977   sym_link *retype = getSpec (operandType (right));
8978   sym_link *letype = getSpec (operandType (result));
8979
8980   D(emitcode (";     genFarPointerSet",""));
8981
8982   aopOp (result, ic, FALSE);
8983   loadDptrFromOperand (result, FALSE);
8984
8985   /* so dptr know contains the address */
8986   aopOp (right, ic, FALSE);
8987
8988   /* if bit then unpack */
8989   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8990     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
8991   else
8992     {
8993       size = AOP_SIZE (right);
8994       offset = 0;
8995
8996       while (size--)
8997         {
8998           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
8999           MOVA (l);
9000           emitcode ("movx", "@dptr,a");
9001           if (size || pi)
9002             emitcode ("inc", "dptr");
9003         }
9004     }
9005   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9006     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9007     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9008     pi->generated=1;
9009   }
9010   freeAsmop (result, NULL, ic, TRUE);
9011   freeAsmop (right, NULL, ic, TRUE);
9012 }
9013
9014 /*-----------------------------------------------------------------*/
9015 /* genGenPointerSet - set value from generic pointer space         */
9016 /*-----------------------------------------------------------------*/
9017 static void
9018 genGenPointerSet (operand * right,
9019                   operand * result, iCode * ic, iCode * pi)
9020 {
9021   int size, offset;
9022   sym_link *retype = getSpec (operandType (right));
9023   sym_link *letype = getSpec (operandType (result));
9024
9025   D(emitcode (";     genGenPointerSet",""));
9026
9027   aopOp (result, ic, FALSE);
9028   loadDptrFromOperand (result, TRUE);
9029
9030   /* so dptr know contains the address */
9031   aopOp (right, ic, FALSE);
9032
9033   /* if bit then unpack */
9034   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9035     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9036   else
9037     {
9038       size = AOP_SIZE (right);
9039       offset = 0;
9040
9041       while (size--)
9042         {
9043           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9044           MOVA (l);
9045           emitcode ("lcall", "__gptrput");
9046           if (size || pi)
9047             emitcode ("inc", "dptr");
9048         }
9049     }
9050
9051   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9052     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9053     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9054     pi->generated=1;
9055   }
9056   freeAsmop (result, NULL, ic, TRUE);
9057   freeAsmop (right, NULL, ic, TRUE);
9058 }
9059
9060 /*-----------------------------------------------------------------*/
9061 /* genPointerSet - stores the value into a pointer location        */
9062 /*-----------------------------------------------------------------*/
9063 static void
9064 genPointerSet (iCode * ic, iCode *pi)
9065 {
9066   operand *right, *result;
9067   sym_link *type, *etype;
9068   int p_type;
9069
9070   D(emitcode (";     genPointerSet",""));
9071
9072   right = IC_RIGHT (ic);
9073   result = IC_RESULT (ic);
9074
9075   /* depending on the type of pointer we need to
9076      move it to the correct pointer register */
9077   type = operandType (result);
9078   etype = getSpec (type);
9079   /* if left is of type of pointer then it is simple */
9080   if (IS_PTR (type) && !IS_FUNC (type->next))
9081     {
9082       p_type = DCL_TYPE (type);
9083     }
9084   else
9085     {
9086       /* we have to go by the storage class */
9087       p_type = PTR_TYPE (SPEC_OCLS (etype));
9088     }
9089
9090   /* special case when cast remat */
9091   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9092       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9093           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9094           type = operandType (result);
9095           p_type = DCL_TYPE (type);
9096   }
9097   /* now that we have the pointer type we assign
9098      the pointer values */
9099   switch (p_type)
9100     {
9101
9102     case POINTER:
9103     case IPOINTER:
9104       genNearPointerSet (right, result, ic, pi);
9105       break;
9106
9107     case PPOINTER:
9108       genPagedPointerSet (right, result, ic, pi);
9109       break;
9110
9111     case FPOINTER:
9112       genFarPointerSet (right, result, ic, pi);
9113       break;
9114
9115     case GPOINTER:
9116       genGenPointerSet (right, result, ic, pi);
9117       break;
9118
9119     default:
9120       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9121               "genPointerSet: illegal pointer type");
9122     }
9123
9124 }
9125
9126 /*-----------------------------------------------------------------*/
9127 /* genIfx - generate code for Ifx statement                        */
9128 /*-----------------------------------------------------------------*/
9129 static void
9130 genIfx (iCode * ic, iCode * popIc)
9131 {
9132   operand *cond = IC_COND (ic);
9133   int isbit = 0;
9134
9135   D(emitcode (";     genIfx",""));
9136
9137   aopOp (cond, ic, FALSE);
9138
9139   /* get the value into acc */
9140   if (AOP_TYPE (cond) != AOP_CRY)
9141     toBoolean (cond);
9142   else
9143     isbit = 1;
9144   /* the result is now in the accumulator */
9145   freeAsmop (cond, NULL, ic, TRUE);
9146
9147   /* if there was something to be popped then do it */
9148   if (popIc)
9149     genIpop (popIc);
9150
9151   /* if the condition is  a bit variable */
9152   if (isbit && IS_ITEMP (cond) &&
9153       SPIL_LOC (cond))
9154     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9155   else if (isbit && !IS_ITEMP (cond))
9156     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9157   else
9158     genIfxJump (ic, "a", NULL, NULL, NULL);
9159
9160   ic->generated = 1;
9161 }
9162
9163 /*-----------------------------------------------------------------*/
9164 /* genAddrOf - generates code for address of                       */
9165 /*-----------------------------------------------------------------*/
9166 static void
9167 genAddrOf (iCode * ic)
9168 {
9169   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9170   int size, offset;
9171
9172   D(emitcode (";     genAddrOf",""));
9173
9174   aopOp (IC_RESULT (ic), ic, FALSE);
9175
9176   /* if the operand is on the stack then we
9177      need to get the stack offset of this
9178      variable */
9179   if (sym->onStack)
9180     {
9181       /* if it has an offset then we need to compute
9182          it */
9183       if (sym->stack)
9184         {
9185           emitcode ("mov", "a,_bp");
9186           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9187                                          ((char) (sym->stack - _G.nRegsSaved)) :
9188                                          ((char) sym->stack)) & 0xff);
9189           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9190         }
9191       else
9192         {
9193           /* we can just move _bp */
9194           aopPut (AOP (IC_RESULT (ic)), "_bp", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9195         }
9196       /* fill the result with zero */
9197       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9198
9199       offset = 1;
9200       while (size--)
9201         {
9202           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9203         }
9204
9205       goto release;
9206     }
9207
9208   /* object not on stack then we need the name */
9209   size = AOP_SIZE (IC_RESULT (ic));
9210   offset = 0;
9211
9212   while (size--)
9213     {
9214       char s[SDCC_NAME_MAX];
9215       if (offset)
9216         sprintf (s, "#(%s >> %d)",
9217                  sym->rname,
9218                  offset * 8);
9219       else
9220         sprintf (s, "#%s", sym->rname);
9221       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9222     }
9223
9224 release:
9225   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9226
9227 }
9228
9229 /*-----------------------------------------------------------------*/
9230 /* genFarFarAssign - assignment when both are in far space         */
9231 /*-----------------------------------------------------------------*/
9232 static void
9233 genFarFarAssign (operand * result, operand * right, iCode * ic)
9234 {
9235   int size = AOP_SIZE (right);
9236   int offset = 0;
9237   char *l;
9238
9239   D(emitcode (";     genFarFarAssign",""));
9240
9241   /* first push the right side on to the stack */
9242   while (size--)
9243     {
9244       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9245       MOVA (l);
9246       emitcode ("push", "acc");
9247     }
9248
9249   freeAsmop (right, NULL, ic, FALSE);
9250   /* now assign DPTR to result */
9251   aopOp (result, ic, FALSE);
9252   size = AOP_SIZE (result);
9253   while (size--)
9254     {
9255       emitcode ("pop", "acc");
9256       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9257     }
9258   freeAsmop (result, NULL, ic, FALSE);
9259
9260 }
9261
9262 /*-----------------------------------------------------------------*/
9263 /* genAssign - generate code for assignment                        */
9264 /*-----------------------------------------------------------------*/
9265 static void
9266 genAssign (iCode * ic)
9267 {
9268   operand *result, *right;
9269   int size, offset;
9270   unsigned long lit = 0L;
9271
9272   D(emitcode(";     genAssign",""));
9273
9274   result = IC_RESULT (ic);
9275   right = IC_RIGHT (ic);
9276
9277   /* if they are the same */
9278   if (operandsEqu (result, right) &&
9279       !isOperandVolatile (result, FALSE) &&
9280       !isOperandVolatile (right, FALSE))
9281     return;
9282
9283   aopOp (right, ic, FALSE);
9284
9285   /* special case both in far space */
9286   if (AOP_TYPE (right) == AOP_DPTR &&
9287       IS_TRUE_SYMOP (result) &&
9288       isOperandInFarSpace (result))
9289     {
9290
9291       genFarFarAssign (result, right, ic);
9292       return;
9293     }
9294
9295   aopOp (result, ic, TRUE);
9296
9297   /* if they are the same registers */
9298   if (sameRegs (AOP (right), AOP (result)) &&
9299       !isOperandVolatile (result, FALSE) &&
9300       !isOperandVolatile (right, FALSE))
9301     goto release;
9302
9303   /* if the result is a bit */
9304   if (AOP_TYPE (result) == AOP_CRY)
9305     {
9306
9307       /* if the right size is a literal then
9308          we know what the value is */
9309       if (AOP_TYPE (right) == AOP_LIT)
9310         {
9311           if (((int) operandLitValue (right)))
9312             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9313           else
9314             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9315           goto release;
9316         }
9317
9318       /* the right is also a bit variable */
9319       if (AOP_TYPE (right) == AOP_CRY)
9320         {
9321           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9322           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9323           goto release;
9324         }
9325
9326       /* we need to or */
9327       toBoolean (right);
9328       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9329       goto release;
9330     }
9331
9332   /* bit variables done */
9333   /* general case */
9334   size = AOP_SIZE (result);
9335   offset = 0;
9336   if (AOP_TYPE (right) == AOP_LIT)
9337     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9338   if ((size > 1) &&
9339       (AOP_TYPE (result) != AOP_REG) &&
9340       (AOP_TYPE (right) == AOP_LIT) &&
9341       !IS_FLOAT (operandType (right)) &&
9342       (lit < 256L))
9343     {
9344       emitcode ("clr", "a");
9345       while (size--)
9346         {
9347           if ((unsigned int) ((lit >> (size * 8)) & 0x0FFL) == 0)
9348             aopPut (AOP (result), "a", size, isOperandVolatile (result, FALSE));
9349           else
9350             aopPut (AOP (result),
9351                     aopGet (AOP (right), size, FALSE, FALSE),
9352                     size,
9353                     isOperandVolatile (result, FALSE));
9354         }
9355     }
9356   else
9357     {
9358       while (size--)
9359         {
9360           aopPut (AOP (result),
9361                   aopGet (AOP (right), offset, FALSE, FALSE),
9362                   offset,
9363                   isOperandVolatile (result, FALSE));
9364           offset++;
9365         }
9366     }
9367
9368 release:
9369   freeAsmop (right, NULL, ic, TRUE);
9370   freeAsmop (result, NULL, ic, TRUE);
9371 }
9372
9373 /*-----------------------------------------------------------------*/
9374 /* genJumpTab - genrates code for jump table                       */
9375 /*-----------------------------------------------------------------*/
9376 static void
9377 genJumpTab (iCode * ic)
9378 {
9379   symbol *jtab;
9380   char *l;
9381
9382   D(emitcode (";     genJumpTab",""));
9383
9384   aopOp (IC_JTCOND (ic), ic, FALSE);
9385   /* get the condition into accumulator */
9386   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9387   MOVA (l);
9388   /* multiply by three */
9389   emitcode ("add", "a,acc");
9390   emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9391   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9392
9393   jtab = newiTempLabel (NULL);
9394   emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9395   emitcode ("jmp", "@a+dptr");
9396   emitcode ("", "%05d$:", jtab->key + 100);
9397   /* now generate the jump labels */
9398   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9399        jtab = setNextItem (IC_JTLABELS (ic)))
9400     emitcode ("ljmp", "%05d$", jtab->key + 100);
9401
9402 }
9403
9404 /*-----------------------------------------------------------------*/
9405 /* genCast - gen code for casting                                  */
9406 /*-----------------------------------------------------------------*/
9407 static void
9408 genCast (iCode * ic)
9409 {
9410   operand *result = IC_RESULT (ic);
9411   sym_link *ctype = operandType (IC_LEFT (ic));
9412   sym_link *rtype = operandType (IC_RIGHT (ic));
9413   operand *right = IC_RIGHT (ic);
9414   int size, offset;
9415
9416   D(emitcode(";     genCast",""));
9417
9418   /* if they are equivalent then do nothing */
9419   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9420     return;
9421
9422   aopOp (right, ic, FALSE);
9423   aopOp (result, ic, FALSE);
9424
9425   /* if the result is a bit (and not a bitfield) */
9426   // if (AOP_TYPE (result) == AOP_CRY)
9427   if (IS_BITVAR (OP_SYMBOL (result)->type)
9428       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9429     {
9430       /* if the right size is a literal then
9431          we know what the value is */
9432       if (AOP_TYPE (right) == AOP_LIT)
9433         {
9434           if (((int) operandLitValue (right)))
9435             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9436           else
9437             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9438
9439           goto release;
9440         }
9441
9442       /* the right is also a bit variable */
9443       if (AOP_TYPE (right) == AOP_CRY)
9444         {
9445           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9446           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9447           goto release;
9448         }
9449
9450       /* we need to or */
9451       toBoolean (right);
9452       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9453       goto release;
9454     }
9455
9456
9457   /* if they are the same size : or less */
9458   if (AOP_SIZE (result) <= AOP_SIZE (right))
9459     {
9460
9461       /* if they are in the same place */
9462       if (sameRegs (AOP (right), AOP (result)))
9463         goto release;
9464
9465       /* if they in different places then copy */
9466       size = AOP_SIZE (result);
9467       offset = 0;
9468       while (size--)
9469         {
9470           aopPut (AOP (result),
9471                   aopGet (AOP (right), offset, FALSE, FALSE),
9472                   offset,
9473                   isOperandVolatile (result, FALSE));
9474           offset++;
9475         }
9476       goto release;
9477     }
9478
9479
9480   /* if the result is of type pointer */
9481   if (IS_PTR (ctype))
9482     {
9483
9484       int p_type;
9485       sym_link *type = operandType (right);
9486       sym_link *etype = getSpec (type);
9487
9488       /* pointer to generic pointer */
9489       if (IS_GENPTR (ctype))
9490         {
9491           if (IS_PTR (type))
9492             p_type = DCL_TYPE (type);
9493           else
9494             {
9495               if (SPEC_SCLS(etype)==S_REGISTER) {
9496                 // let's assume it is a generic pointer
9497                 p_type=GPOINTER;
9498               } else {
9499                 /* we have to go by the storage class */
9500                 p_type = PTR_TYPE (SPEC_OCLS (etype));
9501               }
9502             }
9503
9504           /* the first two bytes are known */
9505           size = GPTRSIZE - 1;
9506           offset = 0;
9507           while (size--)
9508             {
9509               aopPut (AOP (result),
9510                       aopGet (AOP (right), offset, FALSE, FALSE),
9511                       offset,
9512                       isOperandVolatile (result, FALSE));
9513               offset++;
9514             }
9515           /* the last byte depending on type */
9516             {
9517                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
9518                 char gpValStr[10];
9519
9520                 if (gpVal == -1)
9521                 {
9522                     // pointerTypeToGPByte will have bitched.
9523                     exit(1);
9524                 }
9525
9526                 sprintf(gpValStr, "#0x%d", gpVal);
9527                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
9528             }
9529           goto release;
9530         }
9531
9532       /* just copy the pointers */
9533       size = AOP_SIZE (result);
9534       offset = 0;
9535       while (size--)
9536         {
9537           aopPut (AOP (result),
9538                   aopGet (AOP (right), offset, FALSE, FALSE),
9539                   offset,
9540                   isOperandVolatile (result, FALSE));
9541           offset++;
9542         }
9543       goto release;
9544     }
9545
9546   /* so we now know that the size of destination is greater
9547      than the size of the source */
9548   /* we move to result for the size of source */
9549   size = AOP_SIZE (right);
9550   offset = 0;
9551   while (size--)
9552     {
9553       aopPut (AOP (result),
9554               aopGet (AOP (right), offset, FALSE, FALSE),
9555               offset,
9556               isOperandVolatile (result, FALSE));
9557       offset++;
9558     }
9559
9560   /* now depending on the sign of the source && destination */
9561   size = AOP_SIZE (result) - AOP_SIZE (right);
9562   /* if unsigned or not an integral type */
9563   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
9564     {
9565       while (size--)
9566         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
9567     }
9568   else
9569     {
9570       /* we need to extend the sign :{ */
9571       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
9572                         FALSE, FALSE);
9573       MOVA (l);
9574       emitcode ("rlc", "a");
9575       emitcode ("subb", "a,acc");
9576       while (size--)
9577         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
9578     }
9579
9580   /* we are done hurray !!!! */
9581
9582 release:
9583   freeAsmop (right, NULL, ic, TRUE);
9584   freeAsmop (result, NULL, ic, TRUE);
9585
9586 }
9587
9588 /*-----------------------------------------------------------------*/
9589 /* genDjnz - generate decrement & jump if not zero instrucion      */
9590 /*-----------------------------------------------------------------*/
9591 static int
9592 genDjnz (iCode * ic, iCode * ifx)
9593 {
9594   symbol *lbl, *lbl1;
9595   if (!ifx)
9596     return 0;
9597
9598   D(emitcode (";     genDjnz",""));
9599
9600   /* if the if condition has a false label
9601      then we cannot save */
9602   if (IC_FALSE (ifx))
9603     return 0;
9604
9605   /* if the minus is not of the form
9606      a = a - 1 */
9607   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
9608       !IS_OP_LITERAL (IC_RIGHT (ic)))
9609     return 0;
9610
9611   if (operandLitValue (IC_RIGHT (ic)) != 1)
9612     return 0;
9613
9614   /* if the size of this greater than one then no
9615      saving */
9616   if (getSize (operandType (IC_RESULT (ic))) > 1)
9617     return 0;
9618
9619   /* otherwise we can save BIG */
9620   lbl = newiTempLabel (NULL);
9621   lbl1 = newiTempLabel (NULL);
9622
9623   aopOp (IC_RESULT (ic), ic, FALSE);
9624
9625   if (AOP_NEEDSACC(IC_RESULT(ic)))
9626   {
9627       /* If the result is accessed indirectly via
9628        * the accumulator, we must explicitly write
9629        * it back after the decrement.
9630        */
9631       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
9632
9633       if (strcmp(rByte, "a"))
9634       {
9635            /* Something is hopelessly wrong */
9636            fprintf(stderr, "*** warning: internal error at %s:%d\n",
9637                    __FILE__, __LINE__);
9638            /* We can just give up; the generated code will be inefficient,
9639             * but what the hey.
9640             */
9641            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9642            return 0;
9643       }
9644       emitcode ("dec", "%s", rByte);
9645       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9646       emitcode ("jnz", "%05d$", lbl->key + 100);
9647   }
9648   else if (IS_AOP_PREG (IC_RESULT (ic)))
9649     {
9650       emitcode ("dec", "%s",
9651                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9652       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9653       emitcode ("jnz", "%05d$", lbl->key + 100);
9654     }
9655   else
9656     {
9657       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
9658                 lbl->key + 100);
9659     }
9660   emitcode ("sjmp", "%05d$", lbl1->key + 100);
9661   emitcode ("", "%05d$:", lbl->key + 100);
9662   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
9663   emitcode ("", "%05d$:", lbl1->key + 100);
9664
9665   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9666   ifx->generated = 1;
9667   return 1;
9668 }
9669
9670 /*-----------------------------------------------------------------*/
9671 /* genReceive - generate code for a receive iCode                  */
9672 /*-----------------------------------------------------------------*/
9673 static void
9674 genReceive (iCode * ic)
9675 {
9676     int size = getSize (operandType (IC_RESULT (ic)));
9677     int offset = 0;
9678   D(emitcode (";     genReceive",""));
9679
9680   if (ic->argreg == 1) { /* first parameter */
9681       if (isOperandInFarSpace (IC_RESULT (ic)) &&
9682           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
9683            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
9684
9685           regs *tempRegs[4];
9686           int receivingA = 0;
9687           int roffset = 0;
9688
9689           for (offset = 0; offset<size; offset++)
9690             if (!strcmp (fReturn[offset], "a"))
9691               receivingA = 1;
9692
9693           if (!receivingA)
9694             {
9695               if (size==1 || getTempRegs(tempRegs, size-1, ic))
9696                 {
9697                   for (offset = size-1; offset>0; offset--)
9698                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
9699                   emitcode("mov","a,%s", fReturn[0]);
9700                   _G.accInUse++;
9701                   aopOp (IC_RESULT (ic), ic, FALSE);
9702                   _G.accInUse--;
9703                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
9704                           isOperandVolatile (IC_RESULT (ic), FALSE));
9705                   for (offset = 1; offset<size; offset++)
9706                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
9707                             isOperandVolatile (IC_RESULT (ic), FALSE));
9708                   goto release;
9709                 }
9710             }
9711           else
9712             {
9713               if (getTempRegs(tempRegs, size, ic))
9714                 {
9715                   for (offset = 0; offset<size; offset++)
9716                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
9717                   aopOp (IC_RESULT (ic), ic, FALSE);
9718                   for (offset = 0; offset<size; offset++)
9719                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
9720                             isOperandVolatile (IC_RESULT (ic), FALSE));
9721                   goto release;
9722                 }
9723             }
9724
9725           offset = fReturnSizeMCS51 - size;
9726           while (size--) {
9727               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
9728                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
9729               offset++;
9730           }
9731           aopOp (IC_RESULT (ic), ic, FALSE);
9732           size = AOP_SIZE (IC_RESULT (ic));
9733           offset = 0;
9734           while (size--) {
9735               emitcode ("pop", "acc");
9736               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9737           }
9738
9739       } else {
9740           _G.accInUse++;
9741           aopOp (IC_RESULT (ic), ic, FALSE);
9742           _G.accInUse--;
9743           assignResultValue (IC_RESULT (ic));
9744       }
9745   } else { /* second receive onwards */
9746       int rb1off ;
9747       aopOp (IC_RESULT (ic), ic, FALSE);
9748       rb1off = ic->argreg;
9749       while (size--) {
9750           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9751       }
9752   }
9753
9754 release:
9755   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9756 }
9757
9758 /*-----------------------------------------------------------------*/
9759 /* genDummyRead - generate code for dummy read of volatiles        */
9760 /*-----------------------------------------------------------------*/
9761 static void
9762 genDummyRead (iCode * ic)
9763 {
9764   operand *op;
9765   int size, offset;
9766
9767   D(emitcode(";     genDummyRead",""));
9768
9769   op = IC_RIGHT (ic);
9770   if (op && IS_SYMOP (op))
9771     {
9772       aopOp (op, ic, FALSE);
9773
9774       /* if the result is a bit */
9775       if (AOP_TYPE (op) == AOP_CRY)
9776         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9777       else
9778         {
9779           /* bit variables done */
9780           /* general case */
9781           size = AOP_SIZE (op);
9782           offset = 0;
9783           while (size--)
9784           {
9785             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9786             offset++;
9787           }
9788         }
9789
9790       freeAsmop (op, NULL, ic, TRUE);
9791     }
9792
9793   op = IC_LEFT (ic);
9794   if (op && IS_SYMOP (op))
9795     {
9796       aopOp (op, ic, FALSE);
9797
9798       /* if the result is a bit */
9799       if (AOP_TYPE (op) == AOP_CRY)
9800         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9801       else
9802         {
9803           /* bit variables done */
9804           /* general case */
9805           size = AOP_SIZE (op);
9806           offset = 0;
9807           while (size--)
9808           {
9809             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9810             offset++;
9811           }
9812         }
9813
9814       freeAsmop (op, NULL, ic, TRUE);
9815     }
9816 }
9817
9818 /*-----------------------------------------------------------------*/
9819 /* genCritical - generate code for start of a critical sequence    */
9820 /*-----------------------------------------------------------------*/
9821 static void
9822 genCritical (iCode *ic)
9823 {
9824   symbol *tlbl = newiTempLabel (NULL);
9825
9826   D(emitcode(";     genCritical",""));
9827
9828   if (IC_RESULT (ic))
9829     aopOp (IC_RESULT (ic), ic, TRUE);
9830
9831   emitcode ("setb", "c");
9832   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
9833   emitcode ("clr", "c");
9834   emitcode ("", "%05d$:", (tlbl->key + 100));
9835
9836   if (IC_RESULT (ic))
9837     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
9838   else
9839     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
9840
9841   if (IC_RESULT (ic))
9842     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9843 }
9844
9845 /*-----------------------------------------------------------------*/
9846 /* genEndCritical - generate code for end of a critical sequence   */
9847 /*-----------------------------------------------------------------*/
9848 static void
9849 genEndCritical (iCode *ic)
9850 {
9851   D(emitcode(";     genEndCritical",""));
9852
9853   if (IC_RIGHT (ic))
9854     {
9855       aopOp (IC_RIGHT (ic), ic, FALSE);
9856       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
9857         {
9858           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
9859           emitcode ("mov", "ea,c");
9860         }
9861       else
9862         {
9863           MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
9864           emitcode ("rrc", "a");
9865           emitcode ("mov", "ea,c");
9866         }
9867       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
9868     }
9869   else
9870     {
9871       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
9872       emitcode ("mov", "ea,c");
9873     }
9874 }
9875
9876 /*-----------------------------------------------------------------*/
9877 /* gen51Code - generate code for 8051 based controllers            */
9878 /*-----------------------------------------------------------------*/
9879 void
9880 gen51Code (iCode * lic)
9881 {
9882   iCode *ic;
9883   int cln = 0;
9884   /* int cseq = 0; */
9885
9886   _G.currentFunc = NULL;
9887   lineHead = lineCurr = NULL;
9888
9889   /* print the allocation information */
9890   if (allocInfo && currFunc)
9891     printAllocInfo (currFunc, codeOutFile);
9892   /* if debug information required */
9893   if (options.debug && currFunc)
9894     {
9895       debugFile->writeFunction (currFunc, lic);
9896     }
9897   /* stack pointer name */
9898   if (options.useXstack)
9899     spname = "_spx";
9900   else
9901     spname = "sp";
9902
9903
9904   for (ic = lic; ic; ic = ic->next)
9905     {
9906       _G.current_iCode = ic;
9907
9908       if (ic->lineno && cln != ic->lineno)
9909         {
9910           if (options.debug)
9911             {
9912               debugFile->writeCLine(ic);
9913             }
9914           if (!options.noCcodeInAsm) {
9915             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
9916                       printCLine(ic->filename, ic->lineno));
9917           }
9918           cln = ic->lineno;
9919         }
9920       #if 0
9921       if (ic->seqPoint && ic->seqPoint != cseq)
9922         {
9923           emitcode ("", "; sequence point %d", ic->seqPoint);
9924           cseq = ic->seqPoint;
9925         }
9926       #endif
9927       if (options.iCodeInAsm) {
9928         char regsInUse[80];
9929         int i;
9930
9931         for (i=0; i<8; i++) {
9932           sprintf (&regsInUse[i],
9933                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
9934         }
9935         regsInUse[i]=0;
9936         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
9937       }
9938       /* if the result is marked as
9939          spilt and rematerializable or code for
9940          this has already been generated then
9941          do nothing */
9942       if (resultRemat (ic) || ic->generated)
9943         continue;
9944
9945       /* depending on the operation */
9946       switch (ic->op)
9947         {
9948         case '!':
9949           genNot (ic);
9950           break;
9951
9952         case '~':
9953           genCpl (ic);
9954           break;
9955
9956         case UNARYMINUS:
9957           genUminus (ic);
9958           break;
9959
9960         case IPUSH:
9961           genIpush (ic);
9962           break;
9963
9964         case IPOP:
9965           /* IPOP happens only when trying to restore a
9966              spilt live range, if there is an ifx statement
9967              following this pop then the if statement might
9968              be using some of the registers being popped which
9969              would destory the contents of the register so
9970              we need to check for this condition and handle it */
9971           if (ic->next &&
9972               ic->next->op == IFX &&
9973               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
9974             genIfx (ic->next, ic);
9975           else
9976             genIpop (ic);
9977           break;
9978
9979         case CALL:
9980           genCall (ic);
9981           break;
9982
9983         case PCALL:
9984           genPcall (ic);
9985           break;
9986
9987         case FUNCTION:
9988           genFunction (ic);
9989           break;
9990
9991         case ENDFUNCTION:
9992           genEndFunction (ic);
9993           break;
9994
9995         case RETURN:
9996           genRet (ic);
9997           break;
9998
9999         case LABEL:
10000           genLabel (ic);
10001           break;
10002
10003         case GOTO:
10004           genGoto (ic);
10005           break;
10006
10007         case '+':
10008           genPlus (ic);
10009           break;
10010
10011         case '-':
10012           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10013             genMinus (ic);
10014           break;
10015
10016         case '*':
10017           genMult (ic);
10018           break;
10019
10020         case '/':
10021           genDiv (ic);
10022           break;
10023
10024         case '%':
10025           genMod (ic);
10026           break;
10027
10028         case '>':
10029           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10030           break;
10031
10032         case '<':
10033           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10034           break;
10035
10036         case LE_OP:
10037         case GE_OP:
10038         case NE_OP:
10039
10040           /* note these two are xlated by algebraic equivalence
10041              during parsing SDCC.y */
10042           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10043                   "got '>=' or '<=' shouldn't have come here");
10044           break;
10045
10046         case EQ_OP:
10047           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10048           break;
10049
10050         case AND_OP:
10051           genAndOp (ic);
10052           break;
10053
10054         case OR_OP:
10055           genOrOp (ic);
10056           break;
10057
10058         case '^':
10059           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10060           break;
10061
10062         case '|':
10063           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10064           break;
10065
10066         case BITWISEAND:
10067           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10068           break;
10069
10070         case INLINEASM:
10071           genInline (ic);
10072           break;
10073
10074         case RRC:
10075           genRRC (ic);
10076           break;
10077
10078         case RLC:
10079           genRLC (ic);
10080           break;
10081
10082         case GETHBIT:
10083           genGetHbit (ic);
10084           break;
10085
10086         case LEFT_OP:
10087           genLeftShift (ic);
10088           break;
10089
10090         case RIGHT_OP:
10091           genRightShift (ic);
10092           break;
10093
10094         case GET_VALUE_AT_ADDRESS:
10095           genPointerGet (ic, hasInc(IC_LEFT(ic),ic,getSize(operandType(IC_RESULT(ic)))));
10096           break;
10097
10098         case '=':
10099           if (POINTER_SET (ic))
10100             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10101           else
10102             genAssign (ic);
10103           break;
10104
10105         case IFX:
10106           genIfx (ic, NULL);
10107           break;
10108
10109         case ADDRESS_OF:
10110           genAddrOf (ic);
10111           break;
10112
10113         case JUMPTABLE:
10114           genJumpTab (ic);
10115           break;
10116
10117         case CAST:
10118           genCast (ic);
10119           break;
10120
10121         case RECEIVE:
10122           genReceive (ic);
10123           break;
10124
10125         case SEND:
10126           addSet (&_G.sendSet, ic);
10127           break;
10128
10129         case DUMMY_READ_VOLATILE:
10130           genDummyRead (ic);
10131           break;
10132
10133         case CRITICAL:
10134           genCritical (ic);
10135           break;
10136
10137         case ENDCRITICAL:
10138           genEndCritical (ic);
10139           break;
10140
10141         case SWAP:
10142           genSwap (ic);
10143           break;
10144
10145         default:
10146           ic = ic;
10147         }
10148     }
10149
10150   _G.current_iCode = NULL;
10151
10152   /* now we are ready to call the
10153      peep hole optimizer */
10154   if (!options.nopeep)
10155     peepHole (&lineHead);
10156
10157   /* now do the actual printing */
10158   printLine (lineHead, codeOutFile);
10159   return;
10160 }