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