8e5f49cff20d9039d2c5830a34d92d8630473ea7
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   SDCCgen51.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 //#define D(x)
32 #define D(x) x
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "SDCCglobl.h"
39 #include "newalloc.h"
40
41 #include "common.h"
42 #include "SDCCpeeph.h"
43 #include "ralloc.h"
44 #include "gen.h"
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0x00";
55 static char *one = "#0x01";
56 static char *spname;
57
58 char *fReturn8051[] =
59 {"dpl", "dph", "b", "a"};
60 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
61 char **fReturn = fReturn8051;
62 static char *accUse[] =
63 {"a", "b"};
64
65 static unsigned short rbank = -1;
66
67 static struct
68   {
69     short r0Pushed;
70     short r1Pushed;
71     short r0InB;
72     short r1InB;
73     short accInUse;
74     short inLine;
75     short debugLine;
76     short nRegsSaved;
77     set *sendSet;
78     iCode *current_iCode;
79     symbol *currentFunc;
80   }
81 _G;
82
83 static char *rb1regs[] = {
84     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
85 };
86
87 extern int mcs51_ptrRegReq;
88 extern int mcs51_nRegs;
89 extern FILE *codeOutFile;
90 static void saveRBank (int, iCode *, bool);
91 #define RESULTONSTACK(x) \
92                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
93                          IC_RESULT(x)->aop->type == AOP_STK )
94
95 #define MOVA(x) mova(x)  /* use function to avoid multiple eval */
96 #define CLRC    emitcode("clr","c")
97 #define SETC    emitcode("setb","c")
98
99 static lineNode *lineHead = NULL;
100 static lineNode *lineCurr = NULL;
101
102 static unsigned char SLMask[] =
103 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
104  0xE0, 0xC0, 0x80, 0x00};
105 static unsigned char SRMask[] =
106 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
107  0x07, 0x03, 0x01, 0x00};
108
109 #define LSB     0
110 #define MSB16   1
111 #define MSB24   2
112 #define MSB32   3
113
114 /*-----------------------------------------------------------------*/
115 /* emitcode - writes the code into a file : for now it is simple    */
116 /*-----------------------------------------------------------------*/
117 static void
118 emitcode (char *inst, const char *fmt,...)
119 {
120   va_list ap;
121   char lb[INITIAL_INLINEASM];
122   char *lbp = lb;
123
124   va_start (ap, fmt);
125
126   if (inst && *inst)
127     {
128       if (fmt && *fmt)
129         sprintf (lb, "%s\t", inst);
130       else
131         sprintf (lb, "%s", inst);
132       vsprintf (lb + (strlen (lb)), fmt, ap);
133     }
134   else
135     vsprintf (lb, fmt, ap);
136
137   while (isspace (*lbp))
138     lbp++;
139
140   //printf ("%s\n", lb);
141   
142   if (lbp && *lbp)
143     lineCurr = (lineCurr ?
144                 connectLine (lineCurr, newLineNode (lb)) :
145                 (lineHead = newLineNode (lb)));
146   lineCurr->isInline = _G.inLine;
147   lineCurr->isDebug = _G.debugLine;
148   lineCurr->ic = _G.current_iCode;
149   lineCurr->isComment = (*lbp==';');
150   va_end (ap);
151 }
152
153 /*-----------------------------------------------------------------*/
154 /* mcs51_emitDebuggerSymbol - associate the current code location  */
155 /*   with a debugger symbol                                        */
156 /*-----------------------------------------------------------------*/
157 void
158 mcs51_emitDebuggerSymbol (char * debugSym)
159 {
160   _G.debugLine = 1;
161   emitcode ("", "%s ==.", debugSym);
162   _G.debugLine = 0;
163 }
164
165 /*-----------------------------------------------------------------*/
166 /* mova - moves specified value into accumulator                   */
167 /*-----------------------------------------------------------------*/
168 static void
169 mova (const char *x)
170 {
171   /* do some early peephole optimization */
172   if (!strcmp(x, "a") || !strcmp(x, "acc"))
173     return;
174
175   emitcode("mov","a,%s", x);
176 }
177
178 /*-----------------------------------------------------------------*/
179 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
180 /*-----------------------------------------------------------------*/
181 static regs *
182 getFreePtr (iCode * ic, asmop ** aopp, bool result)
183 {
184   bool r0iu = FALSE, r1iu = FALSE;
185   bool r0ou = FALSE, r1ou = FALSE;
186
187   /* the logic: if r0 & r1 used in the instruction
188      then we are in trouble otherwise */
189
190   /* first check if r0 & r1 are used by this
191      instruction, in which case we are in trouble */
192   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
193   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
194   if (r0iu && r1iu) {
195       goto endOfWorld;
196     }
197
198   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
199   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
200
201   /* if no usage of r0 then return it */
202   if (!r0iu && !r0ou)
203     {
204       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
205       (*aopp)->type = AOP_R0;
206
207       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
208     }
209
210   /* if no usage of r1 then return it */
211   if (!r1iu && !r1ou)
212     {
213       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
214       (*aopp)->type = AOP_R1;
215
216       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
217     }
218
219   /* now we know they both have usage */
220   /* if r0 not used in this instruction */
221   if (!r0iu)
222     {
223       /* push it if not already pushed */
224       if (ic->op == IPUSH)
225         {
226           emitcode ("mov", "b,%s",
227                     mcs51_regWithIdx (R0_IDX)->dname);
228           _G.r0InB++;
229         }
230       else if (!_G.r0Pushed)
231         {
232           emitcode ("push", "%s",
233                     mcs51_regWithIdx (R0_IDX)->dname);
234           _G.r0Pushed++;
235         }
236
237       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
238       (*aopp)->type = AOP_R0;
239
240       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
241     }
242
243   /* if r1 not used then */
244
245   if (!r1iu)
246     {
247       /* push it if not already pushed */
248       if (ic->op == IPUSH)
249         {
250           emitcode ("mov", "b,%s",
251                     mcs51_regWithIdx (R1_IDX)->dname);
252           _G.r1InB++;
253         }
254       else if (!_G.r1Pushed)
255         {
256           emitcode ("push", "%s",
257                     mcs51_regWithIdx (R1_IDX)->dname);
258           _G.r1Pushed++;
259         }
260
261       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
262       (*aopp)->type = AOP_R1;
263       return mcs51_regWithIdx (R1_IDX);
264     }
265 endOfWorld:
266   /* I said end of world, but not quite end of world yet */
267   if (result) {
268     /* we can push it on the stack */
269     (*aopp)->type = AOP_STK;
270     return NULL;
271   } else {
272     /* in the case that result AND left AND right needs a pointer reg
273        we can safely use the result's */
274     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
275       (*aopp)->type = AOP_R0;
276       return mcs51_regWithIdx (R0_IDX);
277     }
278     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
279       (*aopp)->type = AOP_R1;
280       return mcs51_regWithIdx (R1_IDX);
281     }
282   }
283
284   /* now this is REALLY the end of the world */
285   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
286           "getFreePtr should never reach here");
287   exit (1);
288 }
289
290
291 /*-----------------------------------------------------------------*/
292 /* getTempRegs - initialize an array of pointers to GPR registers */
293 /*               that are not in use. Returns 1 if the requested   */
294 /*               number of registers were available, 0 otherwise.  */
295 /*-----------------------------------------------------------------*/
296 int
297 getTempRegs(regs **tempRegs, int size, iCode *ic)
298 {
299   bitVect * freeRegs;
300   int i;
301   int offset;
302
303   if (!ic)
304     ic = _G.current_iCode;
305   if (!ic)
306     return 0;
307   if (!_G.currentFunc)
308     return 0;
309
310   freeRegs = newBitVect(8);
311   bitVectSetBit (freeRegs, R2_IDX);
312   bitVectSetBit (freeRegs, R3_IDX);
313   bitVectSetBit (freeRegs, R4_IDX);
314   bitVectSetBit (freeRegs, R5_IDX);
315   bitVectSetBit (freeRegs, R6_IDX);
316   bitVectSetBit (freeRegs, R7_IDX);
317
318   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
319     {
320       bitVect * newfreeRegs;
321       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
322       freeBitVect(freeRegs);
323       freeRegs = newfreeRegs;
324     }
325   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
326
327   offset = 0;
328   for (i=0; i<freeRegs->size; i++)
329     {
330       if (bitVectBitValue(freeRegs,i))
331         tempRegs[offset++] = mcs51_regWithIdx(i);
332       if (offset>=size)
333         {
334           freeBitVect(freeRegs);
335           return 1;
336         }
337     }
338
339   freeBitVect(freeRegs);
340   return 1;
341 }
342
343
344 /*-----------------------------------------------------------------*/
345 /* newAsmop - creates a new asmOp                                  */
346 /*-----------------------------------------------------------------*/
347 static asmop *
348 newAsmop (short type)
349 {
350   asmop *aop;
351
352   aop = Safe_calloc (1, sizeof (asmop));
353   aop->type = type;
354   return aop;
355 }
356
357 /*-----------------------------------------------------------------*/
358 /* pointerCode - returns the code for a pointer type               */
359 /*-----------------------------------------------------------------*/
360 static int
361 pointerCode (sym_link * etype)
362 {
363
364   return PTR_TYPE (SPEC_OCLS (etype));
365
366 }
367
368
369 /*-----------------------------------------------------------------*/
370 /* leftRightUseAcc - returns size of accumulator use by operands   */
371 /*-----------------------------------------------------------------*/
372 static int
373 leftRightUseAcc(iCode *ic)
374 {
375   operand *op;
376   int size;
377   int accuseSize = 0;
378   int accuse = 0;
379
380   if (!ic)
381     {
382       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
383               "null iCode pointer");
384       return 0;
385     }
386
387   if (ic->op == IFX)
388     {
389       op = IC_COND (ic);
390       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
391         {
392           accuse = 1;
393           size = getSize (OP_SYMBOL (op)->type);
394           if (size>accuseSize)
395             accuseSize = size;
396         }
397     }
398   else if (ic->op == JUMPTABLE)
399     {
400       op = IC_JTCOND (ic);
401       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
402         {
403           accuse = 1;
404           size = getSize (OP_SYMBOL (op)->type);
405           if (size>accuseSize)
406             accuseSize = size;
407         }
408     }
409   else
410     {
411       op = IC_LEFT (ic);
412       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
413         {
414           accuse = 1;
415           size = getSize (OP_SYMBOL (op)->type);
416           if (size>accuseSize)
417             accuseSize = size;
418         }
419       op = IC_RIGHT (ic);
420       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
421         {
422           accuse = 1;
423           size = getSize (OP_SYMBOL (op)->type);
424           if (size>accuseSize)
425             accuseSize = size;
426         }
427     }
428
429   if (accuseSize)
430     return accuseSize;
431   else
432     return accuse;
433 }
434
435
436 /*-----------------------------------------------------------------*/
437 /* aopForSym - for a true symbol                                   */
438 /*-----------------------------------------------------------------*/
439 static asmop *
440 aopForSym (iCode * ic, symbol * sym, bool result)
441 {
442   asmop *aop;
443   memmap *space;
444
445   wassertl (ic != NULL, "Got a null iCode");
446   wassertl (sym != NULL, "Got a null symbol");
447
448   space = SPEC_OCLS (sym->etype);
449
450   /* if already has one */
451   if (sym->aop)
452     return sym->aop;
453
454   /* assign depending on the storage class */
455   /* if it is on the stack or indirectly addressable */
456   /* space we need to assign either r0 or r1 to it   */
457   if (sym->onStack || sym->iaccess)
458     {
459       sym->aop = aop = newAsmop (0);
460       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
461       aop->size = getSize (sym->type);
462
463       /* now assign the address of the variable to
464          the pointer register */
465       if (aop->type != AOP_STK)
466         {
467
468           if (sym->onStack)
469             {
470               if (_G.accInUse || leftRightUseAcc (ic))
471                 emitcode ("push", "acc");
472
473               emitcode ("mov", "a,_bp");
474               emitcode ("add", "a,#0x%02x",
475                         ((sym->stack < 0) ?
476                          ((char) (sym->stack - _G.nRegsSaved)) :
477                          ((char) sym->stack)) & 0xff);
478               emitcode ("mov", "%s,a",
479                         aop->aopu.aop_ptr->name);
480
481               if (_G.accInUse || leftRightUseAcc (ic))
482                 emitcode ("pop", "acc");
483             }
484           else
485             emitcode ("mov", "%s,#%s",
486                       aop->aopu.aop_ptr->name,
487                       sym->rname);
488           aop->paged = space->paged;
489         }
490       else
491         aop->aopu.aop_stk = sym->stack;
492       return aop;
493     }
494
495   /* if in bit space */
496   if (IN_BITSPACE (space))
497     {
498       sym->aop = aop = newAsmop (AOP_CRY);
499       aop->aopu.aop_dir = sym->rname;
500       aop->size = getSize (sym->type);
501       return aop;
502     }
503   /* if it is in direct space */
504   if (IN_DIRSPACE (space))
505     {
506       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
507       //printTypeChainRaw(sym->type, NULL);
508       //printf("space = %s\n", space ? space->sname : "NULL");
509       sym->aop = aop = newAsmop (AOP_DIR);
510       aop->aopu.aop_dir = sym->rname;
511       aop->size = getSize (sym->type);
512       return aop;
513     }
514
515   /* special case for a function */
516   if (IS_FUNC (sym->type))
517     {
518       sym->aop = aop = newAsmop (AOP_IMMD);
519       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
520       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
521       aop->size = FPTRSIZE;
522       return aop;
523     }
524
525   /* only remaining is far space */
526   /* in which case DPTR gets the address */
527   sym->aop = aop = newAsmop (AOP_DPTR);
528   emitcode ("mov", "dptr,#%s", sym->rname);
529   aop->size = getSize (sym->type);
530
531   /* if it is in code space */
532   if (IN_CODESPACE (space))
533     aop->code = 1;
534
535   return aop;
536 }
537
538 /*-----------------------------------------------------------------*/
539 /* aopForRemat - rematerialzes an object                           */
540 /*-----------------------------------------------------------------*/
541 static asmop *
542 aopForRemat (symbol * sym)
543 {
544   iCode *ic = sym->rematiCode;
545   asmop *aop = newAsmop (AOP_IMMD);
546   int ptr_type=0;
547   int val = 0;
548
549   for (;;)
550     {
551       if (ic->op == '+')
552         val += (int) operandLitValue (IC_RIGHT (ic));
553       else if (ic->op == '-')
554         val -= (int) operandLitValue (IC_RIGHT (ic));
555       else if (IS_CAST_ICODE(ic)) {
556               sym_link *from_type = operandType(IC_RIGHT(ic));
557               aop->aopu.aop_immd.from_cast_remat = 1;
558               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
559               ptr_type = DCL_TYPE(from_type);
560               if (ptr_type == IPOINTER) {
561                 // bug #481053
562                 ptr_type = POINTER;
563               }
564               continue ;
565       } else break;
566
567       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
568     }
569
570   if (val)
571     sprintf (buffer, "(%s %c 0x%04x)",
572              OP_SYMBOL (IC_LEFT (ic))->rname,
573              val >= 0 ? '+' : '-',
574              abs (val) & 0xffff);
575   else
576     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
577
578   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
579   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
580   /* set immd2 field if required */
581   if (aop->aopu.aop_immd.from_cast_remat) {
582           sprintf(buffer,"#0x%02x",ptr_type);
583           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
584           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
585   }
586
587   return aop;
588 }
589
590 /*-----------------------------------------------------------------*/
591 /* regsInCommon - two operands have some registers in common       */
592 /*-----------------------------------------------------------------*/
593 static bool
594 regsInCommon (operand * op1, operand * op2)
595 {
596   symbol *sym1, *sym2;
597   int i;
598
599   /* if they have registers in common */
600   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
601     return FALSE;
602
603   sym1 = OP_SYMBOL (op1);
604   sym2 = OP_SYMBOL (op2);
605
606   if (sym1->nRegs == 0 || sym2->nRegs == 0)
607     return FALSE;
608
609   for (i = 0; i < sym1->nRegs; i++)
610     {
611       int j;
612       if (!sym1->regs[i])
613         continue;
614
615       for (j = 0; j < sym2->nRegs; j++)
616         {
617           if (!sym2->regs[j])
618             continue;
619
620           if (sym2->regs[j] == sym1->regs[i])
621             return TRUE;
622         }
623     }
624
625   return FALSE;
626 }
627
628 /*-----------------------------------------------------------------*/
629 /* operandsEqu - equivalent                                        */
630 /*-----------------------------------------------------------------*/
631 static bool
632 operandsEqu (operand * op1, operand * op2)
633 {
634   symbol *sym1, *sym2;
635
636   /* if they not symbols */
637   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
638     return FALSE;
639
640   sym1 = OP_SYMBOL (op1);
641   sym2 = OP_SYMBOL (op2);
642
643   /* if both are itemps & one is spilt
644      and the other is not then false */
645   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
646       sym1->isspilt != sym2->isspilt)
647     return FALSE;
648
649   /* if they are the same */
650   if (sym1 == sym2)
651     return TRUE;
652
653   if (sym1->rname[0] && sym2->rname[0]
654       && strcmp (sym1->rname, sym2->rname) == 0)
655     return TRUE;
656
657   /* if left is a tmp & right is not */
658   if (IS_ITEMP (op1) &&
659       !IS_ITEMP (op2) &&
660       sym1->isspilt &&
661       (sym1->usl.spillLoc == sym2))
662     return TRUE;
663
664   if (IS_ITEMP (op2) &&
665       !IS_ITEMP (op1) &&
666       sym2->isspilt &&
667       sym1->level > 0 &&
668       (sym2->usl.spillLoc == sym1))
669     return TRUE;
670
671   return FALSE;
672 }
673
674 /*-----------------------------------------------------------------*/
675 /* sameRegs - two asmops have the same registers                   */
676 /*-----------------------------------------------------------------*/
677 static bool
678 sameRegs (asmop * aop1, asmop * aop2)
679 {
680   int i;
681
682   if (aop1 == aop2)
683     return TRUE;
684
685   if (aop1->type != AOP_REG ||
686       aop2->type != AOP_REG)
687     return FALSE;
688
689   if (aop1->size != aop2->size)
690     return FALSE;
691
692   for (i = 0; i < aop1->size; i++)
693     if (aop1->aopu.aop_reg[i] !=
694         aop2->aopu.aop_reg[i])
695       return FALSE;
696
697   return TRUE;
698 }
699
700 /*-----------------------------------------------------------------*/
701 /* aopOp - allocates an asmop for an operand  :                    */
702 /*-----------------------------------------------------------------*/
703 static void
704 aopOp (operand * op, iCode * ic, bool result)
705 {
706   asmop *aop;
707   symbol *sym;
708   int i;
709
710   if (!op)
711     return;
712
713   /* if this a literal */
714   if (IS_OP_LITERAL (op))
715     {
716       op->aop = aop = newAsmop (AOP_LIT);
717       aop->aopu.aop_lit = op->operand.valOperand;
718       aop->size = getSize (operandType (op));
719       return;
720     }
721
722   /* if already has a asmop then continue */
723   if (op->aop )
724     return;
725
726   /* if the underlying symbol has a aop */
727   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
728     {
729       op->aop = OP_SYMBOL (op)->aop;
730       return;
731     }
732
733   /* if this is a true symbol */
734   if (IS_TRUE_SYMOP (op))
735     {
736       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
737       return;
738     }
739
740   /* this is a temporary : this has
741      only four choices :
742      a) register
743      b) spillocation
744      c) rematerialize
745      d) conditional
746      e) can be a return use only */
747
748   sym = OP_SYMBOL (op);
749
750   /* if the type is a conditional */
751   if (sym->regType == REG_CND)
752     {
753       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
754       aop->size = 0;
755       return;
756     }
757
758   /* if it is spilt then two situations
759      a) is rematerialize
760      b) has a spill location */
761   if (sym->isspilt || sym->nRegs == 0)
762     {
763
764       /* rematerialize it NOW */
765       if (sym->remat)
766         {
767           sym->aop = op->aop = aop =
768             aopForRemat (sym);
769           aop->size = getSize (sym->type);
770           return;
771         }
772
773       if (sym->accuse)
774         {
775           int i;
776           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
777           aop->size = getSize (sym->type);
778           for (i = 0; i < 2; i++)
779             aop->aopu.aop_str[i] = accUse[i];
780           return;
781         }
782
783       if (sym->ruonly)
784         {
785           unsigned i;
786
787           aop = op->aop = sym->aop = newAsmop (AOP_STR);
788           aop->size = getSize (sym->type);
789           for (i = 0; i < fReturnSizeMCS51; i++)
790             aop->aopu.aop_str[i] = fReturn[i];
791           return;
792         }
793
794       if (sym->usl.spillLoc)
795         {
796           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
797             {
798               /* force a new aop if sizes differ */
799               sym->usl.spillLoc->aop = NULL;
800             }
801           sym->aop = op->aop = aop =
802                      aopForSym (ic, sym->usl.spillLoc, result);
803           aop->size = getSize (sym->type);
804           return;
805         }
806
807       /* else must be a dummy iTemp */
808       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
809       aop->size = getSize (sym->type);
810       return;
811     }
812
813   /* must be in a register */
814   sym->aop = op->aop = aop = newAsmop (AOP_REG);
815   aop->size = sym->nRegs;
816   for (i = 0; i < sym->nRegs; i++)
817     aop->aopu.aop_reg[i] = sym->regs[i];
818 }
819
820 /*-----------------------------------------------------------------*/
821 /* freeAsmop - free up the asmop given to an operand               */
822 /*----------------------------------------------------------------*/
823 static void
824 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
825 {
826   asmop *aop;
827
828   if (!op)
829     aop = aaop;
830   else
831     aop = op->aop;
832
833   if (!aop)
834     return;
835
836   if (aop->freed)
837     goto dealloc;
838
839   aop->freed = 1;
840
841   /* depending on the asmop type only three cases need work AOP_RO
842      , AOP_R1 && AOP_STK */
843   switch (aop->type)
844     {
845     case AOP_R0:
846       if (_G.r0InB)
847         {
848           emitcode ("mov", "r0,b");
849           _G.r0InB--;
850         }
851       else if (_G.r0Pushed)
852         {
853           if (pop)
854             {
855               emitcode ("pop", "ar0");
856               _G.r0Pushed--;
857             }
858         }
859       bitVectUnSetBit (ic->rUsed, R0_IDX);
860       break;
861
862     case AOP_R1:
863       if (_G.r1InB)
864         {
865           emitcode ("mov", "r1,b");
866           _G.r1InB--;
867         }
868       if (_G.r1Pushed)
869         {
870           if (pop)
871             {
872               emitcode ("pop", "ar1");
873               _G.r1Pushed--;
874             }
875         }
876       bitVectUnSetBit (ic->rUsed, R1_IDX);
877       break;
878
879     case AOP_STK:
880       {
881         int sz = aop->size;
882         int stk = aop->aopu.aop_stk + aop->size - 1;
883         bitVectUnSetBit (ic->rUsed, R0_IDX);
884         bitVectUnSetBit (ic->rUsed, R1_IDX);
885
886         getFreePtr (ic, &aop, FALSE);
887
888         if (stk)
889           {
890             emitcode ("mov", "a,_bp");
891             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
892             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
893           }
894         else
895           {
896             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
897           }
898
899         while (sz--)
900           {
901             emitcode ("pop", "acc");
902             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
903             if (!sz)
904               break;
905             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
906           }
907         op->aop = aop;
908         freeAsmop (op, NULL, ic, TRUE);
909         if (_G.r1Pushed)
910           {
911             emitcode ("pop", "ar1");
912             _G.r1Pushed--;
913           }
914
915         if (_G.r0Pushed)
916           {
917             emitcode ("pop", "ar0");
918             _G.r0Pushed--;
919           }
920       }
921     }
922
923 dealloc:
924   /* all other cases just dealloc */
925   if (op)
926     {
927       op->aop = NULL;
928       if (IS_SYMOP (op))
929         {
930           OP_SYMBOL (op)->aop = NULL;
931           /* if the symbol has a spill */
932           if (SPIL_LOC (op))
933             SPIL_LOC (op)->aop = NULL;
934         }
935     }
936 }
937
938 /*------------------------------------------------------------------*/
939 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
940 /*                      pop r0 or r1 off stack if pushed            */
941 /*------------------------------------------------------------------*/
942 static void
943 freeForBranchAsmop (operand * op)
944 {
945   asmop *aop;
946
947   if (!op)
948     return;
949     
950   aop = op->aop;
951
952   if (!aop)
953     return;
954
955   if (aop->freed)
956     return;
957
958   switch (aop->type)
959     {
960     case AOP_R0:
961       if (_G.r0InB)
962         {
963           emitcode ("mov", "r0,b");
964         }
965       else if (_G.r0Pushed)
966         {
967           emitcode ("pop", "ar0");
968         }
969       break;
970
971     case AOP_R1:
972       if (_G.r1InB)
973         {
974           emitcode ("mov", "r1,b");
975         }
976       else if (_G.r1Pushed)
977         {
978           emitcode ("pop", "ar1");
979         }
980       break;
981
982     case AOP_STK:
983       {
984         int sz = aop->size;
985         int stk = aop->aopu.aop_stk + aop->size - 1;
986
987         emitcode ("mov", "b,r0");
988         if (stk)
989           {
990             emitcode ("mov", "a,_bp");
991             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
992             emitcode ("mov", "r0,a");
993           }
994         else
995           {
996             emitcode ("mov", "r0,_bp");
997           }
998
999         while (sz--)
1000           {
1001             emitcode ("pop", "acc");
1002             emitcode ("mov", "@r0,a");
1003             if (!sz)
1004               break;
1005             emitcode ("dec", "r0");
1006           }
1007         emitcode ("mov", "r0,b");
1008       }
1009     }
1010
1011 }
1012
1013 /*-----------------------------------------------------------------*/
1014 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1015 /*                 clobber the accumulator                         */
1016 /*-----------------------------------------------------------------*/
1017 static bool
1018 aopGetUsesAcc (asmop *aop, int offset)
1019 {
1020   if (offset > (aop->size - 1))
1021     return FALSE;
1022
1023   switch (aop->type)
1024     {
1025
1026     case AOP_R0:
1027     case AOP_R1:
1028       if (aop->paged)
1029         return TRUE;
1030       return FALSE;
1031     case AOP_DPTR:
1032       return TRUE;
1033     case AOP_IMMD:
1034       return FALSE;
1035     case AOP_DIR:
1036       return FALSE;
1037     case AOP_REG:
1038       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1039       return FALSE;
1040     case AOP_CRY:
1041       return TRUE;
1042     case AOP_ACC:
1043       return TRUE;
1044     case AOP_LIT:
1045       return FALSE;
1046     case AOP_STR:
1047       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1048         return TRUE;
1049       return FALSE;
1050     case AOP_DUMMY:
1051       return FALSE;
1052     default:
1053       /* Error case --- will have been caught already */
1054       wassert(0);
1055       return FALSE;
1056     }
1057 }
1058
1059 /*-----------------------------------------------------------------*/
1060 /* aopGet - for fetching value of the aop                          */
1061 /*-----------------------------------------------------------------*/
1062 static char *
1063 aopGet (asmop * aop, int offset, bool bit16, bool dname)
1064 {
1065   char *s = buffer;
1066   char *rs;
1067
1068   /* offset is greater than
1069      size then zero */
1070   if (offset > (aop->size - 1) &&
1071       aop->type != AOP_LIT)
1072     return zero;
1073
1074   /* depending on type */
1075   switch (aop->type)
1076     {
1077     case AOP_DUMMY:
1078       return zero;
1079
1080     case AOP_R0:
1081     case AOP_R1:
1082       /* if we need to increment it */
1083       while (offset > aop->coff)
1084         {
1085           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1086           aop->coff++;
1087         }
1088
1089       while (offset < aop->coff)
1090         {
1091           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1092           aop->coff--;
1093         }
1094
1095       aop->coff = offset;
1096       if (aop->paged)
1097         {
1098           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1099           return (dname ? "acc" : "a");
1100         }
1101       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1102       rs = Safe_calloc (1, strlen (s) + 1);
1103       strcpy (rs, s);
1104       return rs;
1105
1106     case AOP_DPTR:
1107       if (aop->code && aop->coff==0 && offset>=1) {
1108         emitcode ("mov", "a,#0x%02x", offset);
1109         emitcode ("movc", "a,@a+dptr");
1110         return (dname ? "acc" : "a");
1111       }
1112
1113       while (offset > aop->coff)
1114         {
1115           emitcode ("inc", "dptr");
1116           aop->coff++;
1117         }
1118
1119       while (offset < aop->coff)
1120         {
1121           emitcode ("lcall", "__decdptr");
1122           aop->coff--;
1123         }
1124
1125       aop->coff = offset;
1126       if (aop->code)
1127         {
1128           emitcode ("clr", "a");
1129           emitcode ("movc", "a,@a+dptr");
1130         }
1131       else
1132         {
1133           emitcode ("movx", "a,@dptr");
1134         }
1135       return (dname ? "acc" : "a");
1136
1137
1138     case AOP_IMMD:
1139       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1140               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1141       } else if (bit16)
1142         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1143       else if (offset)
1144         sprintf (s, "#(%s >> %d)",
1145                  aop->aopu.aop_immd.aop_immd1,
1146                  offset * 8);
1147       else
1148         sprintf (s, "#%s",
1149                  aop->aopu.aop_immd.aop_immd1);
1150       rs = Safe_calloc (1, strlen (s) + 1);
1151       strcpy (rs, s);
1152       return rs;
1153
1154     case AOP_DIR:
1155       if (offset)
1156         sprintf (s, "(%s + %d)",
1157                  aop->aopu.aop_dir,
1158                  offset);
1159       else
1160         sprintf (s, "%s", aop->aopu.aop_dir);
1161       rs = Safe_calloc (1, strlen (s) + 1);
1162       strcpy (rs, s);
1163       return rs;
1164
1165     case AOP_REG:
1166       if (dname)
1167         return aop->aopu.aop_reg[offset]->dname;
1168       else
1169         return aop->aopu.aop_reg[offset]->name;
1170
1171     case AOP_CRY:
1172       emitcode ("clr", "a");
1173       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1174       emitcode ("rlc", "a");
1175       return (dname ? "acc" : "a");
1176
1177     case AOP_ACC:
1178       if (!offset && dname)
1179         return "acc";
1180       return aop->aopu.aop_str[offset];
1181
1182     case AOP_LIT:
1183       return aopLiteral (aop->aopu.aop_lit, offset);
1184
1185     case AOP_STR:
1186       aop->coff = offset;
1187       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1188           dname)
1189         return "acc";
1190
1191       return aop->aopu.aop_str[offset];
1192
1193     }
1194
1195   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1196           "aopget got unsupported aop->type");
1197   exit (1);
1198 }
1199 /*-----------------------------------------------------------------*/
1200 /* aopPut - puts a string for a aop                                */
1201 /*-----------------------------------------------------------------*/
1202 static void
1203 aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
1204 {
1205   char *d = buffer;
1206
1207   if (aop->size && offset > (aop->size - 1))
1208     {
1209       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1210               "aopPut got offset > aop->size");
1211       exit (1);
1212     }
1213
1214   /* will assign value to value */
1215   /* depending on where it is ofcourse */
1216   switch (aop->type)
1217     {
1218     case AOP_DUMMY:
1219       MOVA (s);         /* read s in case it was volatile */
1220       break;
1221
1222     case AOP_DIR:
1223       if (offset)
1224         sprintf (d, "(%s + %d)",
1225                  aop->aopu.aop_dir, offset);
1226       else
1227         sprintf (d, "%s", aop->aopu.aop_dir);
1228
1229       if (strcmp (d, s) ||
1230           bvolatile)
1231         emitcode ("mov", "%s,%s", d, s);
1232
1233       break;
1234
1235     case AOP_REG:
1236       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1237           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1238         {
1239           if (*s == '@' ||
1240               strcmp (s, "r0") == 0 ||
1241               strcmp (s, "r1") == 0 ||
1242               strcmp (s, "r2") == 0 ||
1243               strcmp (s, "r3") == 0 ||
1244               strcmp (s, "r4") == 0 ||
1245               strcmp (s, "r5") == 0 ||
1246               strcmp (s, "r6") == 0 ||
1247               strcmp (s, "r7") == 0)
1248             emitcode ("mov", "%s,%s",
1249                       aop->aopu.aop_reg[offset]->dname, s);
1250           else
1251             emitcode ("mov", "%s,%s",
1252                       aop->aopu.aop_reg[offset]->name, s);
1253         }
1254       break;
1255
1256     case AOP_DPTR:
1257       if (aop->code)
1258         {
1259           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1260                   "aopPut writing to code space");
1261           exit (1);
1262         }
1263
1264       while (offset > aop->coff)
1265         {
1266           aop->coff++;
1267           emitcode ("inc", "dptr");
1268         }
1269
1270       while (offset < aop->coff)
1271         {
1272           aop->coff--;
1273           emitcode ("lcall", "__decdptr");
1274         }
1275
1276       aop->coff = offset;
1277
1278       /* if not in accumulater */
1279       MOVA (s);
1280
1281       emitcode ("movx", "@dptr,a");
1282       break;
1283
1284     case AOP_R0:
1285     case AOP_R1:
1286       while (offset > aop->coff)
1287         {
1288           aop->coff++;
1289           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1290         }
1291       while (offset < aop->coff)
1292         {
1293           aop->coff--;
1294           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1295         }
1296       aop->coff = offset;
1297
1298       if (aop->paged)
1299         {
1300           MOVA (s);
1301           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1302
1303         }
1304       else if (*s == '@')
1305         {
1306           MOVA (s);
1307           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1308         }
1309       else if (strcmp (s, "r0") == 0 ||
1310                strcmp (s, "r1") == 0 ||
1311                strcmp (s, "r2") == 0 ||
1312                strcmp (s, "r3") == 0 ||
1313                strcmp (s, "r4") == 0 ||
1314                strcmp (s, "r5") == 0 ||
1315                strcmp (s, "r6") == 0 ||
1316                strcmp (s, "r7") == 0)
1317         {
1318           char buffer[10];
1319           sprintf (buffer, "a%s", s);
1320           emitcode ("mov", "@%s,%s",
1321                     aop->aopu.aop_ptr->name, buffer);
1322         }
1323       else
1324         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1325
1326       break;
1327
1328     case AOP_STK:
1329       if (strcmp (s, "a") == 0)
1330         emitcode ("push", "acc");
1331       else
1332         if (*s=='@') {
1333           MOVA(s);
1334           emitcode ("push", "acc");
1335         } else {
1336           emitcode ("push", s);
1337         }
1338
1339       break;
1340
1341     case AOP_CRY:
1342       /* if bit variable */
1343       if (!aop->aopu.aop_dir)
1344         {
1345           emitcode ("clr", "a");
1346           emitcode ("rlc", "a");
1347         }
1348       else
1349         {
1350           if (s == zero)
1351             emitcode ("clr", "%s", aop->aopu.aop_dir);
1352           else if (s == one)
1353             emitcode ("setb", "%s", aop->aopu.aop_dir);
1354           else if (!strcmp (s, "c"))
1355             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1356           else
1357             {
1358               if (strcmp (s, "a"))
1359                 {
1360                   MOVA (s);
1361                 }
1362               {
1363                 /* set C, if a >= 1 */
1364                 emitcode ("add", "a,#0xff");
1365                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1366               }
1367             }
1368         }
1369       break;
1370
1371     case AOP_STR:
1372       aop->coff = offset;
1373       if (strcmp (aop->aopu.aop_str[offset], s) ||
1374           bvolatile)
1375         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1376       break;
1377
1378     case AOP_ACC:
1379       aop->coff = offset;
1380       if (!offset && (strcmp (s, "acc") == 0) &&
1381           !bvolatile)
1382         break;
1383
1384       if (strcmp (aop->aopu.aop_str[offset], s) &&
1385           !bvolatile)
1386         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1387       break;
1388
1389     default:
1390       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1391               "aopPut got unsupported aop->type");
1392       exit (1);
1393     }
1394
1395 }
1396
1397
1398 #if 0
1399 /*-----------------------------------------------------------------*/
1400 /* pointToEnd :- points to the last byte of the operand            */
1401 /*-----------------------------------------------------------------*/
1402 static void
1403 pointToEnd (asmop * aop)
1404 {
1405   int count;
1406   if (!aop)
1407     return;
1408
1409   aop->coff = count = (aop->size - 1);
1410   switch (aop->type)
1411     {
1412     case AOP_R0:
1413     case AOP_R1:
1414       while (count--)
1415         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1416       break;
1417     case AOP_DPTR:
1418       while (count--)
1419         emitcode ("inc", "dptr");
1420       break;
1421     }
1422
1423 }
1424 #endif
1425
1426 /*-----------------------------------------------------------------*/
1427 /* reAdjustPreg - points a register back to where it should        */
1428 /*-----------------------------------------------------------------*/
1429 static void
1430 reAdjustPreg (asmop * aop)
1431 {
1432   if ((aop->coff==0) || aop->size <= 1)
1433     return;
1434
1435   switch (aop->type)
1436     {
1437     case AOP_R0:
1438     case AOP_R1:
1439       while (aop->coff--)
1440         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1441       break;
1442     case AOP_DPTR:
1443       while (aop->coff--)
1444         {
1445           emitcode ("lcall", "__decdptr");
1446         }
1447       break;
1448     }
1449   aop->coff = 0;
1450 }
1451
1452 #define AOP(op) op->aop
1453 #define AOP_TYPE(op) AOP(op)->type
1454 #define AOP_SIZE(op) AOP(op)->size
1455 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1456                        AOP_TYPE(x) == AOP_R0))
1457
1458 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1459                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
1460
1461 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1462                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
1463                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
1464
1465
1466 /*-----------------------------------------------------------------*/
1467 /* opIsGptr: returns non-zero if the passed operand is       */
1468 /* a generic pointer type.             */
1469 /*-----------------------------------------------------------------*/
1470 static int
1471 opIsGptr (operand * op)
1472 {
1473   sym_link *type = operandType (op);
1474
1475   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1476     {
1477       return 1;
1478     }
1479   return 0;
1480 }
1481
1482 /*-----------------------------------------------------------------*/
1483 /* getDataSize - get the operand data size                         */
1484 /*-----------------------------------------------------------------*/
1485 static int
1486 getDataSize (operand * op)
1487 {
1488   int size;
1489   size = AOP_SIZE (op);
1490   if (size == GPTRSIZE)
1491     {
1492       sym_link *type = operandType (op);
1493       if (IS_GENPTR (type))
1494         {
1495           /* generic pointer; arithmetic operations
1496            * should ignore the high byte (pointer type).
1497            */
1498           size--;
1499         }
1500     }
1501   return size;
1502 }
1503
1504 /*-----------------------------------------------------------------*/
1505 /* outAcc - output Acc                                             */
1506 /*-----------------------------------------------------------------*/
1507 static void
1508 outAcc (operand * result)
1509 {
1510   int size, offset;
1511   size = getDataSize (result);
1512   if (size)
1513     {
1514       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
1515       size--;
1516       offset = 1;
1517       /* unsigned or positive */
1518       while (size--)
1519         {
1520           aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
1521         }
1522     }
1523 }
1524
1525 /*-----------------------------------------------------------------*/
1526 /* outBitC - output a bit C                                        */
1527 /*-----------------------------------------------------------------*/
1528 static void
1529 outBitC (operand * result)
1530 {
1531   /* if the result is bit */
1532   if (AOP_TYPE (result) == AOP_CRY)
1533     aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
1534   else
1535     {
1536       emitcode ("clr", "a");
1537       emitcode ("rlc", "a");
1538       outAcc (result);
1539     }
1540 }
1541
1542 /*-----------------------------------------------------------------*/
1543 /* toBoolean - emit code for orl a,operator(sizeop)                */
1544 /*-----------------------------------------------------------------*/
1545 static void
1546 toBoolean (operand * oper)
1547 {
1548   int size = AOP_SIZE (oper) - 1;
1549   int offset = 1;
1550   MOVA (aopGet (AOP (oper), 0, FALSE, FALSE));
1551   while (size--)
1552     emitcode ("orl", "a,%s", aopGet (AOP (oper), offset++, FALSE, FALSE));
1553 }
1554
1555
1556 /*-----------------------------------------------------------------*/
1557 /* genNot - generate code for ! operation                          */
1558 /*-----------------------------------------------------------------*/
1559 static void
1560 genNot (iCode * ic)
1561 {
1562   symbol *tlbl;
1563
1564   D(emitcode (";     genNot",""));
1565
1566   /* assign asmOps to operand & result */
1567   aopOp (IC_LEFT (ic), ic, FALSE);
1568   aopOp (IC_RESULT (ic), ic, TRUE);
1569
1570   /* if in bit space then a special case */
1571   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1572     {
1573       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1574       emitcode ("cpl", "c");
1575       outBitC (IC_RESULT (ic));
1576       goto release;
1577     }
1578
1579   toBoolean (IC_LEFT (ic));
1580
1581   tlbl = newiTempLabel (NULL);
1582   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1583   emitcode ("", "%05d$:", tlbl->key + 100);
1584   outBitC (IC_RESULT (ic));
1585
1586 release:
1587   /* release the aops */
1588   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1589   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1590 }
1591
1592
1593 /*-----------------------------------------------------------------*/
1594 /* genCpl - generate code for complement                           */
1595 /*-----------------------------------------------------------------*/
1596 static void
1597 genCpl (iCode * ic)
1598 {
1599   int offset = 0;
1600   int size;
1601   symbol *tlbl;
1602
1603   D(emitcode (";     genCpl",""));
1604
1605   /* assign asmOps to operand & result */
1606   aopOp (IC_LEFT (ic), ic, FALSE);
1607   aopOp (IC_RESULT (ic), ic, TRUE);
1608
1609   /* special case if in bit space */
1610   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1611     {
1612       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1613         {
1614           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                           freeAsmop (right, NULL, ic, TRUE);
4781                           freeAsmop (left, NULL, ic, TRUE);
4782
4783                           return;
4784                         }
4785                       else
4786                         emitcode ("rlc", "a");
4787                     }
4788                   goto release;
4789                 }
4790             }
4791           CLRC;
4792           while (size--)
4793             {
4794               rightInB = aopGetUsesAcc(AOP (right), offset);
4795               if (rightInB)
4796                 emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4797               MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4798               if (sign && size == 0)
4799                 {
4800                   emitcode ("xrl", "a,#0x80");
4801                   if (AOP_TYPE (right) == AOP_LIT)
4802                     {
4803                       unsigned long lit = (unsigned long)
4804                       floatFromVal (AOP (right)->aopu.aop_lit);
4805                       emitcode ("subb", "a,#0x%02x",
4806                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4807                     }
4808                   else
4809                     {
4810                       if (!rightInB)
4811                         emitcode ("mov", "b,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4812                       emitcode ("xrl", "b,#0x80");
4813                       emitcode ("subb", "a,b");
4814                     }
4815                 }
4816               else
4817                 {
4818                   if (rightInB)
4819                     emitcode ("subb", "a,b");
4820                   else
4821                     emitcode ("subb", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
4822                 }
4823               offset++;
4824             }
4825         }
4826     }
4827
4828 release:
4829   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4830   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4831   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4832     {
4833       outBitC (result);
4834     }
4835   else
4836     {
4837       /* if the result is used in the next
4838          ifx conditional branch then generate
4839          code a little differently */
4840       if (ifx)
4841         genIfxJump (ifx, "c", NULL, NULL, result);
4842       else
4843         outBitC (result);
4844       /* leave the result in acc */
4845     }
4846 }
4847
4848 /*-----------------------------------------------------------------*/
4849 /* genCmpGt :- greater than comparison                             */
4850 /*-----------------------------------------------------------------*/
4851 static void
4852 genCmpGt (iCode * ic, iCode * ifx)
4853 {
4854   operand *left, *right, *result;
4855   sym_link *letype, *retype;
4856   int sign;
4857
4858   D(emitcode (";     genCmpGt",""));
4859
4860   left = IC_LEFT (ic);
4861   right = IC_RIGHT (ic);
4862   result = IC_RESULT (ic);
4863
4864   letype = getSpec (operandType (left));
4865   retype = getSpec (operandType (right));
4866   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4867            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4868   /* assign the amsops */
4869   aopOp (left, ic, FALSE);
4870   aopOp (right, ic, FALSE);
4871   aopOp (result, ic, TRUE);
4872
4873   genCmp (right, left, result, ifx, sign,ic);
4874
4875   freeAsmop (result, NULL, ic, TRUE);
4876 }
4877
4878 /*-----------------------------------------------------------------*/
4879 /* genCmpLt - less than comparisons                                */
4880 /*-----------------------------------------------------------------*/
4881 static void
4882 genCmpLt (iCode * ic, iCode * ifx)
4883 {
4884   operand *left, *right, *result;
4885   sym_link *letype, *retype;
4886   int sign;
4887
4888   D(emitcode (";     genCmpLt",""));
4889
4890   left = IC_LEFT (ic);
4891   right = IC_RIGHT (ic);
4892   result = IC_RESULT (ic);
4893
4894   letype = getSpec (operandType (left));
4895   retype = getSpec (operandType (right));
4896   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
4897            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
4898   /* assign the amsops */
4899   aopOp (left, ic, FALSE);
4900   aopOp (right, ic, FALSE);
4901   aopOp (result, ic, TRUE);
4902
4903   genCmp (left, right, result, ifx, sign,ic);
4904
4905   freeAsmop (result, NULL, ic, TRUE);
4906 }
4907
4908 /*-----------------------------------------------------------------*/
4909 /* gencjneshort - compare and jump if not equal                    */
4910 /*-----------------------------------------------------------------*/
4911 static void
4912 gencjneshort (operand * left, operand * right, symbol * lbl)
4913 {
4914   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4915   int offset = 0;
4916   unsigned long lit = 0L;
4917
4918   /* if the left side is a literal or
4919      if the right is in a pointer register and left
4920      is not */
4921   if ((AOP_TYPE (left) == AOP_LIT) ||
4922       (AOP_TYPE (left) == AOP_IMMD) ||
4923       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
4924     {
4925       operand *t = right;
4926       right = left;
4927       left = t;
4928     }
4929
4930   if (AOP_TYPE (right) == AOP_LIT)
4931     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4932
4933   /* if the right side is a literal then anything goes */
4934   if (AOP_TYPE (right) == AOP_LIT &&
4935       AOP_TYPE (left) != AOP_DIR  &&
4936       AOP_TYPE (left) != AOP_IMMD)
4937     {
4938       while (size--)
4939         {
4940           emitcode ("cjne", "%s,%s,%05d$",
4941                     aopGet (AOP (left), offset, FALSE, FALSE),
4942                     aopGet (AOP (right), offset, FALSE, FALSE),
4943                     lbl->key + 100);
4944           offset++;
4945         }
4946     }
4947
4948   /* if the right side is in a register or in direct space or
4949      if the left is a pointer register & right is not */
4950   else if (AOP_TYPE (right) == AOP_REG ||
4951            AOP_TYPE (right) == AOP_DIR ||
4952            AOP_TYPE (right) == AOP_LIT ||
4953            AOP_TYPE (right) == AOP_IMMD ||
4954            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
4955            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
4956     {
4957       while (size--)
4958         {
4959           MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
4960           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4961               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4962             emitcode ("jnz", "%05d$", lbl->key + 100);
4963           else
4964             emitcode ("cjne", "a,%s,%05d$",
4965                       aopGet (AOP (right), offset, FALSE, TRUE),
4966                       lbl->key + 100);
4967           offset++;
4968         }
4969     }
4970   else
4971     {
4972       /* right is a pointer reg need both a & b */
4973       while (size--)
4974         {
4975           char *l = aopGet (AOP (left), offset, FALSE, FALSE);
4976           if (strcmp (l, "b"))
4977             emitcode ("mov", "b,%s", l);
4978           MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
4979           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
4980           offset++;
4981         }
4982     }
4983 }
4984
4985 /*-----------------------------------------------------------------*/
4986 /* gencjne - compare and jump if not equal                         */
4987 /*-----------------------------------------------------------------*/
4988 static void
4989 gencjne (operand * left, operand * right, symbol * lbl)
4990 {
4991   symbol *tlbl = newiTempLabel (NULL);
4992
4993   gencjneshort (left, right, lbl);
4994
4995   emitcode ("mov", "a,%s", one);
4996   emitcode ("sjmp", "%05d$", tlbl->key + 100);
4997   emitcode ("", "%05d$:", lbl->key + 100);
4998   emitcode ("clr", "a");
4999   emitcode ("", "%05d$:", tlbl->key + 100);
5000 }
5001
5002 /*-----------------------------------------------------------------*/
5003 /* genCmpEq - generates code for equal to                          */
5004 /*-----------------------------------------------------------------*/
5005 static void
5006 genCmpEq (iCode * ic, iCode * ifx)
5007 {
5008   operand *left, *right, *result;
5009
5010   D(emitcode (";     genCmpEq",""));
5011
5012   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5013   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5014   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5015
5016   /* if literal, literal on the right or
5017      if the right is in a pointer register and left
5018      is not */
5019   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5020       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5021     {
5022       operand *t = IC_RIGHT (ic);
5023       IC_RIGHT (ic) = IC_LEFT (ic);
5024       IC_LEFT (ic) = t;
5025     }
5026
5027   if (ifx && !AOP_SIZE (result))
5028     {
5029       symbol *tlbl;
5030       /* if they are both bit variables */
5031       if (AOP_TYPE (left) == AOP_CRY &&
5032           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5033         {
5034           if (AOP_TYPE (right) == AOP_LIT)
5035             {
5036               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5037               if (lit == 0L)
5038                 {
5039                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5040                   emitcode ("cpl", "c");
5041                 }
5042               else if (lit == 1L)
5043                 {
5044                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5045                 }
5046               else
5047                 {
5048                   emitcode ("clr", "c");
5049                 }
5050               /* AOP_TYPE(right) == AOP_CRY */
5051             }
5052           else
5053             {
5054               symbol *lbl = newiTempLabel (NULL);
5055               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5056               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5057               emitcode ("cpl", "c");
5058               emitcode ("", "%05d$:", (lbl->key + 100));
5059             }
5060           /* if true label then we jump if condition
5061              supplied is true */
5062           tlbl = newiTempLabel (NULL);
5063           if (IC_TRUE (ifx))
5064             {
5065               emitcode ("jnc", "%05d$", tlbl->key + 100);
5066               freeForBranchAsmop (result);
5067               freeForBranchAsmop (right);
5068               freeForBranchAsmop (left);
5069               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5070             }
5071           else
5072             {
5073               emitcode ("jc", "%05d$", tlbl->key + 100);
5074               freeForBranchAsmop (result);
5075               freeForBranchAsmop (right);
5076               freeForBranchAsmop (left);
5077               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5078             }
5079           emitcode ("", "%05d$:", tlbl->key + 100);
5080         }
5081       else
5082         {
5083           tlbl = newiTempLabel (NULL);
5084           gencjneshort (left, right, tlbl);
5085           if (IC_TRUE (ifx))
5086             {
5087               freeForBranchAsmop (result);
5088               freeForBranchAsmop (right);
5089               freeForBranchAsmop (left);
5090               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5091               emitcode ("", "%05d$:", tlbl->key + 100);
5092             }
5093           else
5094             {
5095               symbol *lbl = newiTempLabel (NULL);
5096               emitcode ("sjmp", "%05d$", lbl->key + 100);
5097               emitcode ("", "%05d$:", tlbl->key + 100);
5098               freeForBranchAsmop (result);
5099               freeForBranchAsmop (right);
5100               freeForBranchAsmop (left);
5101               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5102               emitcode ("", "%05d$:", lbl->key + 100);
5103             }
5104         }
5105       /* mark the icode as generated */
5106       ifx->generated = 1;
5107       goto release;
5108     }
5109
5110   /* if they are both bit variables */
5111   if (AOP_TYPE (left) == AOP_CRY &&
5112       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5113     {
5114       if (AOP_TYPE (right) == AOP_LIT)
5115         {
5116           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5117           if (lit == 0L)
5118             {
5119               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5120               emitcode ("cpl", "c");
5121             }
5122           else if (lit == 1L)
5123             {
5124               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5125             }
5126           else
5127             {
5128               emitcode ("clr", "c");
5129             }
5130           /* AOP_TYPE(right) == AOP_CRY */
5131         }
5132       else
5133         {
5134           symbol *lbl = newiTempLabel (NULL);
5135           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5136           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5137           emitcode ("cpl", "c");
5138           emitcode ("", "%05d$:", (lbl->key + 100));
5139         }
5140       /* c = 1 if egal */
5141       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5142         {
5143           outBitC (result);
5144           goto release;
5145         }
5146       if (ifx)
5147         {
5148           genIfxJump (ifx, "c", left, right, result);
5149           goto release;
5150         }
5151       /* if the result is used in an arithmetic operation
5152          then put the result in place */
5153       outBitC (result);
5154     }
5155   else
5156     {
5157       gencjne (left, right, newiTempLabel (NULL));
5158       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5159         {
5160           aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
5161           goto release;
5162         }
5163       if (ifx)
5164         {
5165           genIfxJump (ifx, "a", left, right, result);
5166           goto release;
5167         }
5168       /* if the result is used in an arithmetic operation
5169          then put the result in place */
5170       if (AOP_TYPE (result) != AOP_CRY)
5171         outAcc (result);
5172       /* leave the result in acc */
5173     }
5174
5175 release:
5176   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5177   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5178   freeAsmop (result, NULL, ic, TRUE);
5179 }
5180
5181 /*-----------------------------------------------------------------*/
5182 /* ifxForOp - returns the icode containing the ifx for operand     */
5183 /*-----------------------------------------------------------------*/
5184 static iCode *
5185 ifxForOp (operand * op, iCode * ic)
5186 {
5187   /* if true symbol then needs to be assigned */
5188   if (IS_TRUE_SYMOP (op))
5189     return NULL;
5190
5191   /* if this has register type condition and
5192      the next instruction is ifx with the same operand
5193      and live to of the operand is upto the ifx only then */
5194   if (ic->next &&
5195       ic->next->op == IFX &&
5196       IC_COND (ic->next)->key == op->key &&
5197       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5198     return ic->next;
5199
5200   return NULL;
5201 }
5202
5203 /*-----------------------------------------------------------------*/
5204 /* hasInc - operand is incremented before any other use            */
5205 /*-----------------------------------------------------------------*/
5206 static iCode *
5207 hasInc (operand *op, iCode *ic,int osize)
5208 {
5209   sym_link *type = operandType(op);
5210   sym_link *retype = getSpec (type);
5211   iCode *lic = ic->next;
5212   int isize ;
5213
5214   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5215   if (!IS_SYMOP(op)) return NULL;
5216
5217   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5218   if (IS_AGGREGATE(type->next)) return NULL;
5219   if (osize != (isize = getSize(type->next))) return NULL;
5220
5221   while (lic) {
5222     /* if operand of the form op = op + <sizeof *op> */
5223     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5224         isOperandEqual(IC_RESULT(lic),op) &&
5225         isOperandLiteral(IC_RIGHT(lic)) &&
5226         operandLitValue(IC_RIGHT(lic)) == isize) {
5227       return lic;
5228     }
5229     /* if the operand used or deffed */
5230     if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) {
5231       return NULL;
5232     }
5233     /* if GOTO or IFX */
5234     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5235     lic = lic->next;
5236   }
5237   return NULL;
5238 }
5239
5240 /*-----------------------------------------------------------------*/
5241 /* genAndOp - for && operation                                     */
5242 /*-----------------------------------------------------------------*/
5243 static void
5244 genAndOp (iCode * ic)
5245 {
5246   operand *left, *right, *result;
5247   symbol *tlbl;
5248
5249   D(emitcode (";     genAndOp",""));
5250
5251   /* note here that && operations that are in an
5252      if statement are taken away by backPatchLabels
5253      only those used in arthmetic operations remain */
5254   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5255   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5256   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5257
5258   /* if both are bit variables */
5259   if (AOP_TYPE (left) == AOP_CRY &&
5260       AOP_TYPE (right) == AOP_CRY)
5261     {
5262       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5263       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5264       outBitC (result);
5265     }
5266   else
5267     {
5268       tlbl = newiTempLabel (NULL);
5269       toBoolean (left);
5270       emitcode ("jz", "%05d$", tlbl->key + 100);
5271       toBoolean (right);
5272       emitcode ("", "%05d$:", tlbl->key + 100);
5273       outBitAcc (result);
5274     }
5275
5276   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5277   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5278   freeAsmop (result, NULL, ic, TRUE);
5279 }
5280
5281
5282 /*-----------------------------------------------------------------*/
5283 /* genOrOp - for || operation                                      */
5284 /*-----------------------------------------------------------------*/
5285 static void
5286 genOrOp (iCode * ic)
5287 {
5288   operand *left, *right, *result;
5289   symbol *tlbl;
5290
5291   D(emitcode (";     genOrOp",""));
5292
5293   /* note here that || operations that are in an
5294      if statement are taken away by backPatchLabels
5295      only those used in arthmetic operations remain */
5296   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5297   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5298   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
5299
5300   /* if both are bit variables */
5301   if (AOP_TYPE (left) == AOP_CRY &&
5302       AOP_TYPE (right) == AOP_CRY)
5303     {
5304       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5305       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
5306       outBitC (result);
5307     }
5308   else
5309     {
5310       tlbl = newiTempLabel (NULL);
5311       toBoolean (left);
5312       emitcode ("jnz", "%05d$", tlbl->key + 100);
5313       toBoolean (right);
5314       emitcode ("", "%05d$:", tlbl->key + 100);
5315       outBitAcc (result);
5316     }
5317
5318   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5319   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5320   freeAsmop (result, NULL, ic, TRUE);
5321 }
5322
5323 /*-----------------------------------------------------------------*/
5324 /* isLiteralBit - test if lit == 2^n                               */
5325 /*-----------------------------------------------------------------*/
5326 static int
5327 isLiteralBit (unsigned long lit)
5328 {
5329   unsigned long pw[32] =
5330   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
5331    0x100L, 0x200L, 0x400L, 0x800L,
5332    0x1000L, 0x2000L, 0x4000L, 0x8000L,
5333    0x10000L, 0x20000L, 0x40000L, 0x80000L,
5334    0x100000L, 0x200000L, 0x400000L, 0x800000L,
5335    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
5336    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
5337   int idx;
5338
5339   for (idx = 0; idx < 32; idx++)
5340     if (lit == pw[idx])
5341       return idx + 1;
5342   return 0;
5343 }
5344
5345 /*-----------------------------------------------------------------*/
5346 /* continueIfTrue -                                                */
5347 /*-----------------------------------------------------------------*/
5348 static void
5349 continueIfTrue (iCode * ic)
5350 {
5351   if (IC_TRUE (ic))
5352     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5353   ic->generated = 1;
5354 }
5355
5356 /*-----------------------------------------------------------------*/
5357 /* jmpIfTrue -                                                     */
5358 /*-----------------------------------------------------------------*/
5359 static void
5360 jumpIfTrue (iCode * ic)
5361 {
5362   if (!IC_TRUE (ic))
5363     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5364   ic->generated = 1;
5365 }
5366
5367 /*-----------------------------------------------------------------*/
5368 /* jmpTrueOrFalse -                                                */
5369 /*-----------------------------------------------------------------*/
5370 static void
5371 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
5372 {
5373   // ugly but optimized by peephole
5374   if (IC_TRUE (ic))
5375     {
5376       symbol *nlbl = newiTempLabel (NULL);
5377       emitcode ("sjmp", "%05d$", nlbl->key + 100);
5378       emitcode ("", "%05d$:", tlbl->key + 100);
5379       freeForBranchAsmop (result);
5380       freeForBranchAsmop (right);
5381       freeForBranchAsmop (left);
5382       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
5383       emitcode ("", "%05d$:", nlbl->key + 100);
5384     }
5385   else
5386     {
5387       freeForBranchAsmop (result);
5388       freeForBranchAsmop (right);
5389       freeForBranchAsmop (left);
5390       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
5391       emitcode ("", "%05d$:", tlbl->key + 100);
5392     }
5393   ic->generated = 1;
5394 }
5395
5396 /*-----------------------------------------------------------------*/
5397 /* genAnd  - code for and                                          */
5398 /*-----------------------------------------------------------------*/
5399 static void
5400 genAnd (iCode * ic, iCode * ifx)
5401 {
5402   operand *left, *right, *result;
5403   int size, offset = 0;
5404   unsigned long lit = 0L;
5405   int bytelit = 0;
5406   char buffer[10];
5407
5408   D(emitcode (";     genAnd",""));
5409
5410   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5411   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5412   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5413
5414 #ifdef DEBUG_TYPE
5415   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5416             AOP_TYPE (result),
5417             AOP_TYPE (left), AOP_TYPE (right));
5418   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5419             AOP_SIZE (result),
5420             AOP_SIZE (left), AOP_SIZE (right));
5421 #endif
5422
5423   /* if left is a literal & right is not then exchange them */
5424   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5425       AOP_NEEDSACC (left))
5426     {
5427       operand *tmp = right;
5428       right = left;
5429       left = tmp;
5430     }
5431
5432   /* if result = right then exchange them */
5433   if (sameRegs (AOP (result), AOP (right)))
5434     {
5435       operand *tmp = right;
5436       right = left;
5437       left = tmp;
5438     }
5439
5440   /* if right is bit then exchange them */
5441   if (AOP_TYPE (right) == AOP_CRY &&
5442       AOP_TYPE (left) != AOP_CRY)
5443     {
5444       operand *tmp = right;
5445       right = left;
5446       left = tmp;
5447     }
5448   if (AOP_TYPE (right) == AOP_LIT)
5449     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5450
5451   size = AOP_SIZE (result);
5452
5453   // if(bit & yy)
5454   // result = bit & yy;
5455   if (AOP_TYPE (left) == AOP_CRY)
5456     {
5457       // c = bit & literal;
5458       if (AOP_TYPE (right) == AOP_LIT)
5459         {
5460           if (lit & 1)
5461             {
5462               if (size && sameRegs (AOP (result), AOP (left)))
5463                 // no change
5464                 goto release;
5465               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5466             }
5467           else
5468             {
5469               // bit(result) = 0;
5470               if (size && (AOP_TYPE (result) == AOP_CRY))
5471                 {
5472                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
5473                   goto release;
5474                 }
5475               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5476                 {
5477                   jumpIfTrue (ifx);
5478                   goto release;
5479                 }
5480               emitcode ("clr", "c");
5481             }
5482         }
5483       else
5484         {
5485           if (AOP_TYPE (right) == AOP_CRY)
5486             {
5487               // c = bit & bit;
5488               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5489               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5490             }
5491           else
5492             {
5493               // c = bit & val;
5494               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
5495               // c = lsb
5496               emitcode ("rrc", "a");
5497               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5498             }
5499         }
5500       // bit = c
5501       // val = c
5502       if (size)
5503         outBitC (result);
5504       // if(bit & ...)
5505       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5506         genIfxJump (ifx, "c", left, right, result);
5507       goto release;
5508     }
5509
5510   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
5511   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
5512   if ((AOP_TYPE (right) == AOP_LIT) &&
5513       (AOP_TYPE (result) == AOP_CRY) &&
5514       (AOP_TYPE (left) != AOP_CRY))
5515     {
5516       int posbit = isLiteralBit (lit);
5517       /* left &  2^n */
5518       if (posbit)
5519         {
5520           posbit--;
5521           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE));
5522           // bit = left & 2^n
5523           if (size)
5524             emitcode ("mov", "c,acc.%d", posbit & 0x07);
5525           // if(left &  2^n)
5526           else
5527             {
5528               if (ifx)
5529                 {
5530                   sprintf (buffer, "acc.%d", posbit & 0x07);
5531                   genIfxJump (ifx, buffer, left, right, result);
5532                 }
5533               goto release;
5534             }
5535         }
5536       else
5537         {
5538           symbol *tlbl = newiTempLabel (NULL);
5539           int sizel = AOP_SIZE (left);
5540           if (size)
5541             emitcode ("setb", "c");
5542           while (sizel--)
5543             {
5544               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
5545                 {
5546                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5547                   // byte ==  2^n ?
5548                   if ((posbit = isLiteralBit (bytelit)) != 0)
5549                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
5550                   else
5551                     {
5552                       if (bytelit != 0x0FFL)
5553                         emitcode ("anl", "a,%s",
5554                                   aopGet (AOP (right), offset, FALSE, TRUE));
5555                       emitcode ("jnz", "%05d$", tlbl->key + 100);
5556                     }
5557                 }
5558               offset++;
5559             }
5560           // bit = left & literal
5561           if (size)
5562             {
5563               emitcode ("clr", "c");
5564               emitcode ("", "%05d$:", tlbl->key + 100);
5565             }
5566           // if(left & literal)
5567           else
5568             {
5569               if (ifx)
5570                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
5571               else
5572                 emitcode ("", "%05d$:", tlbl->key + 100);
5573               goto release;
5574             }
5575         }
5576       outBitC (result);
5577       goto release;
5578     }
5579
5580   /* if left is same as result */
5581   if (sameRegs (AOP (result), AOP (left)))
5582     {
5583       for (; size--; offset++)
5584         {
5585           if (AOP_TYPE (right) == AOP_LIT)
5586             {
5587               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5588                 continue;
5589               else if (bytelit == 0)
5590                 {
5591                   aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5592                 }
5593               else if (IS_AOP_PREG (result))
5594                 {
5595                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5596                   emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5597                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5598                 }
5599               else
5600                 emitcode ("anl", "%s,%s",
5601                           aopGet (AOP (left), offset, FALSE, TRUE),
5602                           aopGet (AOP (right), offset, FALSE, FALSE));
5603             }
5604           else
5605             {
5606               if (AOP_TYPE (left) == AOP_ACC)
5607                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5608               else
5609                 {
5610                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5611                   if (IS_AOP_PREG (result))
5612                     {
5613                       emitcode ("anl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5614                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5615
5616                     }
5617                   else
5618                     emitcode ("anl", "%s,a",
5619                               aopGet (AOP (left), offset, FALSE, TRUE));
5620                 }
5621             }
5622         }
5623     }
5624   else
5625     {
5626       // left & result in different registers
5627       if (AOP_TYPE (result) == AOP_CRY)
5628         {
5629           // result = bit
5630           // if(size), result in bit
5631           // if(!size && ifx), conditional oper: if(left & right)
5632           symbol *tlbl = newiTempLabel (NULL);
5633           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
5634           if (size)
5635             emitcode ("setb", "c");
5636           while (sizer--)
5637             {
5638               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5639                 emitcode ("anl", "a,%s",
5640                           aopGet (AOP (right), offset, FALSE, FALSE));
5641               } else {
5642                 if (AOP_TYPE(left)==AOP_ACC) {
5643                   emitcode("mov", "b,a");
5644                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5645                   emitcode("anl", "a,b");
5646                 }else {
5647                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5648                   emitcode ("anl", "a,%s",
5649                             aopGet (AOP (left), offset, FALSE, FALSE));
5650                 }
5651               }
5652               emitcode ("jnz", "%05d$", tlbl->key + 100);
5653               offset++;
5654             }
5655           if (size)
5656             {
5657               CLRC;
5658               emitcode ("", "%05d$:", tlbl->key + 100);
5659               outBitC (result);
5660             }
5661           else if (ifx)
5662             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5663           else
5664             emitcode ("", "%05d$:", tlbl->key + 100);
5665         }
5666       else
5667         {
5668           for (; (size--); offset++)
5669             {
5670               // normal case
5671               // result = left & right
5672               if (AOP_TYPE (right) == AOP_LIT)
5673                 {
5674                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
5675                     {
5676                       aopPut (AOP (result),
5677                               aopGet (AOP (left), offset, FALSE, FALSE),
5678                               offset,
5679                               isOperandVolatile (result, FALSE));
5680                       continue;
5681                     }
5682                   else if (bytelit == 0)
5683                     {
5684                       /* dummy read of volatile operand */
5685                       if (isOperandVolatile (left, FALSE))
5686                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5687                       aopPut (AOP (result), zero, offset, isOperandVolatile (result, FALSE));
5688                       continue;
5689                     }
5690                 }
5691               // faster than result <- left, anl result,right
5692               // and better if result is SFR
5693               if (AOP_TYPE (left) == AOP_ACC)
5694                 emitcode ("anl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5695               else
5696                 {
5697                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5698                   emitcode ("anl", "a,%s",
5699                             aopGet (AOP (left), offset, FALSE, FALSE));
5700                 }
5701               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5702             }
5703         }
5704     }
5705
5706 release:
5707   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5708   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5709   freeAsmop (result, NULL, ic, TRUE);
5710 }
5711
5712 /*-----------------------------------------------------------------*/
5713 /* genOr  - code for or                                            */
5714 /*-----------------------------------------------------------------*/
5715 static void
5716 genOr (iCode * ic, iCode * ifx)
5717 {
5718   operand *left, *right, *result;
5719   int size, offset = 0;
5720   unsigned long lit = 0L;
5721
5722   D(emitcode (";     genOr",""));
5723
5724   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5725   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5726   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5727
5728 #ifdef DEBUG_TYPE
5729   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
5730             AOP_TYPE (result),
5731             AOP_TYPE (left), AOP_TYPE (right));
5732   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
5733             AOP_SIZE (result),
5734             AOP_SIZE (left), AOP_SIZE (right));
5735 #endif
5736
5737   /* if left is a literal & right is not then exchange them */
5738   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
5739       AOP_NEEDSACC (left))
5740     {
5741       operand *tmp = right;
5742       right = left;
5743       left = tmp;
5744     }
5745
5746   /* if result = right then exchange them */
5747   if (sameRegs (AOP (result), AOP (right)))
5748     {
5749       operand *tmp = right;
5750       right = left;
5751       left = tmp;
5752     }
5753
5754   /* if right is bit then exchange them */
5755   if (AOP_TYPE (right) == AOP_CRY &&
5756       AOP_TYPE (left) != AOP_CRY)
5757     {
5758       operand *tmp = right;
5759       right = left;
5760       left = tmp;
5761     }
5762   if (AOP_TYPE (right) == AOP_LIT)
5763     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5764
5765   size = AOP_SIZE (result);
5766
5767   // if(bit | yy)
5768   // xx = bit | yy;
5769   if (AOP_TYPE (left) == AOP_CRY)
5770     {
5771       if (AOP_TYPE (right) == AOP_LIT)
5772         {
5773           // c = bit | literal;
5774           if (lit)
5775             {
5776               // lit != 0 => result = 1
5777               if (AOP_TYPE (result) == AOP_CRY)
5778                 {
5779                   if (size)
5780                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5781                   else if (ifx)
5782                     continueIfTrue (ifx);
5783                   goto release;
5784                 }
5785               emitcode ("setb", "c");
5786             }
5787           else
5788             {
5789               // lit == 0 => result = left
5790               if (size && sameRegs (AOP (result), AOP (left)))
5791                 goto release;
5792               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5793             }
5794         }
5795       else
5796         {
5797           if (AOP_TYPE (right) == AOP_CRY)
5798             {
5799               // c = bit | bit;
5800               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5801               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
5802             }
5803           else
5804             {
5805               // c = bit | val;
5806               symbol *tlbl = newiTempLabel (NULL);
5807               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
5808                 emitcode ("setb", "c");
5809               emitcode ("jb", "%s,%05d$",
5810                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
5811               toBoolean (right);
5812               emitcode ("jnz", "%05d$", tlbl->key + 100);
5813               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5814                 {
5815                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
5816                   goto release;
5817                 }
5818               else
5819                 {
5820                   CLRC;
5821                   emitcode ("", "%05d$:", tlbl->key + 100);
5822                 }
5823             }
5824         }
5825       // bit = c
5826       // val = c
5827       if (size)
5828         outBitC (result);
5829       // if(bit | ...)
5830       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
5831         genIfxJump (ifx, "c", left, right, result);
5832       goto release;
5833     }
5834
5835   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
5836   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
5837   if ((AOP_TYPE (right) == AOP_LIT) &&
5838       (AOP_TYPE (result) == AOP_CRY) &&
5839       (AOP_TYPE (left) != AOP_CRY))
5840     {
5841       if (lit)
5842         {
5843           // result = 1
5844           if (size)
5845             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
5846           else
5847             continueIfTrue (ifx);
5848           goto release;
5849         }
5850       else
5851         {
5852           // lit = 0, result = boolean(left)
5853           if (size)
5854             emitcode ("setb", "c");
5855           toBoolean (right);
5856           if (size)
5857             {
5858               symbol *tlbl = newiTempLabel (NULL);
5859               emitcode ("jnz", "%05d$", tlbl->key + 100);
5860               CLRC;
5861               emitcode ("", "%05d$:", tlbl->key + 100);
5862             }
5863           else
5864             {
5865               genIfxJump (ifx, "a", left, right, result);
5866               goto release;
5867             }
5868         }
5869       outBitC (result);
5870       goto release;
5871     }
5872
5873   /* if left is same as result */
5874   if (sameRegs (AOP (result), AOP (left)))
5875     {
5876       for (; size--; offset++)
5877         {
5878           if (AOP_TYPE (right) == AOP_LIT)
5879             {
5880               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5881                 {
5882                   /* dummy read of volatile operand */
5883                   if (isOperandVolatile (left, FALSE))
5884                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
5885                   else
5886                     continue;
5887                 }
5888               else if (IS_AOP_PREG (left))
5889                 {
5890                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5891                   emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5892                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5893                 }
5894               else
5895                 emitcode ("orl", "%s,%s",
5896                           aopGet (AOP (left), offset, FALSE, TRUE),
5897                           aopGet (AOP (right), offset, FALSE, FALSE));
5898             }
5899           else
5900             {
5901               if (AOP_TYPE (left) == AOP_ACC)
5902                 emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5903               else
5904                 {
5905                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5906                   if (IS_AOP_PREG (left))
5907                     {
5908                       emitcode ("orl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
5909                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5910                     }
5911                   else
5912                     emitcode ("orl", "%s,a",
5913                               aopGet (AOP (left), offset, FALSE, TRUE));
5914                 }
5915             }
5916         }
5917     }
5918   else
5919     {
5920       // left & result in different registers
5921       if (AOP_TYPE (result) == AOP_CRY)
5922         {
5923           // result = bit
5924           // if(size), result in bit
5925           // if(!size && ifx), conditional oper: if(left | right)
5926           symbol *tlbl = newiTempLabel (NULL);
5927           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
5928           if (size)
5929             emitcode ("setb", "c");
5930           while (sizer--)
5931             {
5932               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
5933                 emitcode ("orl", "a,%s",
5934                           aopGet (AOP (right), offset, FALSE, FALSE));
5935               } else {
5936                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5937                 emitcode ("orl", "a,%s",
5938                           aopGet (AOP (left), offset, FALSE, FALSE));
5939               }
5940               emitcode ("jnz", "%05d$", tlbl->key + 100);
5941               offset++;
5942             }
5943           if (size)
5944             {
5945               CLRC;
5946               emitcode ("", "%05d$:", tlbl->key + 100);
5947               outBitC (result);
5948             }
5949           else if (ifx)
5950             jmpTrueOrFalse (ifx, tlbl, left, right, result);
5951           else
5952             emitcode ("", "%05d$:", tlbl->key + 100);
5953         }
5954       else
5955         for (; (size--); offset++)
5956           {
5957             // normal case
5958             // result = left & right
5959             if (AOP_TYPE (right) == AOP_LIT)
5960               {
5961                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5962                   {
5963                     aopPut (AOP (result),
5964                             aopGet (AOP (left), offset, FALSE, FALSE),
5965                             offset,
5966                             isOperandVolatile (result, FALSE));
5967                     continue;
5968                   }
5969               }
5970             // faster than result <- left, anl result,right
5971             // and better if result is SFR
5972             if (AOP_TYPE (left) == AOP_ACC)
5973               emitcode ("orl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
5974             else
5975               {
5976                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
5977                 emitcode ("orl", "a,%s",
5978                           aopGet (AOP (left), offset, FALSE, FALSE));
5979               }
5980             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
5981           }
5982     }
5983
5984 release:
5985   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5986   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5987   freeAsmop (result, NULL, ic, TRUE);
5988 }
5989
5990 /*-----------------------------------------------------------------*/
5991 /* genXor - code for xclusive or                                   */
5992 /*-----------------------------------------------------------------*/
5993 static void
5994 genXor (iCode * ic, iCode * ifx)
5995 {
5996   operand *left, *right, *result;
5997   int size, offset = 0;
5998   unsigned long lit = 0L;
5999
6000   D(emitcode (";     genXor",""));
6001
6002   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6003   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6004   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6005
6006 #ifdef DEBUG_TYPE
6007   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6008             AOP_TYPE (result),
6009             AOP_TYPE (left), AOP_TYPE (right));
6010   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6011             AOP_SIZE (result),
6012             AOP_SIZE (left), AOP_SIZE (right));
6013 #endif
6014
6015   /* if left is a literal & right is not ||
6016      if left needs acc & right does not */
6017   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6018       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6019     {
6020       operand *tmp = right;
6021       right = left;
6022       left = tmp;
6023     }
6024
6025   /* if result = right then exchange them */
6026   if (sameRegs (AOP (result), AOP (right)))
6027     {
6028       operand *tmp = right;
6029       right = left;
6030       left = tmp;
6031     }
6032
6033   /* if right is bit then exchange them */
6034   if (AOP_TYPE (right) == AOP_CRY &&
6035       AOP_TYPE (left) != AOP_CRY)
6036     {
6037       operand *tmp = right;
6038       right = left;
6039       left = tmp;
6040     }
6041   if (AOP_TYPE (right) == AOP_LIT)
6042     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6043
6044   size = AOP_SIZE (result);
6045
6046   // if(bit ^ yy)
6047   // xx = bit ^ yy;
6048   if (AOP_TYPE (left) == AOP_CRY)
6049     {
6050       if (AOP_TYPE (right) == AOP_LIT)
6051         {
6052           // c = bit & literal;
6053           if (lit >> 1)
6054             {
6055               // lit>>1  != 0 => result = 1
6056               if (AOP_TYPE (result) == AOP_CRY)
6057                 {
6058                   if (size)
6059                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6060                   else if (ifx)
6061                     continueIfTrue (ifx);
6062                   goto release;
6063                 }
6064               emitcode ("setb", "c");
6065             }
6066           else
6067             {
6068               // lit == (0 or 1)
6069               if (lit == 0)
6070                 {
6071                   // lit == 0, result = left
6072                   if (size && sameRegs (AOP (result), AOP (left)))
6073                     goto release;
6074                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6075                 }
6076               else
6077                 {
6078                   // lit == 1, result = not(left)
6079                   if (size && sameRegs (AOP (result), AOP (left)))
6080                     {
6081                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6082                       goto release;
6083                     }
6084                   else
6085                     {
6086                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6087                       emitcode ("cpl", "c");
6088                     }
6089                 }
6090             }
6091
6092         }
6093       else
6094         {
6095           // right != literal
6096           symbol *tlbl = newiTempLabel (NULL);
6097           if (AOP_TYPE (right) == AOP_CRY)
6098             {
6099               // c = bit ^ bit;
6100               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6101             }
6102           else
6103             {
6104               int sizer = AOP_SIZE (right);
6105               // c = bit ^ val
6106               // if val>>1 != 0, result = 1
6107               emitcode ("setb", "c");
6108               while (sizer)
6109                 {
6110                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE));
6111                   if (sizer == 1)
6112                     // test the msb of the lsb
6113                     emitcode ("anl", "a,#0xfe");
6114                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6115                   sizer--;
6116                 }
6117               // val = (0,1)
6118               emitcode ("rrc", "a");
6119             }
6120           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6121           emitcode ("cpl", "c");
6122           emitcode ("", "%05d$:", (tlbl->key + 100));
6123         }
6124       // bit = c
6125       // val = c
6126       if (size)
6127         outBitC (result);
6128       // if(bit | ...)
6129       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6130         genIfxJump (ifx, "c", left, right, result);
6131       goto release;
6132     }
6133
6134   if (sameRegs (AOP (result), AOP (left)))
6135     {
6136       /* if left is same as result */
6137       for (; size--; offset++)
6138         {
6139           if (AOP_TYPE (right) == AOP_LIT)
6140             {
6141               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6142                 continue;
6143               else if (IS_AOP_PREG (left))
6144                 {
6145                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6146                   emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6147                   aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6148                 }
6149               else
6150                 emitcode ("xrl", "%s,%s",
6151                           aopGet (AOP (left), offset, FALSE, TRUE),
6152                           aopGet (AOP (right), offset, FALSE, FALSE));
6153             }
6154           else
6155             {
6156               if (AOP_TYPE (left) == AOP_ACC)
6157                 emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6158               else
6159                 {
6160                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6161                   if (IS_AOP_PREG (left))
6162                     {
6163                       emitcode ("xrl", "a,%s", aopGet (AOP (left), offset, FALSE, TRUE));
6164                       aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6165                     }
6166                   else
6167                     emitcode ("xrl", "%s,a",
6168                               aopGet (AOP (left), offset, FALSE, TRUE));
6169                 }
6170             }
6171         }
6172     }
6173   else
6174     {
6175       // left & result in different registers
6176       if (AOP_TYPE (result) == AOP_CRY)
6177         {
6178           // result = bit
6179           // if(size), result in bit
6180           // if(!size && ifx), conditional oper: if(left ^ right)
6181           symbol *tlbl = newiTempLabel (NULL);
6182           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6183           if (size)
6184             emitcode ("setb", "c");
6185           while (sizer--)
6186             {
6187               if ((AOP_TYPE (right) == AOP_LIT) &&
6188                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
6189                 {
6190                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
6191                 }
6192               else
6193                 {
6194                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6195                     emitcode ("xrl", "a,%s",
6196                               aopGet (AOP (right), offset, FALSE, FALSE));
6197                   } else {
6198                     MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6199                     emitcode ("xrl", "a,%s",
6200                               aopGet (AOP (left), offset, FALSE, FALSE));
6201                   }
6202                 }
6203               emitcode ("jnz", "%05d$", tlbl->key + 100);
6204               offset++;
6205             }
6206           if (size)
6207             {
6208               CLRC;
6209               emitcode ("", "%05d$:", tlbl->key + 100);
6210               outBitC (result);
6211             }
6212           else if (ifx)
6213             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6214         }
6215       else
6216         for (; (size--); offset++)
6217           {
6218             // normal case
6219             // result = left & right
6220             if (AOP_TYPE (right) == AOP_LIT)
6221               {
6222                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
6223                   {
6224                     aopPut (AOP (result),
6225                             aopGet (AOP (left), offset, FALSE, FALSE),
6226                             offset,
6227                             isOperandVolatile (result, FALSE));
6228                     continue;
6229                   }
6230               }
6231             // faster than result <- left, anl result,right
6232             // and better if result is SFR
6233             if (AOP_TYPE (left) == AOP_ACC)
6234               emitcode ("xrl", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
6235             else
6236               {
6237                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE));
6238                 emitcode ("xrl", "a,%s",
6239                           aopGet (AOP (left), offset, FALSE, TRUE));
6240               }
6241             aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
6242           }
6243     }
6244
6245 release:
6246   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6247   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6248   freeAsmop (result, NULL, ic, TRUE);
6249 }
6250
6251 /*-----------------------------------------------------------------*/
6252 /* genInline - write the inline code out                           */
6253 /*-----------------------------------------------------------------*/
6254 static void
6255 genInline (iCode * ic)
6256 {
6257   char *buffer, *bp, *bp1;
6258
6259   D(emitcode (";     genInline",""));
6260
6261   _G.inLine += (!options.asmpeep);
6262
6263   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
6264   strcpy (buffer, IC_INLINE (ic));
6265
6266   /* emit each line as a code */
6267   while (*bp)
6268     {
6269       if (*bp == '\n')
6270         {
6271           *bp++ = '\0';
6272           emitcode (bp1, "");
6273           bp1 = bp;
6274         }
6275       else
6276         {
6277           if (*bp == ':')
6278             {
6279               bp++;
6280               *bp = '\0';
6281               bp++;
6282               emitcode (bp1, "");
6283               bp1 = bp;
6284             }
6285           else
6286             bp++;
6287         }
6288     }
6289   if (bp1 != bp)
6290     emitcode (bp1, "");
6291   /*     emitcode("",buffer); */
6292   _G.inLine -= (!options.asmpeep);
6293 }
6294
6295 /*-----------------------------------------------------------------*/
6296 /* genRRC - rotate right with carry                                */
6297 /*-----------------------------------------------------------------*/
6298 static void
6299 genRRC (iCode * ic)
6300 {
6301   operand *left, *result;
6302   int size, offset = 0;
6303   char *l;
6304
6305   D(emitcode (";     genRRC",""));
6306
6307   /* rotate right with carry */
6308   left = IC_LEFT (ic);
6309   result = IC_RESULT (ic);
6310   aopOp (left, ic, FALSE);
6311   aopOp (result, ic, FALSE);
6312
6313   /* move it to the result */
6314   size = AOP_SIZE (result);
6315   offset = size - 1;
6316   if (size == 1) { /* special case for 1 byte */
6317       l = aopGet (AOP (left), offset, FALSE, FALSE);
6318       MOVA (l);
6319       emitcode ("rr", "a");
6320       goto release;
6321   }
6322   CLRC;
6323   while (size--)
6324     {
6325       l = aopGet (AOP (left), offset, FALSE, FALSE);
6326       MOVA (l);
6327       emitcode ("rrc", "a");
6328       if (AOP_SIZE (result) > 1)
6329         aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
6330     }
6331   /* now we need to put the carry into the
6332      highest order byte of the result */
6333   if (AOP_SIZE (result) > 1)
6334     {
6335       l = aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE);
6336       MOVA (l);
6337     }
6338   emitcode ("mov", "acc.7,c");
6339  release:
6340   aopPut (AOP (result), "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
6341   freeAsmop (left, NULL, ic, TRUE);
6342   freeAsmop (result, NULL, ic, TRUE);
6343 }
6344
6345 /*-----------------------------------------------------------------*/
6346 /* genRLC - generate code for rotate left with carry               */
6347 /*-----------------------------------------------------------------*/
6348 static void
6349 genRLC (iCode * ic)
6350 {
6351   operand *left, *result;
6352   int size, offset = 0;
6353   char *l;
6354
6355   D(emitcode (";     genRLC",""));
6356
6357   /* rotate right with carry */
6358   left = IC_LEFT (ic);
6359   result = IC_RESULT (ic);
6360   aopOp (left, ic, FALSE);
6361   aopOp (result, ic, FALSE);
6362
6363   /* move it to the result */
6364   size = AOP_SIZE (result);
6365   offset = 0;
6366   if (size--)
6367     {
6368       l = aopGet (AOP (left), offset, FALSE, FALSE);
6369       MOVA (l);
6370       if (size == 0) { /* special case for 1 byte */
6371               emitcode("rl","a");
6372               goto release;
6373       }
6374       emitcode ("add", "a,acc");
6375       if (AOP_SIZE (result) > 1)
6376         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6377       while (size--)
6378         {
6379           l = aopGet (AOP (left), offset, FALSE, FALSE);
6380           MOVA (l);
6381           emitcode ("rlc", "a");
6382           if (AOP_SIZE (result) > 1)
6383             aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
6384         }
6385     }
6386   /* now we need to put the carry into the
6387      highest order byte of the result */
6388   if (AOP_SIZE (result) > 1)
6389     {
6390       l = aopGet (AOP (result), 0, FALSE, FALSE);
6391       MOVA (l);
6392     }
6393   emitcode ("mov", "acc.0,c");
6394  release:
6395   aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6396   freeAsmop (left, NULL, ic, TRUE);
6397   freeAsmop (result, NULL, ic, TRUE);
6398 }
6399
6400 /*-----------------------------------------------------------------*/
6401 /* genGetHbit - generates code get highest order bit               */
6402 /*-----------------------------------------------------------------*/
6403 static void
6404 genGetHbit (iCode * ic)
6405 {
6406   operand *left, *result;
6407
6408   D(emitcode (";     genGetHbit",""));
6409
6410   left = IC_LEFT (ic);
6411   result = IC_RESULT (ic);
6412   aopOp (left, ic, FALSE);
6413   aopOp (result, ic, FALSE);
6414
6415   /* get the highest order byte into a */
6416   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE));
6417   if (AOP_TYPE (result) == AOP_CRY)
6418     {
6419       emitcode ("rlc", "a");
6420       outBitC (result);
6421     }
6422   else
6423     {
6424       emitcode ("rl", "a");
6425       emitcode ("anl", "a,#0x01");
6426       outAcc (result);
6427     }
6428
6429
6430   freeAsmop (left, NULL, ic, TRUE);
6431   freeAsmop (result, NULL, ic, TRUE);
6432 }
6433
6434 /*-----------------------------------------------------------------*/
6435 /* genSwap - generates code to swap nibbles or bytes               */
6436 /*-----------------------------------------------------------------*/
6437 static void
6438 genSwap (iCode * ic)
6439 {
6440   operand *left, *result;
6441
6442   D(emitcode (";     genSwap",""));
6443
6444   left = IC_LEFT (ic);
6445   result = IC_RESULT (ic);
6446   aopOp (left, ic, FALSE);
6447   aopOp (result, ic, FALSE);
6448
6449   switch (AOP_SIZE (left))
6450     {
6451     case 1: /* swap nibbles in byte */
6452       MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6453       emitcode ("swap", "a");
6454       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
6455       break;
6456     case 2: /* swap bytes in word */
6457       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
6458         {
6459           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6460           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6461                   0, isOperandVolatile (result, FALSE));
6462           aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
6463         }
6464       else if (operandsEqu (left, result))
6465         {
6466           char * reg = "a";
6467           MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
6468           if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
6469             {
6470               emitcode ("mov", "b,a");
6471               reg = "b";
6472             }
6473           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6474                   0, isOperandVolatile (result, FALSE));
6475           aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
6476         }
6477       else
6478         {
6479           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
6480                   0, isOperandVolatile (result, FALSE));
6481           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
6482                   1, isOperandVolatile (result, FALSE));
6483         }
6484       break;
6485     default:
6486       wassertl(FALSE, "unsupported SWAP operand size");
6487     }
6488
6489   freeAsmop (left, NULL, ic, TRUE);
6490   freeAsmop (result, NULL, ic, TRUE);
6491 }
6492
6493
6494 /*-----------------------------------------------------------------*/
6495 /* AccRol - rotate left accumulator by known count                 */
6496 /*-----------------------------------------------------------------*/
6497 static void
6498 AccRol (int shCount)
6499 {
6500   shCount &= 0x0007;            // shCount : 0..7
6501
6502   switch (shCount)
6503     {
6504     case 0:
6505       break;
6506     case 1:
6507       emitcode ("rl", "a");
6508       break;
6509     case 2:
6510       emitcode ("rl", "a");
6511       emitcode ("rl", "a");
6512       break;
6513     case 3:
6514       emitcode ("swap", "a");
6515       emitcode ("rr", "a");
6516       break;
6517     case 4:
6518       emitcode ("swap", "a");
6519       break;
6520     case 5:
6521       emitcode ("swap", "a");
6522       emitcode ("rl", "a");
6523       break;
6524     case 6:
6525       emitcode ("rr", "a");
6526       emitcode ("rr", "a");
6527       break;
6528     case 7:
6529       emitcode ("rr", "a");
6530       break;
6531     }
6532 }
6533
6534 /*-----------------------------------------------------------------*/
6535 /* AccLsh - left shift accumulator by known count                  */
6536 /*-----------------------------------------------------------------*/
6537 static void
6538 AccLsh (int shCount)
6539 {
6540   if (shCount != 0)
6541     {
6542       if (shCount == 1)
6543         emitcode ("add", "a,acc");
6544       else if (shCount == 2)
6545         {
6546           emitcode ("add", "a,acc");
6547           emitcode ("add", "a,acc");
6548         }
6549       else
6550         {
6551           /* rotate left accumulator */
6552           AccRol (shCount);
6553           /* and kill the lower order bits */
6554           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
6555         }
6556     }
6557 }
6558
6559 /*-----------------------------------------------------------------*/
6560 /* AccRsh - right shift accumulator by known count                 */
6561 /*-----------------------------------------------------------------*/
6562 static void
6563 AccRsh (int shCount)
6564 {
6565   if (shCount != 0)
6566     {
6567       if (shCount == 1)
6568         {
6569           CLRC;
6570           emitcode ("rrc", "a");
6571         }
6572       else
6573         {
6574           /* rotate right accumulator */
6575           AccRol (8 - shCount);
6576           /* and kill the higher order bits */
6577           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6578         }
6579     }
6580 }
6581
6582 /*-----------------------------------------------------------------*/
6583 /* AccSRsh - signed right shift accumulator by known count                 */
6584 /*-----------------------------------------------------------------*/
6585 static void
6586 AccSRsh (int shCount)
6587 {
6588   symbol *tlbl;
6589   if (shCount != 0)
6590     {
6591       if (shCount == 1)
6592         {
6593           emitcode ("mov", "c,acc.7");
6594           emitcode ("rrc", "a");
6595         }
6596       else if (shCount == 2)
6597         {
6598           emitcode ("mov", "c,acc.7");
6599           emitcode ("rrc", "a");
6600           emitcode ("mov", "c,acc.7");
6601           emitcode ("rrc", "a");
6602         }
6603       else
6604         {
6605           tlbl = newiTempLabel (NULL);
6606           /* rotate right accumulator */
6607           AccRol (8 - shCount);
6608           /* and kill the higher order bits */
6609           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
6610           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6611           emitcode ("orl", "a,#0x%02x",
6612                     (unsigned char) ~SRMask[shCount]);
6613           emitcode ("", "%05d$:", tlbl->key + 100);
6614         }
6615     }
6616 }
6617
6618 /*-----------------------------------------------------------------*/
6619 /* shiftR1Left2Result - shift right one byte from left to result   */
6620 /*-----------------------------------------------------------------*/
6621 static void
6622 shiftR1Left2Result (operand * left, int offl,
6623                     operand * result, int offr,
6624                     int shCount, int sign)
6625 {
6626   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6627   /* shift right accumulator */
6628   if (sign)
6629     AccSRsh (shCount);
6630   else
6631     AccRsh (shCount);
6632   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6633 }
6634
6635 /*-----------------------------------------------------------------*/
6636 /* shiftL1Left2Result - shift left one byte from left to result    */
6637 /*-----------------------------------------------------------------*/
6638 static void
6639 shiftL1Left2Result (operand * left, int offl,
6640                     operand * result, int offr, int shCount)
6641 {
6642   char *l;
6643   l = aopGet (AOP (left), offl, FALSE, FALSE);
6644   MOVA (l);
6645   /* shift left accumulator */
6646   AccLsh (shCount);
6647   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6648 }
6649
6650 /*-----------------------------------------------------------------*/
6651 /* movLeft2Result - move byte from left to result                  */
6652 /*-----------------------------------------------------------------*/
6653 static void
6654 movLeft2Result (operand * left, int offl,
6655                 operand * result, int offr, int sign)
6656 {
6657   char *l;
6658   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
6659     {
6660       l = aopGet (AOP (left), offl, FALSE, FALSE);
6661
6662       if (*l == '@' && (IS_AOP_PREG (result)))
6663         {
6664           emitcode ("mov", "a,%s", l);
6665           aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6666         }
6667       else
6668         {
6669           if (!sign)
6670             aopPut (AOP (result), l, offr, isOperandVolatile (result, FALSE));
6671           else
6672             {
6673               /* MSB sign in acc.7 ! */
6674               if (getDataSize (left) == offl + 1)
6675                 {
6676                   emitcode ("mov", "a,%s", l);
6677                   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
6678                 }
6679             }
6680         }
6681     }
6682 }
6683
6684 /*-----------------------------------------------------------------*/
6685 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
6686 /*-----------------------------------------------------------------*/
6687 static void
6688 AccAXRrl1 (char *x)
6689 {
6690   emitcode ("rrc", "a");
6691   emitcode ("xch", "a,%s", x);
6692   emitcode ("rrc", "a");
6693   emitcode ("xch", "a,%s", x);
6694 }
6695
6696 /*-----------------------------------------------------------------*/
6697 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
6698 /*-----------------------------------------------------------------*/
6699 static void
6700 AccAXLrl1 (char *x)
6701 {
6702   emitcode ("xch", "a,%s", x);
6703   emitcode ("rlc", "a");
6704   emitcode ("xch", "a,%s", x);
6705   emitcode ("rlc", "a");
6706 }
6707
6708 /*-----------------------------------------------------------------*/
6709 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
6710 /*-----------------------------------------------------------------*/
6711 static void
6712 AccAXLsh1 (char *x)
6713 {
6714   emitcode ("xch", "a,%s", x);
6715   emitcode ("add", "a,acc");
6716   emitcode ("xch", "a,%s", x);
6717   emitcode ("rlc", "a");
6718 }
6719
6720 /*-----------------------------------------------------------------*/
6721 /* AccAXLsh - left shift a:x by known count (0..7)                 */
6722 /*-----------------------------------------------------------------*/
6723 static void
6724 AccAXLsh (char *x, int shCount)
6725 {
6726   switch (shCount)
6727     {
6728     case 0:
6729       break;
6730     case 1:
6731       AccAXLsh1 (x);
6732       break;
6733     case 2:
6734       AccAXLsh1 (x);
6735       AccAXLsh1 (x);
6736       break;
6737     case 3:
6738     case 4:
6739     case 5:                     // AAAAABBB:CCCCCDDD
6740
6741       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
6742
6743       emitcode ("anl", "a,#0x%02x",
6744                 SLMask[shCount]);       // BBB00000:CCCCCDDD
6745
6746       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
6747
6748       AccRol (shCount);         // DDDCCCCC:BBB00000
6749
6750       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
6751
6752       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
6753
6754       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
6755
6756       emitcode ("anl", "a,#0x%02x",
6757                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
6758
6759       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
6760
6761       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
6762
6763       break;
6764     case 6:                     // AAAAAABB:CCCCCCDD
6765       emitcode ("anl", "a,#0x%02x",
6766                 SRMask[shCount]);       // 000000BB:CCCCCCDD
6767       emitcode ("mov", "c,acc.0");      // c = B
6768       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
6769 #if 0 // REMOVE ME
6770       AccAXRrl1 (x);            // BCCCCCCD:D000000B
6771       AccAXRrl1 (x);            // BBCCCCCC:DD000000
6772 #else
6773       emitcode("rrc","a");
6774       emitcode("xch","a,%s", x);
6775       emitcode("rrc","a");
6776       emitcode("mov","c,acc.0"); //<< get correct bit
6777       emitcode("xch","a,%s", x);
6778
6779       emitcode("rrc","a");
6780       emitcode("xch","a,%s", x);
6781       emitcode("rrc","a");
6782       emitcode("xch","a,%s", x);
6783 #endif
6784       break;
6785     case 7:                     // a:x <<= 7
6786
6787       emitcode ("anl", "a,#0x%02x",
6788                 SRMask[shCount]);       // 0000000B:CCCCCCCD
6789
6790       emitcode ("mov", "c,acc.0");      // c = B
6791
6792       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
6793
6794       AccAXRrl1 (x);            // BCCCCCCC:D0000000
6795
6796       break;
6797     default:
6798       break;
6799     }
6800 }
6801
6802 /*-----------------------------------------------------------------*/
6803 /* AccAXRsh - right shift a:x known count (0..7)                   */
6804 /*-----------------------------------------------------------------*/
6805 static void
6806 AccAXRsh (char *x, int shCount)
6807 {
6808   switch (shCount)
6809     {
6810     case 0:
6811       break;
6812     case 1:
6813       CLRC;
6814       AccAXRrl1 (x);            // 0->a:x
6815
6816       break;
6817     case 2:
6818       CLRC;
6819       AccAXRrl1 (x);            // 0->a:x
6820
6821       CLRC;
6822       AccAXRrl1 (x);            // 0->a:x
6823
6824       break;
6825     case 3:
6826     case 4:
6827     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6828
6829       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
6830
6831       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6832
6833       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6834
6835       emitcode ("anl", "a,#0x%02x",
6836                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6837
6838       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6839
6840       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6841
6842       emitcode ("anl", "a,#0x%02x",
6843                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6844
6845       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6846
6847       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6848
6849       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
6850
6851       break;
6852     case 6:                     // AABBBBBB:CCDDDDDD
6853
6854       emitcode ("mov", "c,acc.7");
6855       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6856
6857       emitcode ("mov", "c,acc.7");
6858       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6859
6860       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6861
6862       emitcode ("anl", "a,#0x%02x",
6863                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6864
6865       break;
6866     case 7:                     // ABBBBBBB:CDDDDDDD
6867
6868       emitcode ("mov", "c,acc.7");      // c = A
6869
6870       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6871
6872       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6873
6874       emitcode ("anl", "a,#0x%02x",
6875                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6876
6877       break;
6878     default:
6879       break;
6880     }
6881 }
6882
6883 /*-----------------------------------------------------------------*/
6884 /* AccAXRshS - right shift signed a:x known count (0..7)           */
6885 /*-----------------------------------------------------------------*/
6886 static void
6887 AccAXRshS (char *x, int shCount)
6888 {
6889   symbol *tlbl;
6890   switch (shCount)
6891     {
6892     case 0:
6893       break;
6894     case 1:
6895       emitcode ("mov", "c,acc.7");
6896       AccAXRrl1 (x);            // s->a:x
6897
6898       break;
6899     case 2:
6900       emitcode ("mov", "c,acc.7");
6901       AccAXRrl1 (x);            // s->a:x
6902
6903       emitcode ("mov", "c,acc.7");
6904       AccAXRrl1 (x);            // s->a:x
6905
6906       break;
6907     case 3:
6908     case 4:
6909     case 5:                     // AAAAABBB:CCCCCDDD = a:x
6910
6911       tlbl = newiTempLabel (NULL);
6912       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
6913
6914       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
6915
6916       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
6917
6918       emitcode ("anl", "a,#0x%02x",
6919                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
6920
6921       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
6922
6923       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
6924
6925       emitcode ("anl", "a,#0x%02x",
6926                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
6927
6928       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
6929
6930       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
6931
6932       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
6933
6934       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6935       emitcode ("orl", "a,#0x%02x",
6936                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
6937
6938       emitcode ("", "%05d$:", tlbl->key + 100);
6939       break;                    // SSSSAAAA:BBBCCCCC
6940
6941     case 6:                     // AABBBBBB:CCDDDDDD
6942
6943       tlbl = newiTempLabel (NULL);
6944       emitcode ("mov", "c,acc.7");
6945       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
6946
6947       emitcode ("mov", "c,acc.7");
6948       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
6949
6950       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
6951
6952       emitcode ("anl", "a,#0x%02x",
6953                 SRMask[shCount]);       // 000000AA:BBBBBBCC
6954
6955       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6956       emitcode ("orl", "a,#0x%02x",
6957                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
6958
6959       emitcode ("", "%05d$:", tlbl->key + 100);
6960       break;
6961     case 7:                     // ABBBBBBB:CDDDDDDD
6962
6963       tlbl = newiTempLabel (NULL);
6964       emitcode ("mov", "c,acc.7");      // c = A
6965
6966       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
6967
6968       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
6969
6970       emitcode ("anl", "a,#0x%02x",
6971                 SRMask[shCount]);       // 0000000A:BBBBBBBC
6972
6973       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
6974       emitcode ("orl", "a,#0x%02x",
6975                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
6976
6977       emitcode ("", "%05d$:", tlbl->key + 100);
6978       break;
6979     default:
6980       break;
6981     }
6982 }
6983
6984 /*-----------------------------------------------------------------*/
6985 /* shiftL2Left2Result - shift left two bytes from left to result   */
6986 /*-----------------------------------------------------------------*/
6987 static void
6988 shiftL2Left2Result (operand * left, int offl,
6989                     operand * result, int offr, int shCount)
6990 {
6991   if (sameRegs (AOP (result), AOP (left)) &&
6992       ((offl + MSB16) == offr))
6993     {
6994       /* don't crash result[offr] */
6995       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
6996       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
6997     }
6998   else
6999     {
7000       movLeft2Result (left, offl, result, offr, 0);
7001       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7002     }
7003   /* ax << shCount (x = lsb(result)) */
7004   AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7005   aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7006 }
7007
7008
7009 /*-----------------------------------------------------------------*/
7010 /* shiftR2Left2Result - shift right two bytes from left to result  */
7011 /*-----------------------------------------------------------------*/
7012 static void
7013 shiftR2Left2Result (operand * left, int offl,
7014                     operand * result, int offr,
7015                     int shCount, int sign)
7016 {
7017   if (sameRegs (AOP (result), AOP (left)) &&
7018       ((offl + MSB16) == offr))
7019     {
7020       /* don't crash result[offr] */
7021       MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7022       emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7023     }
7024   else
7025     {
7026       movLeft2Result (left, offl, result, offr, 0);
7027       MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE));
7028     }
7029   /* a:x >> shCount (x = lsb(result)) */
7030   if (sign)
7031     AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7032   else
7033     AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE), shCount);
7034   if (getDataSize (result) > 1)
7035     aopPut (AOP (result), "a", offr + MSB16, isOperandVolatile (result, FALSE));
7036 }
7037
7038 /*-----------------------------------------------------------------*/
7039 /* shiftLLeftOrResult - shift left one byte from left, or to result */
7040 /*-----------------------------------------------------------------*/
7041 static void
7042 shiftLLeftOrResult (operand * left, int offl,
7043                     operand * result, int offr, int shCount)
7044 {
7045   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7046   /* shift left accumulator */
7047   AccLsh (shCount);
7048   /* or with result */
7049   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7050   /* back to result */
7051   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7052 }
7053
7054 /*-----------------------------------------------------------------*/
7055 /* shiftRLeftOrResult - shift right one byte from left,or to result */
7056 /*-----------------------------------------------------------------*/
7057 static void
7058 shiftRLeftOrResult (operand * left, int offl,
7059                     operand * result, int offr, int shCount)
7060 {
7061   MOVA (aopGet (AOP (left), offl, FALSE, FALSE));
7062   /* shift right accumulator */
7063   AccRsh (shCount);
7064   /* or with result */
7065   emitcode ("orl", "a,%s", aopGet (AOP (result), offr, FALSE, FALSE));
7066   /* back to result */
7067   aopPut (AOP (result), "a", offr, isOperandVolatile (result, FALSE));
7068 }
7069
7070 /*-----------------------------------------------------------------*/
7071 /* genlshOne - left shift a one byte quantity by known count       */
7072 /*-----------------------------------------------------------------*/
7073 static void
7074 genlshOne (operand * result, operand * left, int shCount)
7075 {
7076   D(emitcode (";     genlshOne",""));
7077
7078   shiftL1Left2Result (left, LSB, result, LSB, shCount);
7079 }
7080
7081 /*-----------------------------------------------------------------*/
7082 /* genlshTwo - left shift two bytes by known amount != 0           */
7083 /*-----------------------------------------------------------------*/
7084 static void
7085 genlshTwo (operand * result, operand * left, int shCount)
7086 {
7087   int size;
7088
7089   D(emitcode (";     genlshTwo",""));
7090
7091   size = getDataSize (result);
7092
7093   /* if shCount >= 8 */
7094   if (shCount >= 8)
7095     {
7096       shCount -= 8;
7097
7098       if (size > 1)
7099         {
7100           if (shCount)
7101             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7102           else
7103             movLeft2Result (left, LSB, result, MSB16, 0);
7104         }
7105       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7106     }
7107
7108   /*  1 <= shCount <= 7 */
7109   else
7110     {
7111       if (size == 1)
7112         shiftL1Left2Result (left, LSB, result, LSB, shCount);
7113       else
7114         shiftL2Left2Result (left, LSB, result, LSB, shCount);
7115     }
7116 }
7117
7118 /*-----------------------------------------------------------------*/
7119 /* shiftLLong - shift left one long from left to result            */
7120 /* offl = LSB or MSB16                                             */
7121 /*-----------------------------------------------------------------*/
7122 static void
7123 shiftLLong (operand * left, operand * result, int offr)
7124 {
7125   char *l;
7126   int size = AOP_SIZE (result);
7127
7128   if (size >= LSB + offr)
7129     {
7130       l = aopGet (AOP (left), LSB, FALSE, FALSE);
7131       MOVA (l);
7132       emitcode ("add", "a,acc");
7133       if (sameRegs (AOP (left), AOP (result)) &&
7134           size >= MSB16 + offr && offr != LSB)
7135         emitcode ("xch", "a,%s",
7136                   aopGet (AOP (left), LSB + offr, FALSE, FALSE));
7137       else
7138         aopPut (AOP (result), "a", LSB + offr, isOperandVolatile (result, FALSE));
7139     }
7140
7141   if (size >= MSB16 + offr)
7142     {
7143       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
7144         {
7145           l = aopGet (AOP (left), MSB16, FALSE, FALSE);
7146           MOVA (l);
7147         }
7148       emitcode ("rlc", "a");
7149       if (sameRegs (AOP (left), AOP (result)) &&
7150           size >= MSB24 + offr && offr != LSB)
7151         emitcode ("xch", "a,%s",
7152                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE));
7153       else
7154         aopPut (AOP (result), "a", MSB16 + offr, isOperandVolatile (result, FALSE));
7155     }
7156
7157   if (size >= MSB24 + offr)
7158     {
7159       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
7160         {
7161           l = aopGet (AOP (left), MSB24, FALSE, FALSE);
7162           MOVA (l);
7163         }
7164       emitcode ("rlc", "a");
7165       if (sameRegs (AOP (left), AOP (result)) &&
7166           size >= MSB32 + offr && offr != LSB)
7167         emitcode ("xch", "a,%s",
7168                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE));
7169       else
7170         aopPut (AOP (result), "a", MSB24 + offr, isOperandVolatile (result, FALSE));
7171     }
7172
7173   if (size > MSB32 + offr)
7174     {
7175       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
7176         {
7177           l = aopGet (AOP (left), MSB32, FALSE, FALSE);
7178           MOVA (l);
7179         }
7180       emitcode ("rlc", "a");
7181       aopPut (AOP (result), "a", MSB32 + offr, isOperandVolatile (result, FALSE));
7182     }
7183   if (offr != LSB)
7184     aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7185 }
7186
7187 /*-----------------------------------------------------------------*/
7188 /* genlshFour - shift four byte by a known amount != 0             */
7189 /*-----------------------------------------------------------------*/
7190 static void
7191 genlshFour (operand * result, operand * left, int shCount)
7192 {
7193   int size;
7194
7195   D(emitcode (";     genlshFour",""));
7196
7197   size = AOP_SIZE (result);
7198
7199   /* if shifting more that 3 bytes */
7200   if (shCount >= 24)
7201     {
7202       shCount -= 24;
7203       if (shCount)
7204         /* lowest order of left goes to the highest
7205            order of the destination */
7206         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
7207       else
7208         movLeft2Result (left, LSB, result, MSB32, 0);
7209       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7210       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7211       aopPut (AOP (result), zero, MSB24, isOperandVolatile (result, FALSE));
7212       return;
7213     }
7214
7215   /* more than two bytes */
7216   else if (shCount >= 16)
7217     {
7218       /* lower order two bytes goes to higher order two bytes */
7219       shCount -= 16;
7220       /* if some more remaining */
7221       if (shCount)
7222         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
7223       else
7224         {
7225           movLeft2Result (left, MSB16, result, MSB32, 0);
7226           movLeft2Result (left, LSB, result, MSB24, 0);
7227         }
7228       aopPut (AOP (result), zero, MSB16, isOperandVolatile (result, FALSE));
7229       aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7230       return;
7231     }
7232
7233   /* if more than 1 byte */
7234   else if (shCount >= 8)
7235     {
7236       /* lower order three bytes goes to higher order  three bytes */
7237       shCount -= 8;
7238       if (size == 2)
7239         {
7240           if (shCount)
7241             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7242           else
7243             movLeft2Result (left, LSB, result, MSB16, 0);
7244         }
7245       else
7246         {                       /* size = 4 */
7247           if (shCount == 0)
7248             {
7249               movLeft2Result (left, MSB24, result, MSB32, 0);
7250               movLeft2Result (left, MSB16, result, MSB24, 0);
7251               movLeft2Result (left, LSB, result, MSB16, 0);
7252               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7253             }
7254           else if (shCount == 1)
7255             shiftLLong (left, result, MSB16);
7256           else
7257             {
7258               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
7259               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
7260               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
7261               aopPut (AOP (result), zero, LSB, isOperandVolatile (result, FALSE));
7262             }
7263         }
7264     }
7265
7266   /* 1 <= shCount <= 7 */
7267   else if (shCount <= 2)
7268     {
7269       shiftLLong (left, result, LSB);
7270       if (shCount == 2)
7271         shiftLLong (result, result, LSB);
7272     }
7273   /* 3 <= shCount <= 7, optimize */
7274   else
7275     {
7276       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
7277       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
7278       shiftL2Left2Result (left, LSB, result, LSB, shCount);
7279     }
7280 }
7281
7282 /*-----------------------------------------------------------------*/
7283 /* genLeftShiftLiteral - left shifting by known count              */
7284 /*-----------------------------------------------------------------*/
7285 static void
7286 genLeftShiftLiteral (operand * left,
7287                      operand * right,
7288                      operand * result,
7289                      iCode * ic)
7290 {
7291   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7292   int size;
7293
7294   D(emitcode (";     genLeftShiftLiteral",""));
7295
7296   freeAsmop (right, NULL, ic, TRUE);
7297
7298   aopOp (left, ic, FALSE);
7299   aopOp (result, ic, FALSE);
7300
7301   size = getSize (operandType (result));
7302
7303 #if VIEW_SIZE
7304   emitcode ("; shift left ", "result %d, left %d", size,
7305             AOP_SIZE (left));
7306 #endif
7307
7308   /* I suppose that the left size >= result size */
7309   if (shCount == 0)
7310     {
7311       while (size--)
7312         {
7313           movLeft2Result (left, size, result, size, 0);
7314         }
7315     }
7316
7317   else if (shCount >= (size * 8))
7318     while (size--)
7319       aopPut (AOP (result), zero, size, isOperandVolatile (result, FALSE));
7320   else
7321     {
7322       switch (size)
7323         {
7324         case 1:
7325           genlshOne (result, left, shCount);
7326           break;
7327
7328         case 2:
7329           genlshTwo (result, left, shCount);
7330           break;
7331
7332         case 4:
7333           genlshFour (result, left, shCount);
7334           break;
7335         default:
7336           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7337                   "*** ack! mystery literal shift!\n");
7338           break;
7339         }
7340     }
7341   freeAsmop (left, NULL, ic, TRUE);
7342   freeAsmop (result, NULL, ic, TRUE);
7343 }
7344
7345 /*-----------------------------------------------------------------*/
7346 /* genLeftShift - generates code for left shifting                 */
7347 /*-----------------------------------------------------------------*/
7348 static void
7349 genLeftShift (iCode * ic)
7350 {
7351   operand *left, *right, *result;
7352   int size, offset;
7353   char *l;
7354   symbol *tlbl, *tlbl1;
7355
7356   D(emitcode (";     genLeftShift",""));
7357
7358   right = IC_RIGHT (ic);
7359   left = IC_LEFT (ic);
7360   result = IC_RESULT (ic);
7361
7362   aopOp (right, ic, FALSE);
7363
7364   /* if the shift count is known then do it
7365      as efficiently as possible */
7366   if (AOP_TYPE (right) == AOP_LIT)
7367     {
7368       genLeftShiftLiteral (left, right, result, ic);
7369       return;
7370     }
7371
7372   /* shift count is unknown then we have to form
7373      a loop get the loop count in B : Note: we take
7374      only the lower order byte since shifting
7375      more that 32 bits make no sense anyway, ( the
7376      largest size of an object can be only 32 bits ) */
7377
7378   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7379   emitcode ("inc", "b");
7380   freeAsmop (right, NULL, ic, TRUE);
7381   aopOp (left, ic, FALSE);
7382   aopOp (result, ic, FALSE);
7383
7384   /* now move the left to the result if they are not the
7385      same */
7386   if (!sameRegs (AOP (left), AOP (result)) &&
7387       AOP_SIZE (result) > 1)
7388     {
7389
7390       size = AOP_SIZE (result);
7391       offset = 0;
7392       while (size--)
7393         {
7394           l = aopGet (AOP (left), offset, FALSE, TRUE);
7395           if (*l == '@' && (IS_AOP_PREG (result)))
7396             {
7397
7398               emitcode ("mov", "a,%s", l);
7399               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7400             }
7401           else
7402             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7403           offset++;
7404         }
7405     }
7406
7407   tlbl = newiTempLabel (NULL);
7408   size = AOP_SIZE (result);
7409   offset = 0;
7410   tlbl1 = newiTempLabel (NULL);
7411
7412   /* if it is only one byte then */
7413   if (size == 1)
7414     {
7415       symbol *tlbl1 = newiTempLabel (NULL);
7416
7417       l = aopGet (AOP (left), 0, FALSE, FALSE);
7418       MOVA (l);
7419       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7420       emitcode ("", "%05d$:", tlbl->key + 100);
7421       emitcode ("add", "a,acc");
7422       emitcode ("", "%05d$:", tlbl1->key + 100);
7423       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7424       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7425       goto release;
7426     }
7427
7428   reAdjustPreg (AOP (result));
7429
7430   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7431   emitcode ("", "%05d$:", tlbl->key + 100);
7432   l = aopGet (AOP (result), offset, FALSE, FALSE);
7433   MOVA (l);
7434   emitcode ("add", "a,acc");
7435   aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7436   while (--size)
7437     {
7438       l = aopGet (AOP (result), offset, FALSE, FALSE);
7439       MOVA (l);
7440       emitcode ("rlc", "a");
7441       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
7442     }
7443   reAdjustPreg (AOP (result));
7444
7445   emitcode ("", "%05d$:", tlbl1->key + 100);
7446   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7447 release:
7448   freeAsmop (left, NULL, ic, TRUE);
7449   freeAsmop (result, NULL, ic, TRUE);
7450 }
7451
7452 /*-----------------------------------------------------------------*/
7453 /* genrshOne - right shift a one byte quantity by known count      */
7454 /*-----------------------------------------------------------------*/
7455 static void
7456 genrshOne (operand * result, operand * left,
7457            int shCount, int sign)
7458 {
7459   D(emitcode (";     genrshOne",""));
7460
7461   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
7462 }
7463
7464 /*-----------------------------------------------------------------*/
7465 /* genrshTwo - right shift two bytes by known amount != 0          */
7466 /*-----------------------------------------------------------------*/
7467 static void
7468 genrshTwo (operand * result, operand * left,
7469            int shCount, int sign)
7470 {
7471   D(emitcode (";     genrshTwo",""));
7472
7473   /* if shCount >= 8 */
7474   if (shCount >= 8)
7475     {
7476       shCount -= 8;
7477       if (shCount)
7478         shiftR1Left2Result (left, MSB16, result, LSB,
7479                             shCount, sign);
7480       else
7481         movLeft2Result (left, MSB16, result, LSB, sign);
7482       addSign (result, MSB16, sign);
7483     }
7484
7485   /*  1 <= shCount <= 7 */
7486   else
7487     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
7488 }
7489
7490 /*-----------------------------------------------------------------*/
7491 /* shiftRLong - shift right one long from left to result           */
7492 /* offl = LSB or MSB16                                             */
7493 /*-----------------------------------------------------------------*/
7494 static void
7495 shiftRLong (operand * left, int offl,
7496             operand * result, int sign)
7497 {
7498   int isSameRegs=sameRegs(AOP(left),AOP(result));
7499
7500   if (isSameRegs && offl>1) {
7501     // we are in big trouble, but this shouldn't happen
7502     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
7503   }
7504
7505   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7506
7507   if (offl==MSB16) {
7508     // shift is > 8
7509     if (sign) {
7510       emitcode ("rlc", "a");
7511       emitcode ("subb", "a,acc");
7512       if (isSameRegs)
7513         emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
7514       else {
7515         aopPut (AOP (result), "a", MSB32, isOperandVolatile (result, FALSE));
7516         MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
7517       }
7518     } else {
7519       aopPut (AOP(result), zero, MSB32, isOperandVolatile (result, FALSE));
7520     }
7521   }
7522
7523   if (!sign) {
7524     emitcode ("clr", "c");
7525   } else {
7526     emitcode ("mov", "c,acc.7");
7527   }
7528
7529   emitcode ("rrc", "a");
7530
7531   if (isSameRegs && offl==MSB16) {
7532     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
7533   } else {
7534     aopPut (AOP (result), "a", MSB32-offl, isOperandVolatile (result, FALSE));
7535     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
7536   }
7537
7538   emitcode ("rrc", "a");
7539   if (isSameRegs && offl==1) {
7540     emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
7541   } else {
7542     aopPut (AOP (result), "a", MSB24-offl, isOperandVolatile (result, FALSE));
7543     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
7544   }
7545   emitcode ("rrc", "a");
7546   aopPut (AOP (result), "a", MSB16 - offl, isOperandVolatile (result, FALSE));
7547
7548   if (offl == LSB)
7549     {
7550       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
7551       emitcode ("rrc", "a");
7552       aopPut (AOP (result), "a", LSB, isOperandVolatile (result, FALSE));
7553     }
7554 }
7555
7556 /*-----------------------------------------------------------------*/
7557 /* genrshFour - shift four byte by a known amount != 0             */
7558 /*-----------------------------------------------------------------*/
7559 static void
7560 genrshFour (operand * result, operand * left,
7561             int shCount, int sign)
7562 {
7563   D(emitcode (";     genrshFour",""));
7564
7565   /* if shifting more that 3 bytes */
7566   if (shCount >= 24)
7567     {
7568       shCount -= 24;
7569       if (shCount)
7570         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
7571       else
7572         movLeft2Result (left, MSB32, result, LSB, sign);
7573       addSign (result, MSB16, sign);
7574     }
7575   else if (shCount >= 16)
7576     {
7577       shCount -= 16;
7578       if (shCount)
7579         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
7580       else
7581         {
7582           movLeft2Result (left, MSB24, result, LSB, 0);
7583           movLeft2Result (left, MSB32, result, MSB16, sign);
7584         }
7585       addSign (result, MSB24, sign);
7586     }
7587   else if (shCount >= 8)
7588     {
7589       shCount -= 8;
7590       if (shCount == 1)
7591         shiftRLong (left, MSB16, result, sign);
7592       else if (shCount == 0)
7593         {
7594           movLeft2Result (left, MSB16, result, LSB, 0);
7595           movLeft2Result (left, MSB24, result, MSB16, 0);
7596           movLeft2Result (left, MSB32, result, MSB24, sign);
7597           addSign (result, MSB32, sign);
7598         }
7599       else
7600         {
7601           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
7602           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
7603           /* the last shift is signed */
7604           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
7605           addSign (result, MSB32, sign);
7606         }
7607     }
7608   else
7609     {                           /* 1 <= shCount <= 7 */
7610       if (shCount <= 2)
7611         {
7612           shiftRLong (left, LSB, result, sign);
7613           if (shCount == 2)
7614             shiftRLong (result, LSB, result, sign);
7615         }
7616       else
7617         {
7618           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
7619           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
7620           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
7621         }
7622     }
7623 }
7624
7625 /*-----------------------------------------------------------------*/
7626 /* genRightShiftLiteral - right shifting by known count            */
7627 /*-----------------------------------------------------------------*/
7628 static void
7629 genRightShiftLiteral (operand * left,
7630                       operand * right,
7631                       operand * result,
7632                       iCode * ic,
7633                       int sign)
7634 {
7635   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
7636   int size;
7637
7638   D(emitcode (";     genRightShiftLiteral",""));
7639
7640   freeAsmop (right, NULL, ic, TRUE);
7641
7642   aopOp (left, ic, FALSE);
7643   aopOp (result, ic, FALSE);
7644
7645 #if VIEW_SIZE
7646   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
7647             AOP_SIZE (left));
7648 #endif
7649
7650   size = getDataSize (left);
7651   /* test the LEFT size !!! */
7652
7653   /* I suppose that the left size >= result size */
7654   if (shCount == 0)
7655     {
7656       size = getDataSize (result);
7657       while (size--)
7658         movLeft2Result (left, size, result, size, 0);
7659     }
7660
7661   else if (shCount >= (size * 8))
7662     {
7663       if (sign) {
7664         /* get sign in acc.7 */
7665         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE));
7666       }
7667       addSign (result, LSB, sign);
7668     }
7669   else
7670     {
7671       switch (size)
7672         {
7673         case 1:
7674           genrshOne (result, left, shCount, sign);
7675           break;
7676
7677         case 2:
7678           genrshTwo (result, left, shCount, sign);
7679           break;
7680
7681         case 4:
7682           genrshFour (result, left, shCount, sign);
7683           break;
7684         default:
7685           break;
7686         }
7687     }
7688   freeAsmop (left, NULL, ic, TRUE);
7689   freeAsmop (result, NULL, ic, TRUE);
7690 }
7691
7692 /*-----------------------------------------------------------------*/
7693 /* genSignedRightShift - right shift of signed number              */
7694 /*-----------------------------------------------------------------*/
7695 static void
7696 genSignedRightShift (iCode * ic)
7697 {
7698   operand *right, *left, *result;
7699   int size, offset;
7700   char *l;
7701   symbol *tlbl, *tlbl1;
7702
7703   D(emitcode (";     genSignedRightShift",""));
7704
7705   /* we do it the hard way put the shift count in b
7706      and loop thru preserving the sign */
7707
7708   right = IC_RIGHT (ic);
7709   left = IC_LEFT (ic);
7710   result = IC_RESULT (ic);
7711
7712   aopOp (right, ic, FALSE);
7713
7714
7715   if (AOP_TYPE (right) == AOP_LIT)
7716     {
7717       genRightShiftLiteral (left, right, result, ic, 1);
7718       return;
7719     }
7720   /* shift count is unknown then we have to form
7721      a loop get the loop count in B : Note: we take
7722      only the lower order byte since shifting
7723      more that 32 bits make no sense anyway, ( the
7724      largest size of an object can be only 32 bits ) */
7725
7726   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7727   emitcode ("inc", "b");
7728   freeAsmop (right, NULL, ic, TRUE);
7729   aopOp (left, ic, FALSE);
7730   aopOp (result, ic, FALSE);
7731
7732   /* now move the left to the result if they are not the
7733      same */
7734   if (!sameRegs (AOP (left), AOP (result)) &&
7735       AOP_SIZE (result) > 1)
7736     {
7737
7738       size = AOP_SIZE (result);
7739       offset = 0;
7740       while (size--)
7741         {
7742           l = aopGet (AOP (left), offset, FALSE, TRUE);
7743           if (*l == '@' && IS_AOP_PREG (result))
7744             {
7745
7746               emitcode ("mov", "a,%s", l);
7747               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7748             }
7749           else
7750             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7751           offset++;
7752         }
7753     }
7754
7755   /* mov the highest order bit to OVR */
7756   tlbl = newiTempLabel (NULL);
7757   tlbl1 = newiTempLabel (NULL);
7758
7759   size = AOP_SIZE (result);
7760   offset = size - 1;
7761   MOVA (aopGet (AOP (left), offset, FALSE, FALSE));
7762   emitcode ("rlc", "a");
7763   emitcode ("mov", "ov,c");
7764   /* if it is only one byte then */
7765   if (size == 1)
7766     {
7767       l = aopGet (AOP (left), 0, FALSE, FALSE);
7768       MOVA (l);
7769       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7770       emitcode ("", "%05d$:", tlbl->key + 100);
7771       emitcode ("mov", "c,ov");
7772       emitcode ("rrc", "a");
7773       emitcode ("", "%05d$:", tlbl1->key + 100);
7774       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7775       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7776       goto release;
7777     }
7778
7779   reAdjustPreg (AOP (result));
7780   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7781   emitcode ("", "%05d$:", tlbl->key + 100);
7782   emitcode ("mov", "c,ov");
7783   while (size--)
7784     {
7785       l = aopGet (AOP (result), offset, FALSE, FALSE);
7786       MOVA (l);
7787       emitcode ("rrc", "a");
7788       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7789     }
7790   reAdjustPreg (AOP (result));
7791   emitcode ("", "%05d$:", tlbl1->key + 100);
7792   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7793
7794 release:
7795   freeAsmop (left, NULL, ic, TRUE);
7796   freeAsmop (result, NULL, ic, TRUE);
7797 }
7798
7799 /*-----------------------------------------------------------------*/
7800 /* genRightShift - generate code for right shifting                */
7801 /*-----------------------------------------------------------------*/
7802 static void
7803 genRightShift (iCode * ic)
7804 {
7805   operand *right, *left, *result;
7806   sym_link *letype;
7807   int size, offset;
7808   char *l;
7809   symbol *tlbl, *tlbl1;
7810
7811   D(emitcode (";     genRightShift",""));
7812
7813   /* if signed then we do it the hard way preserve the
7814      sign bit moving it inwards */
7815   letype = getSpec (operandType (IC_LEFT (ic)));
7816
7817   if (!SPEC_USIGN (letype))
7818     {
7819       genSignedRightShift (ic);
7820       return;
7821     }
7822
7823   /* signed & unsigned types are treated the same : i.e. the
7824      signed is NOT propagated inwards : quoting from the
7825      ANSI - standard : "for E1 >> E2, is equivalent to division
7826      by 2**E2 if unsigned or if it has a non-negative value,
7827      otherwise the result is implementation defined ", MY definition
7828      is that the sign does not get propagated */
7829
7830   right = IC_RIGHT (ic);
7831   left = IC_LEFT (ic);
7832   result = IC_RESULT (ic);
7833
7834   aopOp (right, ic, FALSE);
7835
7836   /* if the shift count is known then do it
7837      as efficiently as possible */
7838   if (AOP_TYPE (right) == AOP_LIT)
7839     {
7840       genRightShiftLiteral (left, right, result, ic, 0);
7841       return;
7842     }
7843
7844   /* shift count is unknown then we have to form
7845      a loop get the loop count in B : Note: we take
7846      only the lower order byte since shifting
7847      more that 32 bits make no sense anyway, ( the
7848      largest size of an object can be only 32 bits ) */
7849
7850   emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
7851   emitcode ("inc", "b");
7852   freeAsmop (right, NULL, ic, TRUE);
7853   aopOp (left, ic, FALSE);
7854   aopOp (result, ic, FALSE);
7855
7856   /* now move the left to the result if they are not the
7857      same */
7858   if (!sameRegs (AOP (left), AOP (result)) &&
7859       AOP_SIZE (result) > 1)
7860     {
7861
7862       size = AOP_SIZE (result);
7863       offset = 0;
7864       while (size--)
7865         {
7866           l = aopGet (AOP (left), offset, FALSE, TRUE);
7867           if (*l == '@' && IS_AOP_PREG (result))
7868             {
7869
7870               emitcode ("mov", "a,%s", l);
7871               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
7872             }
7873           else
7874             aopPut (AOP (result), l, offset, isOperandVolatile (result, FALSE));
7875           offset++;
7876         }
7877     }
7878
7879   tlbl = newiTempLabel (NULL);
7880   tlbl1 = newiTempLabel (NULL);
7881   size = AOP_SIZE (result);
7882   offset = size - 1;
7883
7884   /* if it is only one byte then */
7885   if (size == 1)
7886     {
7887       l = aopGet (AOP (left), 0, FALSE, FALSE);
7888       MOVA (l);
7889       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7890       emitcode ("", "%05d$:", tlbl->key + 100);
7891       CLRC;
7892       emitcode ("rrc", "a");
7893       emitcode ("", "%05d$:", tlbl1->key + 100);
7894       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7895       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
7896       goto release;
7897     }
7898
7899   reAdjustPreg (AOP (result));
7900   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
7901   emitcode ("", "%05d$:", tlbl->key + 100);
7902   CLRC;
7903   while (size--)
7904     {
7905       l = aopGet (AOP (result), offset, FALSE, FALSE);
7906       MOVA (l);
7907       emitcode ("rrc", "a");
7908       aopPut (AOP (result), "a", offset--, isOperandVolatile (result, FALSE));
7909     }
7910   reAdjustPreg (AOP (result));
7911
7912   emitcode ("", "%05d$:", tlbl1->key + 100);
7913   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
7914
7915 release:
7916   freeAsmop (left, NULL, ic, TRUE);
7917   freeAsmop (result, NULL, ic, TRUE);
7918 }
7919
7920 /*-----------------------------------------------------------------*/
7921 /* emitPtrByteGet - emits code to get a byte into A through a      */
7922 /*                  pointer register (R0, R1, or DPTR). The        */
7923 /*                  original value of A can be preserved in B.     */
7924 /*-----------------------------------------------------------------*/
7925 static void
7926 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
7927 {
7928   switch (p_type)
7929     {
7930     case IPOINTER:
7931     case POINTER:
7932       if (preserveAinB)
7933         emitcode ("mov", "b,a");
7934       emitcode ("mov", "a,@%s", rname);
7935       break;
7936
7937     case PPOINTER:
7938       if (preserveAinB)
7939         emitcode ("mov", "b,a");
7940       emitcode ("movx", "a,@%s", rname);
7941       break;
7942
7943     case FPOINTER:
7944       if (preserveAinB)
7945         emitcode ("mov", "b,a");
7946       emitcode ("movx", "a,@dptr");
7947       break;
7948
7949     case CPOINTER:
7950       if (preserveAinB)
7951         emitcode ("mov", "b,a");
7952       emitcode ("clr", "a");
7953       emitcode ("movc", "a,@a+dptr");
7954       break;
7955
7956     case GPOINTER:
7957       if (preserveAinB)
7958         {
7959           emitcode ("push", "b");
7960           emitcode ("push", "acc");
7961         }
7962       emitcode ("lcall", "__gptrget");
7963       if (preserveAinB)
7964         emitcode ("pop", "b");
7965       break;
7966     }
7967 }
7968
7969 /*-----------------------------------------------------------------*/
7970 /* emitPtrByteSet - emits code to set a byte from src through a    */
7971 /*                  pointer register (R0, R1, or DPTR).            */
7972 /*-----------------------------------------------------------------*/
7973 static void
7974 emitPtrByteSet (char *rname, int p_type, char *src)
7975 {
7976   switch (p_type)
7977     {
7978     case IPOINTER:
7979     case POINTER:
7980       if (*src=='@')
7981         {
7982           MOVA (src);
7983           emitcode ("mov", "@%s,a", rname);
7984         }
7985       else
7986         emitcode ("mov", "@%s,%s", rname, src);
7987       break;
7988
7989     case PPOINTER:
7990       MOVA (src);
7991       emitcode ("movx", "@%s,a", rname);
7992       break;
7993
7994     case FPOINTER:
7995       MOVA (src);
7996       emitcode ("movx", "@dptr,a");
7997       break;
7998
7999     case GPOINTER:
8000       MOVA (src);
8001       emitcode ("lcall", "__gptrput");
8002       break;
8003     }
8004 }
8005
8006 /*-----------------------------------------------------------------*/
8007 /* genUnpackBits - generates code for unpacking bits               */
8008 /*-----------------------------------------------------------------*/
8009 static void
8010 genUnpackBits (operand * result, char *rname, int ptype)
8011 {
8012   int offset = 0;       /* result byte offset */
8013   int rsize;            /* result size */
8014   int rlen = 0;         /* remaining bitfield length */
8015   sym_link *etype;      /* bitfield type information */
8016   int blen;             /* bitfield length */
8017   int bstr;             /* bitfield starting bit within byte */
8018
8019   D(emitcode (";     genUnpackBits",""));
8020
8021   etype = getSpec (operandType (result));
8022   rsize = getSize (operandType (result));
8023   blen = SPEC_BLEN (etype);
8024   bstr = SPEC_BSTR (etype);
8025
8026   /* If the bitfield length is less than a byte */
8027   if (blen < 8)
8028     {
8029       emitPtrByteGet (rname, ptype, FALSE);
8030       AccRsh (bstr);
8031       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
8032       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8033       goto finish;
8034     }
8035
8036   /* Bit field did not fit in a byte. Copy all
8037      but the partial byte at the end.  */
8038   for (rlen=blen;rlen>=8;rlen-=8)
8039     {
8040       emitPtrByteGet (rname, ptype, FALSE);
8041       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8042       if (rlen>8)
8043         emitcode ("inc", "%s", rname);
8044     }
8045
8046   /* Handle the partial byte at the end */
8047   if (rlen)
8048     {
8049       emitPtrByteGet (rname, ptype, FALSE);
8050       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
8051       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8052     }
8053
8054 finish:
8055   if (offset < rsize)
8056     {
8057       rsize -= offset;
8058       while (rsize--)
8059         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
8060     }
8061 }
8062
8063
8064 /*-----------------------------------------------------------------*/
8065 /* genDataPointerGet - generates code when ptr offset is known     */
8066 /*-----------------------------------------------------------------*/
8067 static void
8068 genDataPointerGet (operand * left,
8069                    operand * result,
8070                    iCode * ic)
8071 {
8072   char *l;
8073   char buffer[256];
8074   int size, offset = 0;
8075
8076   D(emitcode (";     genDataPointerGet",""));
8077
8078   aopOp (result, ic, TRUE);
8079
8080   /* get the string representation of the name */
8081   l = aopGet (AOP (left), 0, FALSE, TRUE);
8082   size = AOP_SIZE (result);
8083   while (size--)
8084     {
8085       if (offset)
8086         sprintf (buffer, "(%s + %d)", l + 1, offset);
8087       else
8088         sprintf (buffer, "%s", l + 1);
8089       aopPut (AOP (result), buffer, offset++, isOperandVolatile (result, FALSE));
8090     }
8091
8092   freeAsmop (left, NULL, ic, TRUE);
8093   freeAsmop (result, NULL, ic, TRUE);
8094 }
8095
8096 /*-----------------------------------------------------------------*/
8097 /* genNearPointerGet - emitcode for near pointer fetch             */
8098 /*-----------------------------------------------------------------*/
8099 static void
8100 genNearPointerGet (operand * left,
8101                    operand * result,
8102                    iCode * ic,
8103                    iCode * pi)
8104 {
8105   asmop *aop = NULL;
8106   regs *preg = NULL;
8107   char *rname;
8108   sym_link *rtype, *retype;
8109   sym_link *ltype = operandType (left);
8110   char buffer[80];
8111
8112   D(emitcode (";     genNearPointerGet",""));
8113
8114   rtype = operandType (result);
8115   retype = getSpec (rtype);
8116
8117   aopOp (left, ic, FALSE);
8118
8119   /* if left is rematerialisable and
8120      result is not bitfield variable type and
8121      the left is pointer to data space i.e
8122      lower 128 bytes of space */
8123   if (AOP_TYPE (left) == AOP_IMMD &&
8124       !IS_BITFIELD (retype) &&
8125       DCL_TYPE (ltype) == POINTER)
8126     {
8127       genDataPointerGet (left, result, ic);
8128       return;
8129     }
8130
8131  /* if the value is already in a pointer register
8132      then don't need anything more */
8133   if (!AOP_INPREG (AOP (left)))
8134     {
8135       if (IS_AOP_PREG (left))
8136         {
8137           // Aha, it is a pointer, just in disguise.
8138           rname = aopGet (AOP (left), 0, FALSE, FALSE);
8139           if (*rname != '@')
8140             {
8141               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8142                       __FILE__, __LINE__);
8143             }
8144           else
8145             {
8146               // Expected case.
8147               emitcode ("mov", "a%s,%s", rname + 1, rname);
8148               rname++;  // skip the '@'.
8149             }
8150         }
8151       else
8152         {
8153           /* otherwise get a free pointer register */
8154           aop = newAsmop (0);
8155           preg = getFreePtr (ic, &aop, FALSE);
8156           emitcode ("mov", "%s,%s",
8157                     preg->name,
8158                     aopGet (AOP (left), 0, FALSE, TRUE));
8159           rname = preg->name;
8160         }
8161     }
8162   else
8163     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8164
8165   //aopOp (result, ic, FALSE);
8166   aopOp (result, ic, result?TRUE:FALSE);
8167
8168   /* if bitfield then unpack the bits */
8169   if (IS_BITFIELD (retype))
8170     genUnpackBits (result, rname, POINTER);
8171   else
8172     {
8173       /* we have can just get the values */
8174       int size = AOP_SIZE (result);
8175       int offset = 0;
8176
8177       while (size--)
8178         {
8179           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
8180             {
8181
8182               emitcode ("mov", "a,@%s", rname);
8183               aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8184             }
8185           else
8186             {
8187               sprintf (buffer, "@%s", rname);
8188               aopPut (AOP (result), buffer, offset, isOperandVolatile (result, FALSE));
8189             }
8190           offset++;
8191           if (size || pi)
8192             emitcode ("inc", "%s", rname);
8193         }
8194     }
8195
8196   /* now some housekeeping stuff */
8197   if (aop)       /* we had to allocate for this iCode */
8198     {
8199       if (pi) { /* post increment present */
8200         aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
8201       }
8202       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8203     }
8204   else
8205     {
8206       /* we did not allocate which means left
8207          already in a pointer register, then
8208          if size > 0 && this could be used again
8209          we have to point it back to where it
8210          belongs */
8211       if ((AOP_SIZE (result) > 1 &&
8212            !OP_SYMBOL (left)->remat &&
8213            (OP_SYMBOL (left)->liveTo > ic->seq ||
8214             ic->depth)) &&
8215           !pi)
8216         {
8217           int size = AOP_SIZE (result) - 1;
8218           while (size--)
8219             emitcode ("dec", "%s", rname);
8220         }
8221     }
8222
8223   /* done */
8224   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
8225   freeAsmop (left, NULL, ic, TRUE);
8226   if (pi) pi->generated = 1;
8227 }
8228
8229 /*-----------------------------------------------------------------*/
8230 /* genPagedPointerGet - emitcode for paged pointer fetch           */
8231 /*-----------------------------------------------------------------*/
8232 static void
8233 genPagedPointerGet (operand * left,
8234                     operand * result,
8235                     iCode * ic,
8236                     iCode *pi)
8237 {
8238   asmop *aop = NULL;
8239   regs *preg = NULL;
8240   char *rname;
8241   sym_link *rtype, *retype;
8242
8243   D(emitcode (";     genPagedPointerGet",""));
8244
8245   rtype = operandType (result);
8246   retype = getSpec (rtype);
8247
8248   aopOp (left, ic, FALSE);
8249
8250   /* if the value is already in a pointer register
8251      then don't need anything more */
8252   if (!AOP_INPREG (AOP (left)))
8253     {
8254       /* otherwise get a free pointer register */
8255       aop = newAsmop (0);
8256       preg = getFreePtr (ic, &aop, FALSE);
8257       emitcode ("mov", "%s,%s",
8258                 preg->name,
8259                 aopGet (AOP (left), 0, FALSE, TRUE));
8260       rname = preg->name;
8261     }
8262   else
8263     rname = aopGet (AOP (left), 0, FALSE, FALSE);
8264
8265   aopOp (result, ic, FALSE);
8266
8267   /* if bitfield then unpack the bits */
8268   if (IS_BITFIELD (retype))
8269     genUnpackBits (result, rname, PPOINTER);
8270   else
8271     {
8272       /* we have can just get the values */
8273       int size = AOP_SIZE (result);
8274       int offset = 0;
8275
8276       while (size--)
8277         {
8278
8279           emitcode ("movx", "a,@%s", rname);
8280           aopPut (AOP (result), "a", offset, isOperandVolatile (result, FALSE));
8281
8282           offset++;
8283
8284           if (size || pi)
8285             emitcode ("inc", "%s", rname);
8286         }
8287     }
8288
8289   /* now some housekeeping stuff */
8290   if (aop) /* we had to allocate for this iCode */
8291     {
8292       if (pi) aopPut ( AOP (left), rname, 0, isOperandVolatile (left, FALSE));
8293       freeAsmop (NULL, aop, ic, TRUE);
8294     }
8295   else
8296     {
8297       /* we did not allocate which means left
8298          already in a pointer register, then
8299          if size > 0 && this could be used again
8300          we have to point it back to where it
8301          belongs */
8302       if ((AOP_SIZE (result) > 1 &&
8303            !OP_SYMBOL (left)->remat &&
8304            (OP_SYMBOL (left)->liveTo > ic->seq ||
8305             ic->depth)) &&
8306           !pi)
8307         {
8308           int size = AOP_SIZE (result) - 1;
8309           while (size--)
8310             emitcode ("dec", "%s", rname);
8311         }
8312     }
8313
8314   /* done */
8315   freeAsmop (left, NULL, ic, TRUE);
8316   freeAsmop (result, NULL, ic, TRUE);
8317   if (pi) pi->generated = 1;
8318
8319 }
8320
8321 /*--------------------------------------------------------------------*/
8322 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
8323 /*--------------------------------------------------------------------*/
8324 static void
8325 loadDptrFromOperand (operand *op, bool loadBToo)
8326 {
8327   if (AOP_TYPE (op) != AOP_STR)
8328     {
8329       /* if this is remateriazable */
8330       if (AOP_TYPE (op) == AOP_IMMD)
8331         {
8332           emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
8333           if (loadBToo)
8334             {
8335               if (AOP(op)->aopu.aop_immd.from_cast_remat)
8336                 emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
8337               else
8338                 {
8339                   wassertl(FALSE, "need pointerCode");
8340                   emitcode ("", "; mov b,???");
8341                   /* genPointerGet and genPointerSet originally did different
8342                   ** things for this case. Both seem wrong.
8343                   ** from genPointerGet:
8344                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
8345                   ** from genPointerSet:
8346                   **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
8347                   */
8348                 }
8349             }
8350         }
8351       else if (AOP_TYPE (op) == AOP_DPTR)
8352         {
8353           if (loadBToo)
8354             {
8355               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8356               emitcode ("push", "acc");
8357               MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
8358               emitcode ("push", "acc");
8359               emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8360               emitcode ("pop", "dph");
8361               emitcode ("pop", "dpl");
8362             }
8363           else
8364             {
8365               MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
8366               emitcode ("push", "acc");
8367               emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8368               emitcode ("pop", "dpl");
8369             }
8370         }
8371       else
8372         {                       /* we need to get it byte by byte */
8373           emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
8374           emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
8375           if (loadBToo)
8376             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
8377         }
8378     }
8379 }
8380
8381 /*-----------------------------------------------------------------*/
8382 /* genFarPointerGet - gget value from far space                    */
8383 /*-----------------------------------------------------------------*/
8384 static void
8385 genFarPointerGet (operand * left,
8386                   operand * result, iCode * ic, iCode * pi)
8387 {
8388   int size, offset;
8389   sym_link *retype = getSpec (operandType (result));
8390
8391   D(emitcode (";     genFarPointerGet",""));
8392
8393   aopOp (left, ic, FALSE);
8394   loadDptrFromOperand (left, FALSE);
8395
8396   /* so dptr now contains the address */
8397   aopOp (result, ic, FALSE);
8398
8399   /* if bit then unpack */
8400   if (IS_BITFIELD (retype))
8401     genUnpackBits (result, "dptr", FPOINTER);
8402   else
8403     {
8404       size = AOP_SIZE (result);
8405       offset = 0;
8406
8407       while (size--)
8408         {
8409           emitcode ("movx", "a,@dptr");
8410           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8411           if (size || pi)
8412             emitcode ("inc", "dptr");
8413         }
8414     }
8415
8416   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8417     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8418     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8419     pi->generated = 1;
8420   }
8421   freeAsmop (left, NULL, ic, TRUE);
8422   freeAsmop (result, NULL, ic, TRUE);
8423 }
8424
8425 /*-----------------------------------------------------------------*/
8426 /* genCodePointerGet - gget value from code space                  */
8427 /*-----------------------------------------------------------------*/
8428 static void
8429 genCodePointerGet (operand * left,
8430                     operand * result, iCode * ic, iCode *pi)
8431 {
8432   int size, offset;
8433   sym_link *retype = getSpec (operandType (result));
8434
8435   D(emitcode (";     genCodePointerGet",""));
8436
8437   aopOp (left, ic, FALSE);
8438   loadDptrFromOperand (left, FALSE);
8439
8440   /* so dptr now contains the address */
8441   aopOp (result, ic, FALSE);
8442
8443   /* if bit then unpack */
8444   if (IS_BITFIELD (retype))
8445     genUnpackBits (result, "dptr", CPOINTER);
8446   else
8447     {
8448       size = AOP_SIZE (result);
8449       offset = 0;
8450
8451       while (size--)
8452         {
8453           if (pi)
8454             {
8455               emitcode ("clr", "a");
8456               emitcode ("movc", "a,@a+dptr");
8457               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8458               emitcode ("inc", "dptr");
8459             }
8460           else
8461             {
8462               emitcode ("mov", "a,#0x%02x", offset);
8463               emitcode ("movc", "a,@a+dptr");
8464               aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8465             }
8466         }
8467     }
8468
8469   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8470     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8471     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8472     pi->generated = 1;
8473   }
8474   freeAsmop (left, NULL, ic, TRUE);
8475   freeAsmop (result, NULL, ic, TRUE);
8476 }
8477
8478 /*-----------------------------------------------------------------*/
8479 /* genGenPointerGet - gget value from generic pointer space        */
8480 /*-----------------------------------------------------------------*/
8481 static void
8482 genGenPointerGet (operand * left,
8483                   operand * result, iCode * ic, iCode *pi)
8484 {
8485   int size, offset;
8486   sym_link *retype = getSpec (operandType (result));
8487
8488   D(emitcode (";     genGenPointerGet",""));
8489
8490   aopOp (left, ic, FALSE);
8491   loadDptrFromOperand (left, TRUE);
8492
8493   /* so dptr know contains the address */
8494   aopOp (result, ic, FALSE);
8495
8496   /* if bit then unpack */
8497   if (IS_BITFIELD (retype))
8498     genUnpackBits (result, "dptr", GPOINTER);
8499   else
8500     {
8501       size = AOP_SIZE (result);
8502       offset = 0;
8503
8504       while (size--)
8505         {
8506           emitcode ("lcall", "__gptrget");
8507           aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
8508           if (size || pi)
8509             emitcode ("inc", "dptr");
8510         }
8511     }
8512
8513   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR) {
8514     aopPut ( AOP (left), "dpl", 0, isOperandVolatile (left, FALSE));
8515     aopPut ( AOP (left), "dph", 1, isOperandVolatile (left, FALSE));
8516     pi->generated = 1;
8517   }
8518   freeAsmop (left, NULL, ic, TRUE);
8519   freeAsmop (result, NULL, ic, TRUE);
8520 }
8521
8522 /*-----------------------------------------------------------------*/
8523 /* genPointerGet - generate code for pointer get                   */
8524 /*-----------------------------------------------------------------*/
8525 static void
8526 genPointerGet (iCode * ic, iCode *pi)
8527 {
8528   operand *left, *result;
8529   sym_link *type, *etype;
8530   int p_type;
8531
8532   D(emitcode (";     genPointerGet",""));
8533
8534   left = IC_LEFT (ic);
8535   result = IC_RESULT (ic);
8536
8537   /* depending on the type of pointer we need to
8538      move it to the correct pointer register */
8539   type = operandType (left);
8540   etype = getSpec (type);
8541   /* if left is of type of pointer then it is simple */
8542   if (IS_PTR (type) && !IS_FUNC (type->next))
8543     p_type = DCL_TYPE (type);
8544   else
8545     {
8546       /* we have to go by the storage class */
8547       p_type = PTR_TYPE (SPEC_OCLS (etype));
8548     }
8549
8550   /* special case when cast remat */
8551   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
8552       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
8553           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
8554           type = operandType (left);
8555           p_type = DCL_TYPE (type);
8556   }
8557   /* now that we have the pointer type we assign
8558      the pointer values */
8559   switch (p_type)
8560     {
8561
8562     case POINTER:
8563     case IPOINTER:
8564       genNearPointerGet (left, result, ic, pi);
8565       break;
8566
8567     case PPOINTER:
8568       genPagedPointerGet (left, result, ic, pi);
8569       break;
8570
8571     case FPOINTER:
8572       genFarPointerGet (left, result, ic, pi);
8573       break;
8574
8575     case CPOINTER:
8576       genCodePointerGet (left, result, ic, pi);
8577       break;
8578
8579     case GPOINTER:
8580       genGenPointerGet (left, result, ic, pi);
8581       break;
8582     }
8583
8584 }
8585
8586
8587
8588 /*-----------------------------------------------------------------*/
8589 /* genPackBits - generates code for packed bit storage             */
8590 /*-----------------------------------------------------------------*/
8591 static void
8592 genPackBits (sym_link * etype,
8593              operand * right,
8594              char *rname, int p_type)
8595 {
8596   int offset = 0;       /* source byte offset */
8597   int rlen = 0;         /* remaining bitfield length */
8598   int blen;             /* bitfield length */
8599   int bstr;             /* bitfield starting bit within byte */
8600   int litval;           /* source literal value (if AOP_LIT) */
8601   unsigned char mask;   /* bitmask within current byte */
8602
8603   D(emitcode (";     genPackBits",""));
8604
8605   blen = SPEC_BLEN (etype);
8606   bstr = SPEC_BSTR (etype);
8607
8608   /* If the bitfield length is less than a byte */
8609   if (blen < 8)
8610     {
8611       mask = ((unsigned char) (0xFF << (blen + bstr)) |
8612               (unsigned char) (0xFF >> (8 - bstr)));
8613
8614       if (AOP_TYPE (right) == AOP_LIT)
8615         {
8616           /* Case with a bitfield length <8 and literal source
8617           */
8618           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8619           litval <<= bstr;
8620           litval &= (~mask) & 0xff;
8621           emitPtrByteGet (rname, p_type, FALSE);
8622           if ((mask|litval)!=0xff)
8623             emitcode ("anl","a,#0x%02x", mask);
8624           if (litval)
8625             emitcode ("orl","a,#0x%02x", litval);
8626         }
8627       else
8628         {
8629           if ((blen==1) && (p_type!=GPOINTER))
8630             {
8631               /* Case with a bitfield length == 1 and no generic pointer
8632               */
8633               if (AOP_TYPE (right) == AOP_CRY)
8634                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
8635               else
8636                 {
8637                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8638                   emitcode ("rrc","a");
8639                 }
8640               emitPtrByteGet (rname, p_type, FALSE);
8641               emitcode ("mov","acc.%d,c",bstr);
8642             }
8643           else
8644             {
8645               /* Case with a bitfield length < 8 and arbitrary source
8646               */
8647               MOVA (aopGet (AOP (right), 0, FALSE, FALSE));
8648               /* shift and mask source value */
8649               AccLsh (bstr);
8650               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8651
8652               /* transfer A to B and get next byte */
8653               emitPtrByteGet (rname, p_type, TRUE);
8654
8655               emitcode ("anl", "a,#0x%02x", mask);
8656               emitcode ("orl", "a,b");
8657               if (p_type == GPOINTER)
8658                 emitcode ("pop", "b");
8659            }
8660         }
8661
8662       emitPtrByteSet (rname, p_type, "a");
8663       return;
8664     }
8665
8666   /* Bit length is greater than 7 bits. In this case, copy  */
8667   /* all except the partial byte at the end                 */
8668   for (rlen=blen;rlen>=8;rlen-=8)
8669     {
8670       emitPtrByteSet (rname, p_type,
8671                       aopGet (AOP (right), offset++, FALSE, TRUE) );
8672       if (rlen>8)
8673         emitcode ("inc", "%s", rname);
8674     }
8675
8676   /* If there was a partial byte at the end */
8677   if (rlen)
8678     {
8679       mask = (((unsigned char) -1 << rlen) & 0xff);
8680
8681       if (AOP_TYPE (right) == AOP_LIT)
8682         {
8683           /* Case with partial byte and literal source
8684           */
8685           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8686           litval >>= (blen-rlen);
8687           litval &= (~mask) & 0xff;
8688           emitPtrByteGet (rname, p_type, FALSE);
8689           if ((mask|litval)!=0xff)
8690             emitcode ("anl","a,#0x%02x", mask);
8691           if (litval)
8692             emitcode ("orl","a,#0x%02x", litval);
8693         }
8694       else
8695         {
8696           /* Case with partial byte and arbitrary source
8697           */
8698           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
8699           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
8700
8701           /* transfer A to B and get next byte */
8702           emitPtrByteGet (rname, p_type, TRUE);
8703
8704           emitcode ("anl", "a,#0x%02x", mask);
8705           emitcode ("orl", "a,b");
8706           if (p_type == GPOINTER)
8707             emitcode ("pop", "b");
8708         }
8709       emitPtrByteSet (rname, p_type, "a");
8710     }
8711
8712 }
8713
8714
8715 /*-----------------------------------------------------------------*/
8716 /* genDataPointerSet - remat pointer to data space                 */
8717 /*-----------------------------------------------------------------*/
8718 static void
8719 genDataPointerSet (operand * right,
8720                    operand * result,
8721                    iCode * ic)
8722 {
8723   int size, offset = 0;
8724   char *l, buffer[256];
8725
8726   D(emitcode (";     genDataPointerSet",""));
8727
8728   aopOp (right, ic, FALSE);
8729
8730   l = aopGet (AOP (result), 0, FALSE, TRUE);
8731   size = AOP_SIZE (right);
8732   while (size--)
8733     {
8734       if (offset)
8735         sprintf (buffer, "(%s + %d)", l + 1, offset);
8736       else
8737         sprintf (buffer, "%s", l + 1);
8738       emitcode ("mov", "%s,%s", buffer,
8739                 aopGet (AOP (right), offset++, FALSE, FALSE));
8740     }
8741
8742   freeAsmop (right, NULL, ic, TRUE);
8743   freeAsmop (result, NULL, ic, TRUE);
8744 }
8745
8746 /*-----------------------------------------------------------------*/
8747 /* genNearPointerSet - emitcode for near pointer put                */
8748 /*-----------------------------------------------------------------*/
8749 static void
8750 genNearPointerSet (operand * right,
8751                    operand * result,
8752                    iCode * ic,
8753                    iCode * pi)
8754 {
8755   asmop *aop = NULL;
8756   regs *preg = NULL;
8757   char *rname, *l;
8758   sym_link *retype, *letype;
8759   sym_link *ptype = operandType (result);
8760
8761   D(emitcode (";     genNearPointerSet",""));
8762
8763   retype = getSpec (operandType (right));
8764   letype = getSpec (ptype);
8765   aopOp (result, ic, FALSE);
8766
8767   /* if the result is rematerializable &
8768      in data space & not a bit variable */
8769   if (AOP_TYPE (result) == AOP_IMMD &&
8770       DCL_TYPE (ptype) == POINTER &&
8771       !IS_BITVAR (retype) &&
8772       !IS_BITVAR (letype))
8773     {
8774       genDataPointerSet (right, result, ic);
8775       return;
8776     }
8777
8778   /* if the value is already in a pointer register
8779      then don't need anything more */
8780   if (!AOP_INPREG (AOP (result)))
8781     {
8782         if (
8783             //AOP_TYPE (result) == AOP_STK
8784             IS_AOP_PREG(result)
8785             )
8786         {
8787             // Aha, it is a pointer, just in disguise.
8788             rname = aopGet (AOP (result), 0, FALSE, FALSE);
8789             if (*rname != '@')
8790             {
8791                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
8792                         __FILE__, __LINE__);
8793             }
8794             else
8795             {
8796                 // Expected case.
8797                 emitcode ("mov", "a%s,%s", rname + 1, rname);
8798                 rname++;  // skip the '@'.
8799             }
8800         }
8801         else
8802         {
8803             /* otherwise get a free pointer register */
8804             aop = newAsmop (0);
8805             preg = getFreePtr (ic, &aop, FALSE);
8806             emitcode ("mov", "%s,%s",
8807                       preg->name,
8808                       aopGet (AOP (result), 0, FALSE, TRUE));
8809             rname = preg->name;
8810         }
8811     }
8812     else
8813     {
8814         rname = aopGet (AOP (result), 0, FALSE, FALSE);
8815     }
8816
8817   aopOp (right, ic, FALSE);
8818
8819   /* if bitfield then unpack the bits */
8820   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8821     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
8822   else
8823     {
8824       /* we have can just get the values */
8825       int size = AOP_SIZE (right);
8826       int offset = 0;
8827
8828       while (size--)
8829         {
8830           l = aopGet (AOP (right), offset, FALSE, TRUE);
8831           if (*l == '@')
8832             {
8833               MOVA (l);
8834               emitcode ("mov", "@%s,a", rname);
8835             }
8836           else
8837             emitcode ("mov", "@%s,%s", rname, l);
8838           if (size || pi)
8839             emitcode ("inc", "%s", rname);
8840           offset++;
8841         }
8842     }
8843
8844   /* now some housekeeping stuff */
8845   if (aop) /* we had to allocate for this iCode */
8846     {
8847       if (pi)
8848         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8849       freeAsmop (NULL, aop, ic, TRUE);
8850     }
8851   else
8852     {
8853       /* we did not allocate which means left
8854          already in a pointer register, then
8855          if size > 0 && this could be used again
8856          we have to point it back to where it
8857          belongs */
8858       if ((AOP_SIZE (right) > 1 &&
8859            !OP_SYMBOL (result)->remat &&
8860            (OP_SYMBOL (result)->liveTo > ic->seq ||
8861             ic->depth)) &&
8862           !pi)
8863         {
8864           int size = AOP_SIZE (right) - 1;
8865           while (size--)
8866             emitcode ("dec", "%s", rname);
8867         }
8868     }
8869
8870   /* done */
8871   if (pi) pi->generated = 1;
8872   freeAsmop (result, NULL, ic, TRUE);
8873   freeAsmop (right, NULL, ic, TRUE);
8874 }
8875
8876 /*-----------------------------------------------------------------*/
8877 /* genPagedPointerSet - emitcode for Paged pointer put             */
8878 /*-----------------------------------------------------------------*/
8879 static void
8880 genPagedPointerSet (operand * right,
8881                     operand * result,
8882                     iCode * ic,
8883                     iCode * pi)
8884 {
8885   asmop *aop = NULL;
8886   regs *preg = NULL;
8887   char *rname, *l;
8888   sym_link *retype, *letype;
8889
8890   D(emitcode (";     genPagedPointerSet",""));
8891
8892   retype = getSpec (operandType (right));
8893   letype = getSpec (operandType (result));
8894
8895   aopOp (result, ic, FALSE);
8896
8897   /* if the value is already in a pointer register
8898      then don't need anything more */
8899   if (!AOP_INPREG (AOP (result)))
8900     {
8901       /* otherwise get a free pointer register */
8902       aop = newAsmop (0);
8903       preg = getFreePtr (ic, &aop, FALSE);
8904       emitcode ("mov", "%s,%s",
8905                 preg->name,
8906                 aopGet (AOP (result), 0, FALSE, TRUE));
8907       rname = preg->name;
8908     }
8909   else
8910     rname = aopGet (AOP (result), 0, FALSE, FALSE);
8911
8912   aopOp (right, ic, FALSE);
8913
8914   /* if bitfield then unpack the bits */
8915   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8916     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
8917   else
8918     {
8919       /* we have can just get the values */
8920       int size = AOP_SIZE (right);
8921       int offset = 0;
8922
8923       while (size--)
8924         {
8925           l = aopGet (AOP (right), offset, FALSE, TRUE);
8926
8927           MOVA (l);
8928           emitcode ("movx", "@%s,a", rname);
8929
8930           if (size || pi)
8931             emitcode ("inc", "%s", rname);
8932
8933           offset++;
8934         }
8935     }
8936
8937   /* now some housekeeping stuff */
8938   if (aop) /* we had to allocate for this iCode */
8939     {
8940       if (pi)
8941         aopPut (AOP (result), rname, 0, isOperandVolatile (result, FALSE));
8942       freeAsmop (NULL, aop, ic, TRUE);
8943     }
8944   else
8945     {
8946       /* we did not allocate which means left
8947          already in a pointer register, then
8948          if size > 0 && this could be used again
8949          we have to point it back to where it
8950          belongs */
8951       if (AOP_SIZE (right) > 1 &&
8952           !OP_SYMBOL (result)->remat &&
8953           (OP_SYMBOL (result)->liveTo > ic->seq ||
8954            ic->depth))
8955         {
8956           int size = AOP_SIZE (right) - 1;
8957           while (size--)
8958             emitcode ("dec", "%s", rname);
8959         }
8960     }
8961
8962   /* done */
8963   if (pi) pi->generated = 1;
8964   freeAsmop (result, NULL, ic, TRUE);
8965   freeAsmop (right, NULL, ic, TRUE);
8966
8967
8968 }
8969
8970 /*-----------------------------------------------------------------*/
8971 /* genFarPointerSet - set value from far space                     */
8972 /*-----------------------------------------------------------------*/
8973 static void
8974 genFarPointerSet (operand * right,
8975                   operand * result, iCode * ic, iCode * pi)
8976 {
8977   int size, offset;
8978   sym_link *retype = getSpec (operandType (right));
8979   sym_link *letype = getSpec (operandType (result));
8980
8981   D(emitcode (";     genFarPointerSet",""));
8982
8983   aopOp (result, ic, FALSE);
8984   loadDptrFromOperand (result, FALSE);
8985
8986   /* so dptr know contains the address */
8987   aopOp (right, ic, FALSE);
8988
8989   /* if bit then unpack */
8990   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
8991     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
8992   else
8993     {
8994       size = AOP_SIZE (right);
8995       offset = 0;
8996
8997       while (size--)
8998         {
8999           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9000           MOVA (l);
9001           emitcode ("movx", "@dptr,a");
9002           if (size || pi)
9003             emitcode ("inc", "dptr");
9004         }
9005     }
9006   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9007     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9008     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9009     pi->generated=1;
9010   }
9011   freeAsmop (result, NULL, ic, TRUE);
9012   freeAsmop (right, NULL, ic, TRUE);
9013 }
9014
9015 /*-----------------------------------------------------------------*/
9016 /* genGenPointerSet - set value from generic pointer space         */
9017 /*-----------------------------------------------------------------*/
9018 static void
9019 genGenPointerSet (operand * right,
9020                   operand * result, iCode * ic, iCode * pi)
9021 {
9022   int size, offset;
9023   sym_link *retype = getSpec (operandType (right));
9024   sym_link *letype = getSpec (operandType (result));
9025
9026   D(emitcode (";     genGenPointerSet",""));
9027
9028   aopOp (result, ic, FALSE);
9029   loadDptrFromOperand (result, TRUE);
9030
9031   /* so dptr know contains the address */
9032   aopOp (right, ic, FALSE);
9033
9034   /* if bit then unpack */
9035   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9036     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
9037   else
9038     {
9039       size = AOP_SIZE (right);
9040       offset = 0;
9041
9042       while (size--)
9043         {
9044           char *l = aopGet (AOP (right), offset++, FALSE, FALSE);
9045           MOVA (l);
9046           emitcode ("lcall", "__gptrput");
9047           if (size || pi)
9048             emitcode ("inc", "dptr");
9049         }
9050     }
9051
9052   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
9053     aopPut (AOP(result), "dpl", 0, isOperandVolatile (result, FALSE));
9054     aopPut (AOP(result), "dph", 1, isOperandVolatile (result, FALSE));
9055     pi->generated=1;
9056   }
9057   freeAsmop (result, NULL, ic, TRUE);
9058   freeAsmop (right, NULL, ic, TRUE);
9059 }
9060
9061 /*-----------------------------------------------------------------*/
9062 /* genPointerSet - stores the value into a pointer location        */
9063 /*-----------------------------------------------------------------*/
9064 static void
9065 genPointerSet (iCode * ic, iCode *pi)
9066 {
9067   operand *right, *result;
9068   sym_link *type, *etype;
9069   int p_type;
9070
9071   D(emitcode (";     genPointerSet",""));
9072
9073   right = IC_RIGHT (ic);
9074   result = IC_RESULT (ic);
9075
9076   /* depending on the type of pointer we need to
9077      move it to the correct pointer register */
9078   type = operandType (result);
9079   etype = getSpec (type);
9080   /* if left is of type of pointer then it is simple */
9081   if (IS_PTR (type) && !IS_FUNC (type->next))
9082     {
9083       p_type = DCL_TYPE (type);
9084     }
9085   else
9086     {
9087       /* we have to go by the storage class */
9088       p_type = PTR_TYPE (SPEC_OCLS (etype));
9089     }
9090
9091   /* special case when cast remat */
9092   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
9093       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
9094           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
9095           type = operandType (result);
9096           p_type = DCL_TYPE (type);
9097   }
9098   /* now that we have the pointer type we assign
9099      the pointer values */
9100   switch (p_type)
9101     {
9102
9103     case POINTER:
9104     case IPOINTER:
9105       genNearPointerSet (right, result, ic, pi);
9106       break;
9107
9108     case PPOINTER:
9109       genPagedPointerSet (right, result, ic, pi);
9110       break;
9111
9112     case FPOINTER:
9113       genFarPointerSet (right, result, ic, pi);
9114       break;
9115
9116     case GPOINTER:
9117       genGenPointerSet (right, result, ic, pi);
9118       break;
9119
9120     default:
9121       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9122               "genPointerSet: illegal pointer type");
9123     }
9124
9125 }
9126
9127 /*-----------------------------------------------------------------*/
9128 /* genIfx - generate code for Ifx statement                        */
9129 /*-----------------------------------------------------------------*/
9130 static void
9131 genIfx (iCode * ic, iCode * popIc)
9132 {
9133   operand *cond = IC_COND (ic);
9134   int isbit = 0;
9135
9136   D(emitcode (";     genIfx",""));
9137
9138   aopOp (cond, ic, FALSE);
9139
9140   /* get the value into acc */
9141   if (AOP_TYPE (cond) != AOP_CRY)
9142     toBoolean (cond);
9143   else
9144     isbit = 1;
9145   /* the result is now in the accumulator */
9146   freeAsmop (cond, NULL, ic, TRUE);
9147
9148   /* if there was something to be popped then do it */
9149   if (popIc)
9150     genIpop (popIc);
9151
9152   /* if the condition is  a bit variable */
9153   if (isbit && IS_ITEMP (cond) &&
9154       SPIL_LOC (cond))
9155     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
9156   else if (isbit && !IS_ITEMP (cond))
9157     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
9158   else
9159     genIfxJump (ic, "a", NULL, NULL, NULL);
9160
9161   ic->generated = 1;
9162 }
9163
9164 /*-----------------------------------------------------------------*/
9165 /* genAddrOf - generates code for address of                       */
9166 /*-----------------------------------------------------------------*/
9167 static void
9168 genAddrOf (iCode * ic)
9169 {
9170   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
9171   int size, offset;
9172
9173   D(emitcode (";     genAddrOf",""));
9174
9175   aopOp (IC_RESULT (ic), ic, FALSE);
9176
9177   /* if the operand is on the stack then we
9178      need to get the stack offset of this
9179      variable */
9180   if (sym->onStack)
9181     {
9182       /* if it has an offset then we need to compute
9183          it */
9184       if (sym->stack)
9185         {
9186           emitcode ("mov", "a,_bp");
9187           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
9188                                          ((char) (sym->stack - _G.nRegsSaved)) :
9189                                          ((char) sym->stack)) & 0xff);
9190           aopPut (AOP (IC_RESULT (ic)), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9191         }
9192       else
9193         {
9194           /* we can just move _bp */
9195           aopPut (AOP (IC_RESULT (ic)), "_bp", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9196         }
9197       /* fill the result with zero */
9198       size = AOP_SIZE (IC_RESULT (ic)) - 1;
9199
9200       offset = 1;
9201       while (size--)
9202         {
9203           aopPut (AOP (IC_RESULT (ic)), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9204         }
9205
9206       goto release;
9207     }
9208
9209   /* object not on stack then we need the name */
9210   size = AOP_SIZE (IC_RESULT (ic));
9211   offset = 0;
9212
9213   while (size--)
9214     {
9215       char s[SDCC_NAME_MAX];
9216       if (offset)
9217         sprintf (s, "#(%s >> %d)",
9218                  sym->rname,
9219                  offset * 8);
9220       else
9221         sprintf (s, "#%s", sym->rname);
9222       aopPut (AOP (IC_RESULT (ic)), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9223     }
9224
9225 release:
9226   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9227
9228 }
9229
9230 /*-----------------------------------------------------------------*/
9231 /* genFarFarAssign - assignment when both are in far space         */
9232 /*-----------------------------------------------------------------*/
9233 static void
9234 genFarFarAssign (operand * result, operand * right, iCode * ic)
9235 {
9236   int size = AOP_SIZE (right);
9237   int offset = 0;
9238   char *l;
9239
9240   D(emitcode (";     genFarFarAssign",""));
9241
9242   /* first push the right side on to the stack */
9243   while (size--)
9244     {
9245       l = aopGet (AOP (right), offset++, FALSE, FALSE);
9246       MOVA (l);
9247       emitcode ("push", "acc");
9248     }
9249
9250   freeAsmop (right, NULL, ic, FALSE);
9251   /* now assign DPTR to result */
9252   aopOp (result, ic, FALSE);
9253   size = AOP_SIZE (result);
9254   while (size--)
9255     {
9256       emitcode ("pop", "acc");
9257       aopPut (AOP (result), "a", --offset, isOperandVolatile (result, FALSE));
9258     }
9259   freeAsmop (result, NULL, ic, FALSE);
9260
9261 }
9262
9263 /*-----------------------------------------------------------------*/
9264 /* genAssign - generate code for assignment                        */
9265 /*-----------------------------------------------------------------*/
9266 static void
9267 genAssign (iCode * ic)
9268 {
9269   operand *result, *right;
9270   int size, offset;
9271   unsigned long lit = 0L;
9272
9273   D(emitcode(";     genAssign",""));
9274
9275   result = IC_RESULT (ic);
9276   right = IC_RIGHT (ic);
9277
9278   /* if they are the same */
9279   if (operandsEqu (result, right) &&
9280       !isOperandVolatile (result, FALSE) &&
9281       !isOperandVolatile (right, FALSE))
9282     return;
9283
9284   aopOp (right, ic, FALSE);
9285
9286   /* special case both in far space */
9287   if (AOP_TYPE (right) == AOP_DPTR &&
9288       IS_TRUE_SYMOP (result) &&
9289       isOperandInFarSpace (result))
9290     {
9291
9292       genFarFarAssign (result, right, ic);
9293       return;
9294     }
9295
9296   aopOp (result, ic, TRUE);
9297
9298   /* if they are the same registers */
9299   if (sameRegs (AOP (right), AOP (result)) &&
9300       !isOperandVolatile (result, FALSE) &&
9301       !isOperandVolatile (right, FALSE))
9302     goto release;
9303
9304   /* if the result is a bit */
9305   if (AOP_TYPE (result) == AOP_CRY)
9306     {
9307
9308       /* if the right size is a literal then
9309          we know what the value is */
9310       if (AOP_TYPE (right) == AOP_LIT)
9311         {
9312           if (((int) operandLitValue (right)))
9313             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9314           else
9315             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9316           goto release;
9317         }
9318
9319       /* the right is also a bit variable */
9320       if (AOP_TYPE (right) == AOP_CRY)
9321         {
9322           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9323           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9324           goto release;
9325         }
9326
9327       /* we need to or */
9328       toBoolean (right);
9329       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9330       goto release;
9331     }
9332
9333   /* bit variables done */
9334   /* general case */
9335   size = AOP_SIZE (result);
9336   offset = 0;
9337   if (AOP_TYPE (right) == AOP_LIT)
9338     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
9339   if ((size > 1) &&
9340       (AOP_TYPE (result) != AOP_REG) &&
9341       (AOP_TYPE (right) == AOP_LIT) &&
9342       !IS_FLOAT (operandType (right)) &&
9343       (lit < 256L))
9344     {
9345       emitcode ("clr", "a");
9346       while (size--)
9347         {
9348           if ((unsigned int) ((lit >> (size * 8)) & 0x0FFL) == 0)
9349             aopPut (AOP (result), "a", size, isOperandVolatile (result, FALSE));
9350           else
9351             aopPut (AOP (result),
9352                     aopGet (AOP (right), size, FALSE, FALSE),
9353                     size,
9354                     isOperandVolatile (result, FALSE));
9355         }
9356     }
9357   else
9358     {
9359       while (size--)
9360         {
9361           aopPut (AOP (result),
9362                   aopGet (AOP (right), offset, FALSE, FALSE),
9363                   offset,
9364                   isOperandVolatile (result, FALSE));
9365           offset++;
9366         }
9367     }
9368
9369 release:
9370   freeAsmop (right, NULL, ic, TRUE);
9371   freeAsmop (result, NULL, ic, TRUE);
9372 }
9373
9374 /*-----------------------------------------------------------------*/
9375 /* genJumpTab - genrates code for jump table                       */
9376 /*-----------------------------------------------------------------*/
9377 static void
9378 genJumpTab (iCode * ic)
9379 {
9380   symbol *jtab;
9381   char *l;
9382
9383   D(emitcode (";     genJumpTab",""));
9384
9385   aopOp (IC_JTCOND (ic), ic, FALSE);
9386   /* get the condition into accumulator */
9387   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE);
9388   MOVA (l);
9389   /* multiply by three */
9390   emitcode ("add", "a,acc");
9391   emitcode ("add", "a,%s", aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE));
9392   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
9393
9394   jtab = newiTempLabel (NULL);
9395   emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
9396   emitcode ("jmp", "@a+dptr");
9397   emitcode ("", "%05d$:", jtab->key + 100);
9398   /* now generate the jump labels */
9399   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
9400        jtab = setNextItem (IC_JTLABELS (ic)))
9401     emitcode ("ljmp", "%05d$", jtab->key + 100);
9402
9403 }
9404
9405 /*-----------------------------------------------------------------*/
9406 /* genCast - gen code for casting                                  */
9407 /*-----------------------------------------------------------------*/
9408 static void
9409 genCast (iCode * ic)
9410 {
9411   operand *result = IC_RESULT (ic);
9412   sym_link *ctype = operandType (IC_LEFT (ic));
9413   sym_link *rtype = operandType (IC_RIGHT (ic));
9414   operand *right = IC_RIGHT (ic);
9415   int size, offset;
9416
9417   D(emitcode(";     genCast",""));
9418
9419   /* if they are equivalent then do nothing */
9420   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
9421     return;
9422
9423   aopOp (right, ic, FALSE);
9424   aopOp (result, ic, FALSE);
9425
9426   /* if the result is a bit (and not a bitfield) */
9427   // if (AOP_TYPE (result) == AOP_CRY)
9428   if (IS_BITVAR (OP_SYMBOL (result)->type)
9429       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
9430     {
9431       /* if the right size is a literal then
9432          we know what the value is */
9433       if (AOP_TYPE (right) == AOP_LIT)
9434         {
9435           if (((int) operandLitValue (right)))
9436             aopPut (AOP (result), one, 0, isOperandVolatile (result, FALSE));
9437           else
9438             aopPut (AOP (result), zero, 0, isOperandVolatile (result, FALSE));
9439
9440           goto release;
9441         }
9442
9443       /* the right is also a bit variable */
9444       if (AOP_TYPE (right) == AOP_CRY)
9445         {
9446           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
9447           aopPut (AOP (result), "c", 0, isOperandVolatile (result, FALSE));
9448           goto release;
9449         }
9450
9451       /* we need to or */
9452       toBoolean (right);
9453       aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
9454       goto release;
9455     }
9456
9457
9458   /* if they are the same size : or less */
9459   if (AOP_SIZE (result) <= AOP_SIZE (right))
9460     {
9461
9462       /* if they are in the same place */
9463       if (sameRegs (AOP (right), AOP (result)))
9464         goto release;
9465
9466       /* if they in different places then copy */
9467       size = AOP_SIZE (result);
9468       offset = 0;
9469       while (size--)
9470         {
9471           aopPut (AOP (result),
9472                   aopGet (AOP (right), offset, FALSE, FALSE),
9473                   offset,
9474                   isOperandVolatile (result, FALSE));
9475           offset++;
9476         }
9477       goto release;
9478     }
9479
9480
9481   /* if the result is of type pointer */
9482   if (IS_PTR (ctype))
9483     {
9484
9485       int p_type;
9486       sym_link *type = operandType (right);
9487       sym_link *etype = getSpec (type);
9488
9489       /* pointer to generic pointer */
9490       if (IS_GENPTR (ctype))
9491         {
9492           if (IS_PTR (type))
9493             p_type = DCL_TYPE (type);
9494           else
9495             {
9496               if (SPEC_SCLS(etype)==S_REGISTER) {
9497                 // let's assume it is a generic pointer
9498                 p_type=GPOINTER;
9499               } else {
9500                 /* we have to go by the storage class */
9501                 p_type = PTR_TYPE (SPEC_OCLS (etype));
9502               }
9503             }
9504
9505           /* the first two bytes are known */
9506           size = GPTRSIZE - 1;
9507           offset = 0;
9508           while (size--)
9509             {
9510               aopPut (AOP (result),
9511                       aopGet (AOP (right), offset, FALSE, FALSE),
9512                       offset,
9513                       isOperandVolatile (result, FALSE));
9514               offset++;
9515             }
9516           /* the last byte depending on type */
9517             {
9518                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
9519                 char gpValStr[10];
9520
9521                 if (gpVal == -1)
9522                 {
9523                     // pointerTypeToGPByte will have bitched.
9524                     exit(1);
9525                 }
9526
9527                 sprintf(gpValStr, "#0x%d", gpVal);
9528                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
9529             }
9530           goto release;
9531         }
9532
9533       /* just copy the pointers */
9534       size = AOP_SIZE (result);
9535       offset = 0;
9536       while (size--)
9537         {
9538           aopPut (AOP (result),
9539                   aopGet (AOP (right), offset, FALSE, FALSE),
9540                   offset,
9541                   isOperandVolatile (result, FALSE));
9542           offset++;
9543         }
9544       goto release;
9545     }
9546
9547   /* so we now know that the size of destination is greater
9548      than the size of the source */
9549   /* we move to result for the size of source */
9550   size = AOP_SIZE (right);
9551   offset = 0;
9552   while (size--)
9553     {
9554       aopPut (AOP (result),
9555               aopGet (AOP (right), offset, FALSE, FALSE),
9556               offset,
9557               isOperandVolatile (result, FALSE));
9558       offset++;
9559     }
9560
9561   /* now depending on the sign of the source && destination */
9562   size = AOP_SIZE (result) - AOP_SIZE (right);
9563   /* if unsigned or not an integral type */
9564   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
9565     {
9566       while (size--)
9567         aopPut (AOP (result), zero, offset++, isOperandVolatile (result, FALSE));
9568     }
9569   else
9570     {
9571       /* we need to extend the sign :{ */
9572       char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
9573                         FALSE, FALSE);
9574       MOVA (l);
9575       emitcode ("rlc", "a");
9576       emitcode ("subb", "a,acc");
9577       while (size--)
9578         aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
9579     }
9580
9581   /* we are done hurray !!!! */
9582
9583 release:
9584   freeAsmop (right, NULL, ic, TRUE);
9585   freeAsmop (result, NULL, ic, TRUE);
9586
9587 }
9588
9589 /*-----------------------------------------------------------------*/
9590 /* genDjnz - generate decrement & jump if not zero instrucion      */
9591 /*-----------------------------------------------------------------*/
9592 static int
9593 genDjnz (iCode * ic, iCode * ifx)
9594 {
9595   symbol *lbl, *lbl1;
9596   if (!ifx)
9597     return 0;
9598
9599   D(emitcode (";     genDjnz",""));
9600
9601   /* if the if condition has a false label
9602      then we cannot save */
9603   if (IC_FALSE (ifx))
9604     return 0;
9605
9606   /* if the minus is not of the form
9607      a = a - 1 */
9608   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
9609       !IS_OP_LITERAL (IC_RIGHT (ic)))
9610     return 0;
9611
9612   if (operandLitValue (IC_RIGHT (ic)) != 1)
9613     return 0;
9614
9615   /* if the size of this greater than one then no
9616      saving */
9617   if (getSize (operandType (IC_RESULT (ic))) > 1)
9618     return 0;
9619
9620   /* otherwise we can save BIG */
9621   lbl = newiTempLabel (NULL);
9622   lbl1 = newiTempLabel (NULL);
9623
9624   aopOp (IC_RESULT (ic), ic, FALSE);
9625
9626   if (AOP_NEEDSACC(IC_RESULT(ic)))
9627   {
9628       /* If the result is accessed indirectly via
9629        * the accumulator, we must explicitly write
9630        * it back after the decrement.
9631        */
9632       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE);
9633
9634       if (strcmp(rByte, "a"))
9635       {
9636            /* Something is hopelessly wrong */
9637            fprintf(stderr, "*** warning: internal error at %s:%d\n",
9638                    __FILE__, __LINE__);
9639            /* We can just give up; the generated code will be inefficient,
9640             * but what the hey.
9641             */
9642            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9643            return 0;
9644       }
9645       emitcode ("dec", "%s", rByte);
9646       aopPut(AOP(IC_RESULT(ic)), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
9647       emitcode ("jnz", "%05d$", lbl->key + 100);
9648   }
9649   else if (IS_AOP_PREG (IC_RESULT (ic)))
9650     {
9651       emitcode ("dec", "%s",
9652                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9653       MOVA (aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE));
9654       emitcode ("jnz", "%05d$", lbl->key + 100);
9655     }
9656   else
9657     {
9658       emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE),
9659                 lbl->key + 100);
9660     }
9661   emitcode ("sjmp", "%05d$", lbl1->key + 100);
9662   emitcode ("", "%05d$:", lbl->key + 100);
9663   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
9664   emitcode ("", "%05d$:", lbl1->key + 100);
9665
9666   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9667   ifx->generated = 1;
9668   return 1;
9669 }
9670
9671 /*-----------------------------------------------------------------*/
9672 /* genReceive - generate code for a receive iCode                  */
9673 /*-----------------------------------------------------------------*/
9674 static void
9675 genReceive (iCode * ic)
9676 {
9677     int size = getSize (operandType (IC_RESULT (ic)));
9678     int offset = 0;
9679   D(emitcode (";     genReceive",""));
9680
9681   if (ic->argreg == 1) { /* first parameter */
9682       if (isOperandInFarSpace (IC_RESULT (ic)) &&
9683           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
9684            IS_TRUE_SYMOP (IC_RESULT (ic)))) {
9685
9686           regs *tempRegs[4];
9687           int receivingA = 0;
9688           int roffset = 0;
9689
9690           for (offset = 0; offset<size; offset++)
9691             if (!strcmp (fReturn[offset], "a"))
9692               receivingA = 1;
9693
9694           if (!receivingA)
9695             {
9696               if (size==1 || getTempRegs(tempRegs, size-1, ic))
9697                 {
9698                   for (offset = size-1; offset>0; offset--)
9699                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
9700                   emitcode("mov","a,%s", fReturn[0]);
9701                   _G.accInUse++;
9702                   aopOp (IC_RESULT (ic), ic, FALSE);
9703                   _G.accInUse--;
9704                   aopPut (AOP (IC_RESULT (ic)), "a", offset,
9705                           isOperandVolatile (IC_RESULT (ic), FALSE));
9706                   for (offset = 1; offset<size; offset++)
9707                     aopPut (AOP (IC_RESULT (ic)), tempRegs[--roffset]->name, offset,
9708                             isOperandVolatile (IC_RESULT (ic), FALSE));
9709                   goto release;
9710                 }
9711             }
9712           else
9713             {
9714               if (getTempRegs(tempRegs, size, ic))
9715                 {
9716                   for (offset = 0; offset<size; offset++)
9717                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
9718                   aopOp (IC_RESULT (ic), ic, FALSE);
9719                   for (offset = 0; offset<size; offset++)
9720                     aopPut (AOP (IC_RESULT (ic)), tempRegs[offset]->name, offset,
9721                             isOperandVolatile (IC_RESULT (ic), FALSE));
9722                   goto release;
9723                 }
9724             }
9725
9726           offset = fReturnSizeMCS51 - size;
9727           while (size--) {
9728               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
9729                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
9730               offset++;
9731           }
9732           aopOp (IC_RESULT (ic), ic, FALSE);
9733           size = AOP_SIZE (IC_RESULT (ic));
9734           offset = 0;
9735           while (size--) {
9736               emitcode ("pop", "acc");
9737               aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9738           }
9739
9740       } else {
9741           _G.accInUse++;
9742           aopOp (IC_RESULT (ic), ic, FALSE);
9743           _G.accInUse--;
9744           assignResultValue (IC_RESULT (ic));
9745       }
9746   } else { /* second receive onwards */
9747       int rb1off ;
9748       aopOp (IC_RESULT (ic), ic, FALSE);
9749       rb1off = ic->argreg;
9750       while (size--) {
9751           aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
9752       }
9753   }
9754
9755 release:
9756   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9757 }
9758
9759 /*-----------------------------------------------------------------*/
9760 /* genDummyRead - generate code for dummy read of volatiles        */
9761 /*-----------------------------------------------------------------*/
9762 static void
9763 genDummyRead (iCode * ic)
9764 {
9765   operand *op;
9766   int size, offset;
9767
9768   D(emitcode(";     genDummyRead",""));
9769
9770   op = IC_RIGHT (ic);
9771   if (op && IS_SYMOP (op))
9772     {
9773       aopOp (op, ic, FALSE);
9774
9775       /* if the result is a bit */
9776       if (AOP_TYPE (op) == AOP_CRY)
9777         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9778       else
9779         {
9780           /* bit variables done */
9781           /* general case */
9782           size = AOP_SIZE (op);
9783           offset = 0;
9784           while (size--)
9785           {
9786             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9787             offset++;
9788           }
9789         }
9790
9791       freeAsmop (op, NULL, ic, TRUE);
9792     }
9793
9794   op = IC_LEFT (ic);
9795   if (op && IS_SYMOP (op))
9796     {
9797       aopOp (op, ic, FALSE);
9798
9799       /* if the result is a bit */
9800       if (AOP_TYPE (op) == AOP_CRY)
9801         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
9802       else
9803         {
9804           /* bit variables done */
9805           /* general case */
9806           size = AOP_SIZE (op);
9807           offset = 0;
9808           while (size--)
9809           {
9810             MOVA (aopGet (AOP (op), offset, FALSE, FALSE));
9811             offset++;
9812           }
9813         }
9814
9815       freeAsmop (op, NULL, ic, TRUE);
9816     }
9817 }
9818
9819 /*-----------------------------------------------------------------*/
9820 /* genCritical - generate code for start of a critical sequence    */
9821 /*-----------------------------------------------------------------*/
9822 static void
9823 genCritical (iCode *ic)
9824 {
9825   symbol *tlbl = newiTempLabel (NULL);
9826
9827   D(emitcode(";     genCritical",""));
9828
9829   if (IC_RESULT (ic))
9830     aopOp (IC_RESULT (ic), ic, TRUE);
9831
9832   emitcode ("setb", "c");
9833   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
9834   emitcode ("clr", "c");
9835   emitcode ("", "%05d$:", (tlbl->key + 100));
9836
9837   if (IC_RESULT (ic))
9838     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
9839   else
9840     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
9841
9842   if (IC_RESULT (ic))
9843     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
9844 }
9845
9846 /*-----------------------------------------------------------------*/
9847 /* genEndCritical - generate code for end of a critical sequence   */
9848 /*-----------------------------------------------------------------*/
9849 static void
9850 genEndCritical (iCode *ic)
9851 {
9852   D(emitcode(";     genEndCritical",""));
9853
9854   if (IC_RIGHT (ic))
9855     {
9856       aopOp (IC_RIGHT (ic), ic, FALSE);
9857       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
9858         {
9859           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
9860           emitcode ("mov", "ea,c");
9861         }
9862       else
9863         {
9864           MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE));
9865           emitcode ("rrc", "a");
9866           emitcode ("mov", "ea,c");
9867         }
9868       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
9869     }
9870   else
9871     {
9872       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
9873       emitcode ("mov", "ea,c");
9874     }
9875 }
9876
9877 /*-----------------------------------------------------------------*/
9878 /* gen51Code - generate code for 8051 based controllers            */
9879 /*-----------------------------------------------------------------*/
9880 void
9881 gen51Code (iCode * lic)
9882 {
9883   iCode *ic;
9884   int cln = 0;
9885   /* int cseq = 0; */
9886
9887   _G.currentFunc = NULL;
9888   lineHead = lineCurr = NULL;
9889
9890   /* print the allocation information */
9891   if (allocInfo && currFunc)
9892     printAllocInfo (currFunc, codeOutFile);
9893   /* if debug information required */
9894   if (options.debug && currFunc)
9895     {
9896       debugFile->writeFunction (currFunc, lic);
9897     }
9898   /* stack pointer name */
9899   if (options.useXstack)
9900     spname = "_spx";
9901   else
9902     spname = "sp";
9903
9904
9905   for (ic = lic; ic; ic = ic->next)
9906     {
9907       _G.current_iCode = ic;
9908
9909       if (ic->lineno && cln != ic->lineno)
9910         {
9911           if (options.debug)
9912             {
9913               debugFile->writeCLine(ic);
9914             }
9915           if (!options.noCcodeInAsm) {
9916             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
9917                       printCLine(ic->filename, ic->lineno));
9918           }
9919           cln = ic->lineno;
9920         }
9921       #if 0
9922       if (ic->seqPoint && ic->seqPoint != cseq)
9923         {
9924           emitcode ("", "; sequence point %d", ic->seqPoint);
9925           cseq = ic->seqPoint;
9926         }
9927       #endif
9928       if (options.iCodeInAsm) {
9929         char regsInUse[80];
9930         int i;
9931
9932         for (i=0; i<8; i++) {
9933           sprintf (&regsInUse[i],
9934                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
9935         }
9936         regsInUse[i]=0;
9937         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
9938       }
9939       /* if the result is marked as
9940          spilt and rematerializable or code for
9941          this has already been generated then
9942          do nothing */
9943       if (resultRemat (ic) || ic->generated)
9944         continue;
9945
9946       /* depending on the operation */
9947       switch (ic->op)
9948         {
9949         case '!':
9950           genNot (ic);
9951           break;
9952
9953         case '~':
9954           genCpl (ic);
9955           break;
9956
9957         case UNARYMINUS:
9958           genUminus (ic);
9959           break;
9960
9961         case IPUSH:
9962           genIpush (ic);
9963           break;
9964
9965         case IPOP:
9966           /* IPOP happens only when trying to restore a
9967              spilt live range, if there is an ifx statement
9968              following this pop then the if statement might
9969              be using some of the registers being popped which
9970              would destory the contents of the register so
9971              we need to check for this condition and handle it */
9972           if (ic->next &&
9973               ic->next->op == IFX &&
9974               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
9975             genIfx (ic->next, ic);
9976           else
9977             genIpop (ic);
9978           break;
9979
9980         case CALL:
9981           genCall (ic);
9982           break;
9983
9984         case PCALL:
9985           genPcall (ic);
9986           break;
9987
9988         case FUNCTION:
9989           genFunction (ic);
9990           break;
9991
9992         case ENDFUNCTION:
9993           genEndFunction (ic);
9994           break;
9995
9996         case RETURN:
9997           genRet (ic);
9998           break;
9999
10000         case LABEL:
10001           genLabel (ic);
10002           break;
10003
10004         case GOTO:
10005           genGoto (ic);
10006           break;
10007
10008         case '+':
10009           genPlus (ic);
10010           break;
10011
10012         case '-':
10013           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
10014             genMinus (ic);
10015           break;
10016
10017         case '*':
10018           genMult (ic);
10019           break;
10020
10021         case '/':
10022           genDiv (ic);
10023           break;
10024
10025         case '%':
10026           genMod (ic);
10027           break;
10028
10029         case '>':
10030           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
10031           break;
10032
10033         case '<':
10034           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
10035           break;
10036
10037         case LE_OP:
10038         case GE_OP:
10039         case NE_OP:
10040
10041           /* note these two are xlated by algebraic equivalence
10042              during parsing SDCC.y */
10043           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10044                   "got '>=' or '<=' shouldn't have come here");
10045           break;
10046
10047         case EQ_OP:
10048           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
10049           break;
10050
10051         case AND_OP:
10052           genAndOp (ic);
10053           break;
10054
10055         case OR_OP:
10056           genOrOp (ic);
10057           break;
10058
10059         case '^':
10060           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
10061           break;
10062
10063         case '|':
10064           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
10065           break;
10066
10067         case BITWISEAND:
10068           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
10069           break;
10070
10071         case INLINEASM:
10072           genInline (ic);
10073           break;
10074
10075         case RRC:
10076           genRRC (ic);
10077           break;
10078
10079         case RLC:
10080           genRLC (ic);
10081           break;
10082
10083         case GETHBIT:
10084           genGetHbit (ic);
10085           break;
10086
10087         case LEFT_OP:
10088           genLeftShift (ic);
10089           break;
10090
10091         case RIGHT_OP:
10092           genRightShift (ic);
10093           break;
10094
10095         case GET_VALUE_AT_ADDRESS:
10096           genPointerGet (ic, hasInc(IC_LEFT(ic),ic,getSize(operandType(IC_RESULT(ic)))));
10097           break;
10098
10099         case '=':
10100           if (POINTER_SET (ic))
10101             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
10102           else
10103             genAssign (ic);
10104           break;
10105
10106         case IFX:
10107           genIfx (ic, NULL);
10108           break;
10109
10110         case ADDRESS_OF:
10111           genAddrOf (ic);
10112           break;
10113
10114         case JUMPTABLE:
10115           genJumpTab (ic);
10116           break;
10117
10118         case CAST:
10119           genCast (ic);
10120           break;
10121
10122         case RECEIVE:
10123           genReceive (ic);
10124           break;
10125
10126         case SEND:
10127           addSet (&_G.sendSet, ic);
10128           break;
10129
10130         case DUMMY_READ_VOLATILE:
10131           genDummyRead (ic);
10132           break;
10133
10134         case CRITICAL:
10135           genCritical (ic);
10136           break;
10137
10138         case ENDCRITICAL:
10139           genEndCritical (ic);
10140           break;
10141
10142         case SWAP:
10143           genSwap (ic);
10144           break;
10145
10146         default:
10147           ic = ic;
10148         }
10149     }
10150
10151   _G.current_iCode = NULL;
10152
10153   /* now we are ready to call the
10154      peep hole optimizer */
10155   if (!options.nopeep)
10156     peepHole (&lineHead);
10157
10158   /* now do the actual printing */
10159   printLine (lineHead, codeOutFile);
10160   return;
10161 }