* src/mcs51/gen.c (genCodePointerGet): inc dptr instead of loading acc
[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 char *aopLiteralLong (value * val, int offset, int size);
48 extern int allocInfo;
49
50 /* this is the down and dirty file with all kinds of
51    kludgy & hacky stuff. This is what it is all about
52    CODE GENERATION for a specific MCU . some of the
53    routines may be reusable, will have to see */
54
55 static char *zero = "#0x00";
56 static char *one = "#0x01";
57 static char *spname;
58
59 char *fReturn8051[] =
60 {"dpl", "dph", "b", "a"};
61 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
62 char **fReturn = fReturn8051;
63 static char *accUse[] =
64 {"a", "b"};
65
66 static unsigned short rbank = -1;
67
68 #define AOP(op) op->aop
69 #define AOP_TYPE(op) AOP(op)->type
70 #define AOP_SIZE(op) AOP(op)->size
71 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
72                        AOP_TYPE(x) == AOP_R0))
73
74 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
75                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
76
77 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
78                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
79                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
80
81
82 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
83
84 #define R0INB   _G.bu.bs.r0InB
85 #define R1INB   _G.bu.bs.r1InB
86 #define OPINB   _G.bu.bs.OpInB
87 #define BINUSE  _G.bu.BInUse
88
89 static struct
90   {
91     short r0Pushed;
92     short r1Pushed;
93     union
94       {
95         struct
96           {
97             short r0InB : 2;//2 so we can see it overflow
98             short r1InB : 2;//2 so we can see it overflow
99             short OpInB : 2;//2 so we can see it overflow
100           } bs;
101         short BInUse;
102       } bu;
103     short accInUse;
104     short inLine;
105     short debugLine;
106     short nRegsSaved;
107     set *sendSet;
108     iCode *current_iCode;
109     symbol *currentFunc;
110   }
111 _G;
112
113 static char *rb1regs[] = {
114     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
115     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
116 };
117
118 extern int mcs51_ptrRegReq;
119 extern int mcs51_nRegs;
120 extern FILE *codeOutFile;
121 static void saveRBank (int, iCode *, bool);
122
123 #define RESULTONSTACK(x) \
124                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
125                          IC_RESULT(x)->aop->type == AOP_STK )
126
127 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
128 #define CLRC     emitcode("clr","c")
129 #define SETC     emitcode("setb","c")
130
131 static lineNode *lineHead = NULL;
132 static lineNode *lineCurr = NULL;
133
134 static unsigned char SLMask[] =
135 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
136  0xE0, 0xC0, 0x80, 0x00};
137 static unsigned char SRMask[] =
138 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
139  0x07, 0x03, 0x01, 0x00};
140
141 #define LSB     0
142 #define MSB16   1
143 #define MSB24   2
144 #define MSB32   3
145
146 /*-----------------------------------------------------------------*/
147 /* emitcode - writes the code into a file : for now it is simple    */
148 /*-----------------------------------------------------------------*/
149 static void
150 emitcode (char *inst, const char *fmt,...)
151 {
152   va_list ap;
153   char lb[INITIAL_INLINEASM];
154   char *lbp = lb;
155
156   va_start (ap, fmt);
157
158   if (inst && *inst)
159     {
160       if (fmt && *fmt)
161           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
162       else
163           SNPRINTF (lb, sizeof(lb), "%s", inst);
164       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
165     }
166   else
167       tvsprintf (lb, sizeof(lb), fmt, ap);
168
169   while (isspace ((unsigned char)*lbp))
170       lbp++;
171
172   if (lbp && *lbp)
173       lineCurr = (lineCurr ?
174                   connectLine (lineCurr, newLineNode (lb)) :
175                   (lineHead = newLineNode (lb)));
176   lineCurr->isInline = _G.inLine;
177   lineCurr->isDebug = _G.debugLine;
178   lineCurr->ic = _G.current_iCode;
179   lineCurr->isComment = (*lbp==';');
180   va_end (ap);
181 }
182
183 /*-----------------------------------------------------------------*/
184 /* mcs51_emitDebuggerSymbol - associate the current code location  */
185 /*   with a debugger symbol                                        */
186 /*-----------------------------------------------------------------*/
187 void
188 mcs51_emitDebuggerSymbol (char * debugSym)
189 {
190   _G.debugLine = 1;
191   emitcode ("", "%s ==.", debugSym);
192   _G.debugLine = 0;
193 }
194
195 /*-----------------------------------------------------------------*/
196 /* mova - moves specified value into accumulator                   */
197 /*-----------------------------------------------------------------*/
198 static void
199 mova (const char *x)
200 {
201   /* do some early peephole optimization */
202   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
203     return;
204
205   emitcode("mov","a,%s", x);
206 }
207
208 /*-----------------------------------------------------------------*/
209 /* movc - moves specified value into the carry                     */
210 /*-----------------------------------------------------------------*/
211 static void
212 movc (const char *s)
213 {
214   if (s == zero)
215     CLRC;
216   else if (s == one)
217     SETC;
218   else if (strcmp (s, "c"))
219     {/* it's not in carry already */
220       MOVA (s);
221       /* set C, if a >= 1 */
222       emitcode ("add", "a,#0xff");
223     }
224 }
225
226 /*-----------------------------------------------------------------*/
227 /* pushB - saves register B if necessary                           */
228 /*-----------------------------------------------------------------*/
229 static bool
230 pushB (void)
231 {
232   bool pushedB = FALSE;
233
234   if (BINUSE)
235     {
236       emitcode ("push", "b");
237 //    printf("B was in use !\n");
238       pushedB = TRUE;
239     }
240   else
241     {
242       OPINB++;
243     }
244   return pushedB;
245 }
246
247 /*-----------------------------------------------------------------*/
248 /* popB - restores value of register B if necessary                */
249 /*-----------------------------------------------------------------*/
250 static void
251 popB (bool pushedB)
252 {
253   if (pushedB)
254     {
255       emitcode ("pop", "b");
256     }
257   else
258     {
259       OPINB--;
260     }
261 }
262
263 /*-----------------------------------------------------------------*/
264 /* pushReg - saves register                                        */
265 /*-----------------------------------------------------------------*/
266 static bool
267 pushReg (int index, bool bits_pushed)
268 {
269   regs * reg = mcs51_regWithIdx (index);
270   if (reg->type == REG_BIT)
271     {
272       if (!bits_pushed)
273         emitcode ("push", "%s", reg->base);
274       return TRUE;
275     }
276   else
277     emitcode ("push", "%s", reg->dname);
278   return bits_pushed;
279 }
280
281 /*-----------------------------------------------------------------*/
282 /* popReg - restores register                                      */
283 /*-----------------------------------------------------------------*/
284 static bool
285 popReg (int index, bool bits_popped)
286 {
287   regs * reg = mcs51_regWithIdx (index);
288   if (reg->type == REG_BIT)
289     {
290       if (!bits_popped)
291         emitcode ("pop", "%s", reg->base);
292       return TRUE;
293     }
294   else
295     emitcode ("pop", "%s", reg->dname);
296   return bits_popped;
297 }
298
299 /*-----------------------------------------------------------------*/
300 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
301 /*-----------------------------------------------------------------*/
302 static regs *
303 getFreePtr (iCode * ic, asmop ** aopp, bool result)
304 {
305   bool r0iu, r1iu;
306   bool r0ou, r1ou;
307
308   /* the logic: if r0 & r1 used in the instruction
309      then we are in trouble otherwise */
310
311   /* first check if r0 & r1 are used by this
312      instruction, in which case we are in trouble */
313   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
314   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
315   if (r0iu && r1iu) {
316       goto endOfWorld;
317     }
318
319   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
320   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
321
322   /* if no usage of r0 then return it */
323   if (!r0iu && !r0ou)
324     {
325       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
326       (*aopp)->type = AOP_R0;
327
328       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
329     }
330
331   /* if no usage of r1 then return it */
332   if (!r1iu && !r1ou)
333     {
334       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
335       (*aopp)->type = AOP_R1;
336
337       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
338     }
339
340   /* now we know they both have usage */
341   /* if r0 not used in this instruction */
342   if (!r0iu)
343     {
344       /* push it if not already pushed */
345       if (ic->op == IPUSH)
346         {
347           emitcode ("mov", "b,%s",
348                     mcs51_regWithIdx (R0_IDX)->dname);
349           R0INB++;
350         }
351       else if (!_G.r0Pushed)
352         {
353           emitcode ("push", "%s",
354                     mcs51_regWithIdx (R0_IDX)->dname);
355           _G.r0Pushed++;
356         }
357
358       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
359       (*aopp)->type = AOP_R0;
360
361       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
362     }
363
364   /* if r1 not used then */
365
366   if (!r1iu)
367     {
368       /* push it if not already pushed */
369       if (ic->op == IPUSH)
370         {
371           emitcode ("mov", "b,%s",
372                     mcs51_regWithIdx (R1_IDX)->dname);
373           R1INB++;
374         }
375       else if (!_G.r1Pushed)
376         {
377           emitcode ("push", "%s",
378                     mcs51_regWithIdx (R1_IDX)->dname);
379           _G.r1Pushed++;
380         }
381
382       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
383       (*aopp)->type = AOP_R1;
384       return mcs51_regWithIdx (R1_IDX);
385     }
386 endOfWorld:
387   /* I said end of world, but not quite end of world yet */
388   if (result) {
389     /* we can push it on the stack */
390     (*aopp)->type = AOP_STK;
391     return NULL;
392   } else {
393     /* in the case that result AND left AND right needs a pointer reg
394        we can safely use the result's */
395     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
396       (*aopp)->type = AOP_R0;
397       return mcs51_regWithIdx (R0_IDX);
398     }
399     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
400       (*aopp)->type = AOP_R1;
401       return mcs51_regWithIdx (R1_IDX);
402     }
403   }
404
405   /* now this is REALLY the end of the world */
406   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
407           "getFreePtr should never reach here");
408   exit (1);
409 }
410
411
412 /*-----------------------------------------------------------------*/
413 /* getTempRegs - initialize an array of pointers to GPR registers */
414 /*               that are not in use. Returns 1 if the requested   */
415 /*               number of registers were available, 0 otherwise.  */
416 /*-----------------------------------------------------------------*/
417 int
418 getTempRegs(regs **tempRegs, int size, iCode *ic)
419 {
420   bitVect * freeRegs;
421   int i;
422   int offset;
423
424   if (!ic)
425     ic = _G.current_iCode;
426   if (!ic)
427     return 0;
428   if (!_G.currentFunc)
429     return 0;
430
431   freeRegs = newBitVect(8);
432   bitVectSetBit (freeRegs, R2_IDX);
433   bitVectSetBit (freeRegs, R3_IDX);
434   bitVectSetBit (freeRegs, R4_IDX);
435   bitVectSetBit (freeRegs, R5_IDX);
436   bitVectSetBit (freeRegs, R6_IDX);
437   bitVectSetBit (freeRegs, R7_IDX);
438
439   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
440     {
441       bitVect * newfreeRegs;
442       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
443       freeBitVect(freeRegs);
444       freeRegs = newfreeRegs;
445     }
446   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
447
448   offset = 0;
449   for (i=0; i<freeRegs->size; i++)
450     {
451       if (bitVectBitValue(freeRegs,i))
452         tempRegs[offset++] = mcs51_regWithIdx(i);
453       if (offset>=size)
454         {
455           freeBitVect(freeRegs);
456           return 1;
457         }
458     }
459
460   freeBitVect(freeRegs);
461   return 0;
462 }
463
464
465 /*-----------------------------------------------------------------*/
466 /* newAsmop - creates a new asmOp                                  */
467 /*-----------------------------------------------------------------*/
468 static asmop *
469 newAsmop (short type)
470 {
471   asmop *aop;
472
473   aop = Safe_calloc (1, sizeof (asmop));
474   aop->type = type;
475   aop->allocated = 1;
476   return aop;
477 }
478
479 /*-----------------------------------------------------------------*/
480 /* pointerCode - returns the code for a pointer type               */
481 /*-----------------------------------------------------------------*/
482 static int
483 pointerCode (sym_link * etype)
484 {
485
486   return PTR_TYPE (SPEC_OCLS (etype));
487
488 }
489
490 /*-----------------------------------------------------------------*/
491 /* leftRightUseAcc - returns size of accumulator use by operands   */
492 /*-----------------------------------------------------------------*/
493 static int
494 leftRightUseAcc(iCode *ic)
495 {
496   operand *op;
497   int size;
498   int accuseSize = 0;
499   int accuse = 0;
500
501   if (!ic)
502     {
503       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
504               "null iCode pointer");
505       return 0;
506     }
507
508   if (ic->op == IFX)
509     {
510       op = IC_COND (ic);
511       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
512         {
513           accuse = 1;
514           size = getSize (OP_SYMBOL (op)->type);
515           if (size>accuseSize)
516             accuseSize = size;
517         }
518     }
519   else if (ic->op == JUMPTABLE)
520     {
521       op = IC_JTCOND (ic);
522       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
523         {
524           accuse = 1;
525           size = getSize (OP_SYMBOL (op)->type);
526           if (size>accuseSize)
527             accuseSize = size;
528         }
529     }
530   else
531     {
532       op = IC_LEFT (ic);
533       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
534         {
535           accuse = 1;
536           size = getSize (OP_SYMBOL (op)->type);
537           if (size>accuseSize)
538             accuseSize = size;
539         }
540       op = IC_RIGHT (ic);
541       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
542         {
543           accuse = 1;
544           size = getSize (OP_SYMBOL (op)->type);
545           if (size>accuseSize)
546             accuseSize = size;
547         }
548     }
549
550   if (accuseSize)
551     return accuseSize;
552   else
553     return accuse;
554 }
555
556 /*-----------------------------------------------------------------*/
557 /* aopForSym - for a true symbol                                   */
558 /*-----------------------------------------------------------------*/
559 static asmop *
560 aopForSym (iCode * ic, symbol * sym, bool result)
561 {
562   asmop *aop;
563   memmap *space;
564
565   wassertl (ic != NULL, "Got a null iCode");
566   wassertl (sym != NULL, "Got a null symbol");
567
568   space = SPEC_OCLS (sym->etype);
569
570   /* if already has one */
571   if (sym->aop)
572     {
573           sym->aop->allocated++;
574       return sym->aop;
575     }
576
577   /* assign depending on the storage class */
578   /* if it is on the stack or indirectly addressable */
579   /* space we need to assign either r0 or r1 to it   */
580   if (sym->onStack || sym->iaccess)
581     {
582       sym->aop = aop = newAsmop (0);
583       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
584       aop->size = getSize (sym->type);
585
586       /* now assign the address of the variable to
587          the pointer register */
588       if (aop->type != AOP_STK)
589         {
590
591           if (sym->onStack)
592             {
593               char offset = ((sym->stack < 0) ?
594                          ((char) (sym->stack - _G.nRegsSaved)) :
595                          ((char) sym->stack)) & 0xff;
596
597               if ((offset >= -3) && (offset <= 3))
598                 {
599                   emitcode ("mov", "%s,%s",
600                             aop->aopu.aop_ptr->name, SYM_BP (sym));
601                   while (offset < 0)
602                     {
603                       emitcode ("dec", aop->aopu.aop_ptr->name);
604                       offset++;
605                     }
606                   while (offset > 0)
607                     {
608                       emitcode ("inc", aop->aopu.aop_ptr->name);
609                       offset--;
610                     }
611                 }
612               else
613                 {
614                   if (_G.accInUse || leftRightUseAcc (ic))
615                     emitcode ("push", "acc");
616                   emitcode ("mov", "a,%s", SYM_BP (sym));
617                   emitcode ("add", "a,#0x%02x", offset);
618                   emitcode ("mov", "%s,a",
619                             aop->aopu.aop_ptr->name);
620                   if (_G.accInUse || leftRightUseAcc (ic))
621                     emitcode ("pop", "acc");
622                 }
623             }
624           else
625             emitcode ("mov", "%s,#%s",
626                       aop->aopu.aop_ptr->name,
627                       sym->rname);
628           aop->paged = space->paged;
629         }
630       else
631         aop->aopu.aop_stk = sym->stack;
632       return aop;
633     }
634
635   /* if in bit space */
636   if (IN_BITSPACE (space))
637     {
638       sym->aop = aop = newAsmop (AOP_CRY);
639       aop->aopu.aop_dir = sym->rname;
640       aop->size = getSize (sym->type);
641       return aop;
642     }
643   /* if it is in direct space */
644   if (IN_DIRSPACE (space))
645     {
646       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
647       //printTypeChainRaw(sym->type, NULL);
648       //printf("space = %s\n", space ? space->sname : "NULL");
649       sym->aop = aop = newAsmop (AOP_DIR);
650       aop->aopu.aop_dir = sym->rname;
651       aop->size = getSize (sym->type);
652       return aop;
653     }
654
655   /* special case for a function */
656   if (IS_FUNC (sym->type))
657     {
658       sym->aop = aop = newAsmop (AOP_IMMD);
659       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
660       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
661       aop->size = getSize (sym->type);
662       return aop;
663     }
664
665   /* only remaining is far space */
666   /* in which case DPTR gets the address */
667   sym->aop = aop = newAsmop (AOP_DPTR);
668   emitcode ("mov", "dptr,#%s", sym->rname);
669   aop->size = getSize (sym->type);
670
671   /* if it is in code space */
672   if (IN_CODESPACE (space))
673     aop->code = 1;
674
675   return aop;
676 }
677
678 /*-----------------------------------------------------------------*/
679 /* aopForRemat - rematerialzes an object                           */
680 /*-----------------------------------------------------------------*/
681 static asmop *
682 aopForRemat (symbol * sym)
683 {
684   iCode *ic = sym->rematiCode;
685   asmop *aop = newAsmop (AOP_IMMD);
686   int ptr_type = 0;
687   int val = 0;
688
689   for (;;)
690     {
691       if (ic->op == '+')
692         val += (int) operandLitValue (IC_RIGHT (ic));
693       else if (ic->op == '-')
694         val -= (int) operandLitValue (IC_RIGHT (ic));
695       else if (IS_CAST_ICODE(ic)) {
696               sym_link *from_type = operandType(IC_RIGHT(ic));
697               aop->aopu.aop_immd.from_cast_remat = 1;
698               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
699               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
700               continue;
701       } else break;
702
703       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
704     }
705
706   if (val)
707     sprintf (buffer, "(%s %c 0x%04x)",
708              OP_SYMBOL (IC_LEFT (ic))->rname,
709              val >= 0 ? '+' : '-',
710              abs (val) & 0xffff);
711   else
712     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
713
714   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
715   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
716   /* set immd2 field if required */
717   if (aop->aopu.aop_immd.from_cast_remat) {
718           sprintf(buffer,"#0x%02x",ptr_type);
719           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
720           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
721   }
722
723   return aop;
724 }
725
726 /*-----------------------------------------------------------------*/
727 /* regsInCommon - two operands have some registers in common       */
728 /*-----------------------------------------------------------------*/
729 static bool
730 regsInCommon (operand * op1, operand * op2)
731 {
732   symbol *sym1, *sym2;
733   int i;
734
735   /* if they have registers in common */
736   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
737     return FALSE;
738
739   sym1 = OP_SYMBOL (op1);
740   sym2 = OP_SYMBOL (op2);
741
742   if (sym1->nRegs == 0 || sym2->nRegs == 0)
743     return FALSE;
744
745   for (i = 0; i < sym1->nRegs; i++)
746     {
747       int j;
748       if (!sym1->regs[i])
749         continue;
750
751       for (j = 0; j < sym2->nRegs; j++)
752         {
753           if (!sym2->regs[j])
754             continue;
755
756           if (sym2->regs[j] == sym1->regs[i])
757             return TRUE;
758         }
759     }
760
761   return FALSE;
762 }
763
764 /*-----------------------------------------------------------------*/
765 /* operandsEqu - equivalent                                        */
766 /*-----------------------------------------------------------------*/
767 static bool
768 operandsEqu (operand * op1, operand * op2)
769 {
770   symbol *sym1, *sym2;
771
772   /* if they're not symbols */
773   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
774     return FALSE;
775
776   sym1 = OP_SYMBOL (op1);
777   sym2 = OP_SYMBOL (op2);
778
779   /* if both are itemps & one is spilt
780      and the other is not then false */
781   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
782       sym1->isspilt != sym2->isspilt)
783     return FALSE;
784
785   /* if they are the same */
786   if (sym1 == sym2)
787     return TRUE;
788
789   /* if they have the same rname */
790   if (sym1->rname[0] && sym2->rname[0] &&
791       strcmp (sym1->rname, sym2->rname) == 0 &&
792       !(IS_PARM (op2) && IS_ITEMP (op1)))
793     return TRUE;
794
795   /* if left is a tmp & right is not */
796   if (IS_ITEMP (op1) &&
797       !IS_ITEMP (op2) &&
798       sym1->isspilt &&
799       (sym1->usl.spillLoc == sym2))
800     return TRUE;
801
802   if (IS_ITEMP (op2) &&
803       !IS_ITEMP (op1) &&
804       sym2->isspilt &&
805       sym1->level > 0 &&
806       (sym2->usl.spillLoc == sym1))
807     return TRUE;
808
809   return FALSE;
810 }
811
812 /*-----------------------------------------------------------------*/
813 /* sameReg - two asmops have the same register at given offsets    */
814 /*-----------------------------------------------------------------*/
815 static bool
816 sameReg (asmop * aop1, int off1, asmop * aop2, int off2)
817 {
818   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
819     return FALSE;
820
821   if (aop1->type != aop2->type)
822     return FALSE;
823
824   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
825     return FALSE;
826
827   return TRUE;
828 }
829
830 /*-----------------------------------------------------------------*/
831 /* sameRegs - two asmops have the same registers                   */
832 /*-----------------------------------------------------------------*/
833 static bool
834 sameRegs (asmop * aop1, asmop * aop2)
835 {
836   int i;
837
838   if (aop1 == aop2)
839     return TRUE;
840
841   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
842     return FALSE;
843
844   if (aop1->type != aop2->type)
845     return FALSE;
846
847   if (aop1->size != aop2->size)
848     return FALSE;
849
850   for (i = 0; i < aop1->size; i++)
851     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
852       return FALSE;
853
854   return TRUE;
855 }
856
857 /*-----------------------------------------------------------------*/
858 /* aopOp - allocates an asmop for an operand  :                    */
859 /*-----------------------------------------------------------------*/
860 static void
861 aopOp (operand * op, iCode * ic, bool result)
862 {
863   asmop *aop;
864   symbol *sym;
865   int i;
866
867   if (!op)
868     return;
869
870   /* if this a literal */
871   if (IS_OP_LITERAL (op))
872     {
873       op->aop = aop = newAsmop (AOP_LIT);
874       aop->aopu.aop_lit = op->operand.valOperand;
875       aop->size = getSize (operandType (op));
876       return;
877     }
878
879   /* if already has a asmop then continue */
880   if (op->aop)
881     {
882           op->aop->allocated++;
883       return;
884     }
885
886   /* if the underlying symbol has a aop */
887   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
888     {
889       op->aop = OP_SYMBOL (op)->aop;
890           op->aop->allocated++;
891       return;
892     }
893
894   /* if this is a true symbol */
895   if (IS_TRUE_SYMOP (op))
896     {
897       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
898       return;
899     }
900
901   /* this is a temporary : this has
902      only five choices :
903      a) register
904      b) spillocation
905      c) rematerialize
906      d) conditional
907      e) can be a return use only */
908
909   sym = OP_SYMBOL (op);
910
911   /* if the type is a conditional */
912   if (sym->regType == REG_CND)
913     {
914       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
915       aop->size = 0;
916       return;
917     }
918
919   /* if it is spilt then two situations
920      a) is rematerialize
921      b) has a spill location */
922   if (sym->isspilt || sym->nRegs == 0)
923     {
924
925       /* rematerialize it NOW */
926       if (sym->remat)
927         {
928           sym->aop = op->aop = aop =
929             aopForRemat (sym);
930           aop->size = getSize (sym->type);
931           return;
932         }
933
934       if (sym->accuse)
935         {
936           int i;
937           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
938           aop->size = getSize (sym->type);
939           for (i = 0; i < 2; i++)
940             aop->aopu.aop_str[i] = accUse[i];
941           return;
942         }
943
944       if (sym->ruonly)
945         {
946           unsigned i;
947
948           aop = op->aop = sym->aop = newAsmop (AOP_STR);
949           aop->size = getSize (sym->type);
950           for (i = 0; i < fReturnSizeMCS51; i++)
951             aop->aopu.aop_str[i] = fReturn[i];
952           return;
953         }
954
955       if (sym->usl.spillLoc)
956         {
957           asmop *oldAsmOp = NULL;
958
959           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
960             {
961               /* force a new aop if sizes differ */
962               oldAsmOp = sym->usl.spillLoc->aop;
963               sym->usl.spillLoc->aop = NULL;
964             }
965           sym->aop = op->aop = aop =
966                      aopForSym (ic, sym->usl.spillLoc, result);
967           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
968             {
969               /* Don't reuse the new aop, go with the last one */
970               sym->usl.spillLoc->aop = oldAsmOp;
971             }
972           aop->size = getSize (sym->type);
973           return;
974         }
975
976       /* else must be a dummy iTemp */
977       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
978       aop->size = getSize (sym->type);
979       return;
980     }
981
982   /* if the type is a bit register */
983   if (sym->regType == REG_BIT)
984     {
985       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
986       aop->size = sym->nRegs;//1???
987       aop->aopu.aop_reg[0] = sym->regs[0];
988       aop->aopu.aop_dir = sym->regs[0]->name;
989       return;
990     }
991
992   /* must be in a register */
993   sym->aop = op->aop = aop = newAsmop (AOP_REG);
994   aop->size = sym->nRegs;
995   for (i = 0; i < sym->nRegs; i++)
996     aop->aopu.aop_reg[i] = sym->regs[i];
997 }
998
999 /*-----------------------------------------------------------------*/
1000 /* freeAsmop - free up the asmop given to an operand               */
1001 /*----------------------------------------------------------------*/
1002 static void
1003 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1004 {
1005   asmop *aop;
1006
1007   if (!op)
1008     aop = aaop;
1009   else
1010     aop = op->aop;
1011
1012   if (!aop)
1013     return;
1014
1015   aop->allocated--;
1016
1017   if (aop->allocated)
1018     goto dealloc;
1019
1020   /* depending on the asmop type only three cases need work
1021      AOP_R0, AOP_R1 & AOP_STK */
1022   switch (aop->type)
1023     {
1024     case AOP_R0:
1025       if (R0INB)
1026         {
1027           emitcode ("mov", "r0,b");
1028           R0INB--;
1029         }
1030       else if (_G.r0Pushed)
1031         {
1032           if (pop)
1033             {
1034               emitcode ("pop", "ar0");
1035               _G.r0Pushed--;
1036             }
1037         }
1038       bitVectUnSetBit (ic->rUsed, R0_IDX);
1039       break;
1040
1041     case AOP_R1:
1042       if (R1INB)
1043         {
1044           emitcode ("mov", "r1,b");
1045           R1INB--;
1046         }
1047       if (_G.r1Pushed)
1048         {
1049           if (pop)
1050             {
1051               emitcode ("pop", "ar1");
1052               _G.r1Pushed--;
1053             }
1054         }
1055       bitVectUnSetBit (ic->rUsed, R1_IDX);
1056       break;
1057
1058     case AOP_STK:
1059       {
1060         int sz = aop->size;
1061         int stk = aop->aopu.aop_stk + aop->size - 1;
1062         bitVectUnSetBit (ic->rUsed, R0_IDX);
1063         bitVectUnSetBit (ic->rUsed, R1_IDX);
1064
1065         getFreePtr (ic, &aop, FALSE);
1066
1067         if (stk)
1068           {
1069             emitcode ("mov", "a,_bp");
1070             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1071             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1072           }
1073         else
1074           {
1075             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1076           }
1077
1078         while (sz--)
1079           {
1080             emitcode ("pop", "acc");
1081             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1082             if (!sz)
1083               break;
1084             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1085           }
1086         op->aop = aop;
1087         freeAsmop (op, NULL, ic, TRUE);
1088         if (_G.r1Pushed)
1089           {
1090             emitcode ("pop", "ar1");
1091             _G.r1Pushed--;
1092           }
1093
1094         if (_G.r0Pushed)
1095           {
1096             emitcode ("pop", "ar0");
1097             _G.r0Pushed--;
1098           }
1099       }
1100     }
1101
1102 dealloc:
1103   /* all other cases just dealloc */
1104   if (op)
1105     {
1106       op->aop = NULL;
1107       if (IS_SYMOP (op))
1108         {
1109           OP_SYMBOL (op)->aop = NULL;
1110           /* if the symbol has a spill */
1111           if (SPIL_LOC (op))
1112             SPIL_LOC (op)->aop = NULL;
1113         }
1114     }
1115 }
1116
1117 /*------------------------------------------------------------------*/
1118 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1119 /*                      pop r0 or r1 off stack if pushed            */
1120 /*------------------------------------------------------------------*/
1121 static void
1122 freeForBranchAsmop (operand * op)
1123 {
1124   asmop *aop;
1125
1126   if (!op)
1127     return;
1128
1129   aop = op->aop;
1130
1131   if (!aop)
1132     return;
1133
1134   if (!aop->allocated)
1135     return;
1136
1137   switch (aop->type)
1138     {
1139     case AOP_R0:
1140       if (R0INB)
1141         {
1142           emitcode ("mov", "r0,b");
1143         }
1144       else if (_G.r0Pushed)
1145         {
1146           emitcode ("pop", "ar0");
1147         }
1148       break;
1149
1150     case AOP_R1:
1151       if (R1INB)
1152         {
1153           emitcode ("mov", "r1,b");
1154         }
1155       else if (_G.r1Pushed)
1156         {
1157           emitcode ("pop", "ar1");
1158         }
1159       break;
1160
1161     case AOP_STK:
1162       {
1163         int sz = aop->size;
1164         int stk = aop->aopu.aop_stk + aop->size - 1;
1165
1166         emitcode ("mov", "b,r0");
1167         if (stk)
1168           {
1169             emitcode ("mov", "a,_bp");
1170             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1171             emitcode ("mov", "r0,a");
1172           }
1173         else
1174           {
1175             emitcode ("mov", "r0,_bp");
1176           }
1177
1178         while (sz--)
1179           {
1180             emitcode ("pop", "acc");
1181             emitcode ("mov", "@r0,a");
1182             if (!sz)
1183               break;
1184             emitcode ("dec", "r0");
1185           }
1186         emitcode ("mov", "r0,b");
1187       }
1188     }
1189
1190 }
1191
1192 /*-----------------------------------------------------------------*/
1193 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1194 /*                 clobber the accumulator                         */
1195 /*-----------------------------------------------------------------*/
1196 static bool
1197 aopGetUsesAcc (operand * oper, int offset)
1198 {
1199   asmop * aop = AOP (oper);
1200
1201   if (offset > (aop->size - 1))
1202     return FALSE;
1203
1204   switch (aop->type)
1205     {
1206
1207     case AOP_R0:
1208     case AOP_R1:
1209       if (aop->paged)
1210         return TRUE;
1211       return FALSE;
1212     case AOP_DPTR:
1213       return TRUE;
1214     case AOP_IMMD:
1215       return FALSE;
1216     case AOP_DIR:
1217       return FALSE;
1218     case AOP_REG:
1219       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1220       return FALSE;
1221     case AOP_CRY:
1222       return TRUE;
1223     case AOP_ACC:
1224       if (offset)
1225         return FALSE;
1226       return TRUE;
1227     case AOP_LIT:
1228       return FALSE;
1229     case AOP_STR:
1230       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1231         return TRUE;
1232       return FALSE;
1233     case AOP_DUMMY:
1234       return FALSE;
1235     default:
1236       /* Error case --- will have been caught already */
1237       wassert(0);
1238       return FALSE;
1239     }
1240 }
1241
1242 /*-----------------------------------------------------------------*/
1243 /* aopGet - for fetching value of the aop                          */
1244 /*-----------------------------------------------------------------*/
1245 static char *
1246 aopGet (operand * oper, int offset, bool bit16, bool dname)
1247 {
1248   char *s = buffer;
1249   char *rs;
1250   asmop * aop = AOP (oper);
1251
1252   /* offset is greater than
1253      size then zero */
1254   if (offset > (aop->size - 1) &&
1255       aop->type != AOP_LIT)
1256     return zero;
1257
1258   /* depending on type */
1259   switch (aop->type)
1260     {
1261     case AOP_DUMMY:
1262       return zero;
1263
1264     case AOP_R0:
1265     case AOP_R1:
1266       /* if we need to increment it */
1267       while (offset > aop->coff)
1268         {
1269           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1270           aop->coff++;
1271         }
1272
1273       while (offset < aop->coff)
1274         {
1275           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1276           aop->coff--;
1277         }
1278
1279       aop->coff = offset;
1280       if (aop->paged)
1281         {
1282           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1283           return (dname ? "acc" : "a");
1284         }
1285       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1286       rs = Safe_calloc (1, strlen (s) + 1);
1287       strcpy (rs, s);
1288       return rs;
1289
1290     case AOP_DPTR:
1291       if (aop->code && aop->coff==0 && offset>=1) {
1292         emitcode ("mov", "a,#0x%02x", offset);
1293         emitcode ("movc", "a,@a+dptr");
1294         return (dname ? "acc" : "a");
1295       }
1296
1297       while (offset > aop->coff)
1298         {
1299           emitcode ("inc", "dptr");
1300           aop->coff++;
1301         }
1302
1303       while (offset < aop->coff)
1304         {
1305           emitcode ("lcall", "__decdptr");
1306           aop->coff--;
1307         }
1308
1309       aop->coff = offset;
1310       if (aop->code)
1311         {
1312           emitcode ("clr", "a");
1313           emitcode ("movc", "a,@a+dptr");
1314         }
1315       else
1316         {
1317           emitcode ("movx", "a,@dptr");
1318         }
1319       return (dname ? "acc" : "a");
1320
1321
1322     case AOP_IMMD:
1323       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1324               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1325       } else if (bit16)
1326         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1327       else if (offset)
1328         sprintf (s, "#(%s >> %d)",
1329                  aop->aopu.aop_immd.aop_immd1,
1330                  offset * 8);
1331       else
1332         sprintf (s, "#%s",
1333                  aop->aopu.aop_immd.aop_immd1);
1334       rs = Safe_calloc (1, strlen (s) + 1);
1335       strcpy (rs, s);
1336       return rs;
1337
1338     case AOP_DIR:
1339       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1340         sprintf (s, "(%s >> %d)",
1341                  aop->aopu.aop_dir, offset * 8);
1342       else if (offset)
1343         sprintf (s, "(%s + %d)",
1344                  aop->aopu.aop_dir,
1345                  offset);
1346       else
1347         sprintf (s, "%s", aop->aopu.aop_dir);
1348       rs = Safe_calloc (1, strlen (s) + 1);
1349       strcpy (rs, s);
1350       return rs;
1351
1352     case AOP_REG:
1353       if (dname)
1354         return aop->aopu.aop_reg[offset]->dname;
1355       else
1356         return aop->aopu.aop_reg[offset]->name;
1357
1358     case AOP_CRY:
1359       emitcode ("clr", "a");
1360       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1361       emitcode ("rlc", "a");
1362       return (dname ? "acc" : "a");
1363
1364     case AOP_ACC:
1365       if (!offset && dname)
1366         return "acc";
1367       return aop->aopu.aop_str[offset];
1368
1369     case AOP_LIT:
1370       return aopLiteral (aop->aopu.aop_lit, offset);
1371
1372     case AOP_STR:
1373       aop->coff = offset;
1374       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1375           dname)
1376         return "acc";
1377
1378       return aop->aopu.aop_str[offset];
1379
1380     }
1381
1382   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1383           "aopget got unsupported aop->type");
1384   exit (1);
1385 }
1386
1387 /*-----------------------------------------------------------------*/
1388 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1389 /*                 clobber the accumulator                         */
1390 /*-----------------------------------------------------------------*/
1391 static bool
1392 aopPutUsesAcc (operand * oper, const char *s, int offset)
1393 {
1394   asmop * aop = AOP (oper);
1395
1396   if (offset > (aop->size - 1))
1397     return FALSE;
1398
1399   switch (aop->type)
1400     {
1401     case AOP_DUMMY:
1402       return TRUE;
1403     case AOP_DIR:
1404       return FALSE;
1405     case AOP_REG:
1406       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1407       return FALSE;
1408     case AOP_DPTR:
1409       return TRUE;
1410     case AOP_R0:
1411     case AOP_R1:
1412       return ((aop->paged) || (*s == '@'));
1413     case AOP_STK:
1414       return (*s == '@');
1415     case AOP_CRY:
1416       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1417     case AOP_STR:
1418       return FALSE;
1419     case AOP_IMMD:
1420       return FALSE;
1421     case AOP_ACC:
1422       return FALSE;
1423     default:
1424       /* Error case --- will have been caught already */
1425       wassert(0);
1426       return FALSE;
1427     }
1428 }
1429
1430 /*-----------------------------------------------------------------*/
1431 /* aopPut - puts a string for a aop and indicates if acc is in use */
1432 /*-----------------------------------------------------------------*/
1433 static bool
1434 aopPut (operand * result, const char *s, int offset, bool bvolatile)
1435 {
1436   char *d = buffer;
1437   bool accuse = FALSE;
1438   asmop * aop = AOP (result);
1439
1440   if (aop->size && offset > (aop->size - 1))
1441     {
1442       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1443               "aopPut got offset > aop->size");
1444       exit (1);
1445     }
1446
1447   /* will assign value to value */
1448   /* depending on where it is ofcourse */
1449   switch (aop->type)
1450     {
1451     case AOP_DUMMY:
1452       MOVA (s);         /* read s in case it was volatile */
1453       accuse = TRUE;
1454       break;
1455
1456     case AOP_DIR:
1457       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1458         sprintf (d, "(%s >> %d)", aop->aopu.aop_dir, offset * 8);
1459       else if (offset)
1460         sprintf (d, "(%s + %d)", aop->aopu.aop_dir, offset);
1461       else
1462         sprintf (d, "%s", aop->aopu.aop_dir);
1463
1464       if (strcmp (d, s) || bvolatile)
1465           emitcode ("mov", "%s,%s", d, s);
1466       if (!strcmp (d, "acc"))
1467           accuse = TRUE;
1468
1469       break;
1470
1471     case AOP_REG:
1472       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1473           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1474         {
1475           if (*s == '@' ||
1476               strcmp (s, "r0") == 0 ||
1477               strcmp (s, "r1") == 0 ||
1478               strcmp (s, "r2") == 0 ||
1479               strcmp (s, "r3") == 0 ||
1480               strcmp (s, "r4") == 0 ||
1481               strcmp (s, "r5") == 0 ||
1482               strcmp (s, "r6") == 0 ||
1483               strcmp (s, "r7") == 0)
1484             emitcode ("mov", "%s,%s",
1485                       aop->aopu.aop_reg[offset]->dname, s);
1486           else
1487             emitcode ("mov", "%s,%s",
1488                       aop->aopu.aop_reg[offset]->name, s);
1489         }
1490       break;
1491
1492     case AOP_DPTR:
1493       if (aop->code)
1494         {
1495           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1496                   "aopPut writing to code space");
1497           exit (1);
1498         }
1499
1500       while (offset > aop->coff)
1501         {
1502           aop->coff++;
1503           emitcode ("inc", "dptr");
1504         }
1505
1506       while (offset < aop->coff)
1507         {
1508           aop->coff--;
1509           emitcode ("lcall", "__decdptr");
1510         }
1511
1512       aop->coff = offset;
1513
1514       /* if not in accumulator */
1515       MOVA (s);
1516
1517       emitcode ("movx", "@dptr,a");
1518       break;
1519
1520     case AOP_R0:
1521     case AOP_R1:
1522       while (offset > aop->coff)
1523         {
1524           aop->coff++;
1525           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1526         }
1527       while (offset < aop->coff)
1528         {
1529           aop->coff--;
1530           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1531         }
1532       aop->coff = offset;
1533
1534       if (aop->paged)
1535         {
1536           MOVA (s);
1537           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1538         }
1539       else if (*s == '@')
1540         {
1541           MOVA (s);
1542           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1543         }
1544       else if (strcmp (s, "r0") == 0 ||
1545                strcmp (s, "r1") == 0 ||
1546                strcmp (s, "r2") == 0 ||
1547                strcmp (s, "r3") == 0 ||
1548                strcmp (s, "r4") == 0 ||
1549                strcmp (s, "r5") == 0 ||
1550                strcmp (s, "r6") == 0 ||
1551                strcmp (s, "r7") == 0)
1552         {
1553           char buffer[10];
1554           sprintf (buffer, "a%s", s);
1555           emitcode ("mov", "@%s,%s",
1556                     aop->aopu.aop_ptr->name, buffer);
1557         }
1558       else
1559         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1560
1561       break;
1562
1563     case AOP_STK:
1564       if (strcmp (s, "a") == 0)
1565         emitcode ("push", "acc");
1566       else
1567         if (*s=='@') {
1568           MOVA(s);
1569           emitcode ("push", "acc");
1570         } else {
1571           emitcode ("push", s);
1572         }
1573
1574       break;
1575
1576     case AOP_CRY:
1577       /* if not bit variable */
1578       if (!aop->aopu.aop_dir)
1579         {
1580           /* inefficient: move carry into A and use jz/jnz */
1581           emitcode ("clr", "a");
1582           emitcode ("rlc", "a");
1583           accuse = TRUE;
1584         }
1585       else
1586         {
1587           if (s == zero)
1588             emitcode ("clr", "%s", aop->aopu.aop_dir);
1589           else if (s == one)
1590             emitcode ("setb", "%s", aop->aopu.aop_dir);
1591           else if (!strcmp (s, "c"))
1592             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1593           else if (strcmp (s, aop->aopu.aop_dir))
1594             {
1595               MOVA (s);
1596               /* set C, if a >= 1 */
1597               emitcode ("add", "a,#0xff");
1598               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1599             }
1600         }
1601       break;
1602
1603     case AOP_STR:
1604       aop->coff = offset;
1605       if (strcmp (aop->aopu.aop_str[offset], s) ||
1606           bvolatile)
1607         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1608       break;
1609
1610     case AOP_ACC:
1611       accuse = TRUE;
1612       aop->coff = offset;
1613       if (!offset && (strcmp (s, "acc") == 0) &&
1614           !bvolatile)
1615         break;
1616
1617       if (strcmp (aop->aopu.aop_str[offset], s) &&
1618           !bvolatile)
1619         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1620       break;
1621
1622     default:
1623       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1624               "aopPut got unsupported aop->type");
1625       exit (1);
1626     }
1627
1628     return accuse;
1629 }
1630
1631
1632 #if 0
1633 /*-----------------------------------------------------------------*/
1634 /* pointToEnd :- points to the last byte of the operand            */
1635 /*-----------------------------------------------------------------*/
1636 static void
1637 pointToEnd (asmop * aop)
1638 {
1639   int count;
1640   if (!aop)
1641     return;
1642
1643   aop->coff = count = (aop->size - 1);
1644   switch (aop->type)
1645     {
1646     case AOP_R0:
1647     case AOP_R1:
1648       while (count--)
1649         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1650       break;
1651     case AOP_DPTR:
1652       while (count--)
1653         emitcode ("inc", "dptr");
1654       break;
1655     }
1656
1657 }
1658 #endif
1659
1660 /*-----------------------------------------------------------------*/
1661 /* reAdjustPreg - points a register back to where it should        */
1662 /*-----------------------------------------------------------------*/
1663 static void
1664 reAdjustPreg (asmop * aop)
1665 {
1666   if ((aop->coff==0) || aop->size <= 1)
1667     return;
1668
1669   switch (aop->type)
1670     {
1671     case AOP_R0:
1672     case AOP_R1:
1673       while (aop->coff--)
1674         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1675       break;
1676     case AOP_DPTR:
1677       while (aop->coff--)
1678         {
1679           emitcode ("lcall", "__decdptr");
1680         }
1681       break;
1682     }
1683   aop->coff = 0;
1684 }
1685
1686 /*-----------------------------------------------------------------*/
1687 /* opIsGptr: returns non-zero if the passed operand is       */
1688 /* a generic pointer type.             */
1689 /*-----------------------------------------------------------------*/
1690 static int
1691 opIsGptr (operand * op)
1692 {
1693   sym_link *type = operandType (op);
1694
1695   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1696     {
1697       return 1;
1698     }
1699   return 0;
1700 }
1701
1702 /*-----------------------------------------------------------------*/
1703 /* getDataSize - get the operand data size                         */
1704 /*-----------------------------------------------------------------*/
1705 static int
1706 getDataSize (operand * op)
1707 {
1708   int size;
1709   size = AOP_SIZE (op);
1710   if (size == GPTRSIZE)
1711     {
1712       sym_link *type = operandType (op);
1713       if (IS_GENPTR (type))
1714         {
1715           /* generic pointer; arithmetic operations
1716            * should ignore the high byte (pointer type).
1717            */
1718           size--;
1719         }
1720     }
1721   return size;
1722 }
1723
1724 /*-----------------------------------------------------------------*/
1725 /* outAcc - output Acc                                             */
1726 /*-----------------------------------------------------------------*/
1727 static void
1728 outAcc (operand * result)
1729 {
1730   int size, offset;
1731   size = getDataSize (result);
1732   if (size)
1733     {
1734       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
1735       size--;
1736       offset = 1;
1737       /* unsigned or positive */
1738       while (size--)
1739         {
1740           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
1741         }
1742     }
1743 }
1744
1745 /*-----------------------------------------------------------------*/
1746 /* outBitC - output a bit C                                        */
1747 /*-----------------------------------------------------------------*/
1748 static void
1749 outBitC (operand * result)
1750 {
1751   /* if the result is bit */
1752   if (AOP_TYPE (result) == AOP_CRY)
1753     aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
1754   else
1755     {
1756       emitcode ("clr", "a");
1757       emitcode ("rlc", "a");
1758       outAcc (result);
1759     }
1760 }
1761
1762 /*-----------------------------------------------------------------*/
1763 /* toBoolean - emit code for orl a,operator(sizeop)                */
1764 /*-----------------------------------------------------------------*/
1765 static void
1766 toBoolean (operand * oper)
1767 {
1768   int size = AOP_SIZE (oper) - 1;
1769   int offset = 1;
1770   bool AccUsed = FALSE;
1771   bool pushedB;
1772
1773   while (!AccUsed && size--)
1774     {
1775       AccUsed |= aopGetUsesAcc(oper, offset++);
1776     }
1777
1778   size = AOP_SIZE (oper) - 1;
1779   offset = 1;
1780   MOVA (aopGet (oper, 0, FALSE, FALSE));
1781   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1782     {
1783       pushedB = pushB ();
1784       emitcode("mov", "b,a");
1785       while (--size)
1786         {
1787           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1788           emitcode ("orl", "b,a");
1789         }
1790       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1791       emitcode ("orl", "a,b");
1792       popB (pushedB);
1793     }
1794   else
1795     {
1796       while (size--)
1797         {
1798           emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
1799         }
1800     }
1801 }
1802
1803
1804 /*-----------------------------------------------------------------*/
1805 /* genNot - generate code for ! operation                          */
1806 /*-----------------------------------------------------------------*/
1807 static void
1808 genNot (iCode * ic)
1809 {
1810   symbol *tlbl;
1811
1812   D(emitcode (";     genNot",""));
1813
1814   /* assign asmOps to operand & result */
1815   aopOp (IC_LEFT (ic), ic, FALSE);
1816   aopOp (IC_RESULT (ic), ic, TRUE);
1817
1818   /* if in bit space then a special case */
1819   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1820     {
1821       /* if left==result then cpl bit */
1822       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1823         {
1824           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1825         }
1826       else
1827         {
1828           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1829           emitcode ("cpl", "c");
1830           outBitC (IC_RESULT (ic));
1831         }
1832       goto release;
1833     }
1834
1835   toBoolean (IC_LEFT (ic));
1836
1837   /* set C, if a == 0 */
1838   tlbl = newiTempLabel (NULL);
1839   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1840   emitcode ("", "%05d$:", tlbl->key + 100);
1841   outBitC (IC_RESULT (ic));
1842
1843 release:
1844   /* release the aops */
1845   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1846   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1847 }
1848
1849
1850 /*-----------------------------------------------------------------*/
1851 /* genCpl - generate code for complement                           */
1852 /*-----------------------------------------------------------------*/
1853 static void
1854 genCpl (iCode * ic)
1855 {
1856   int offset = 0;
1857   int size;
1858   symbol *tlbl;
1859   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1860
1861   D(emitcode (";", "genCpl"));
1862
1863   /* assign asmOps to operand & result */
1864   aopOp (IC_LEFT (ic), ic, FALSE);
1865   aopOp (IC_RESULT (ic), ic, TRUE);
1866
1867   /* special case if in bit space */
1868   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1869     {
1870       char *l;
1871
1872       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1873           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1874         {
1875           /* promotion rules are responsible for this strange result:
1876              bit -> int -> ~int -> bit
1877              uchar -> int -> ~int -> bit
1878           */
1879           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1880           goto release;
1881         }
1882
1883       tlbl=newiTempLabel(NULL);
1884       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
1885       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1886           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1887           IS_AOP_PREG (IC_LEFT (ic)))
1888         {
1889           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1890         }
1891       else
1892         {
1893           MOVA (l);
1894           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1895         }
1896       emitcode ("", "%05d$:", tlbl->key + 100);
1897       outBitC (IC_RESULT(ic));
1898       goto release;
1899     }
1900
1901   size = AOP_SIZE (IC_RESULT (ic));
1902   while (size--)
1903     {
1904       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1905       MOVA (l);
1906       emitcode ("cpl", "a");
1907       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1908     }
1909
1910
1911 release:
1912   /* release the aops */
1913   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1914   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1915 }
1916
1917 /*-----------------------------------------------------------------*/
1918 /* genUminusFloat - unary minus for floating points                */
1919 /*-----------------------------------------------------------------*/
1920 static void
1921 genUminusFloat (operand * op, operand * result)
1922 {
1923   int size, offset = 0;
1924   char *l;
1925
1926   D(emitcode (";     genUminusFloat",""));
1927
1928   /* for this we just copy and then flip the bit */
1929
1930   size = AOP_SIZE (op) - 1;
1931
1932   while (size--)
1933     {
1934       aopPut (result,
1935               aopGet (op, offset, FALSE, FALSE),
1936               offset,
1937               isOperandVolatile (result, FALSE));
1938       offset++;
1939     }
1940
1941   l = aopGet (op, offset, FALSE, FALSE);
1942
1943   MOVA (l);
1944
1945   emitcode ("cpl", "acc.7");
1946   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
1947 }
1948
1949 /*-----------------------------------------------------------------*/
1950 /* genUminus - unary minus code generation                         */
1951 /*-----------------------------------------------------------------*/
1952 static void
1953 genUminus (iCode * ic)
1954 {
1955   int offset, size;
1956   sym_link *optype, *rtype;
1957
1958
1959   D(emitcode (";     genUminus",""));
1960
1961   /* assign asmops */
1962   aopOp (IC_LEFT (ic), ic, FALSE);
1963   aopOp (IC_RESULT (ic), ic, TRUE);
1964
1965   /* if both in bit space then special
1966      case */
1967   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1968       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1969     {
1970
1971       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1972       emitcode ("cpl", "c");
1973       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1974       goto release;
1975     }
1976
1977   optype = operandType (IC_LEFT (ic));
1978   rtype = operandType (IC_RESULT (ic));
1979
1980   /* if float then do float stuff */
1981   if (IS_FLOAT (optype))
1982     {
1983       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1984       goto release;
1985     }
1986
1987   /* otherwise subtract from zero */
1988   size = AOP_SIZE (IC_LEFT (ic));
1989   offset = 0;
1990   //CLRC ;
1991   while (size--)
1992     {
1993       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1994       if (!strcmp (l, "a"))
1995         {
1996           if (offset == 0)
1997             SETC;
1998           emitcode ("cpl", "a");
1999           emitcode ("addc", "a,#0");
2000         }
2001       else
2002         {
2003           if (offset == 0)
2004             CLRC;
2005           emitcode ("clr", "a");
2006           emitcode ("subb", "a,%s", l);
2007         }
2008       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
2009     }
2010
2011   /* if any remaining bytes in the result */
2012   /* we just need to propagate the sign   */
2013   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2014     {
2015       emitcode ("rlc", "a");
2016       emitcode ("subb", "a,acc");
2017       while (size--)
2018         aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
2019     }
2020
2021 release:
2022   /* release the aops */
2023   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2024   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2025 }
2026
2027 /*-----------------------------------------------------------------*/
2028 /* saveRegisters - will look for a call and save the registers     */
2029 /*-----------------------------------------------------------------*/
2030 static void
2031 saveRegisters (iCode * lic)
2032 {
2033   int i;
2034   iCode *ic;
2035   bitVect *rsave;
2036
2037   /* look for call */
2038   for (ic = lic; ic; ic = ic->next)
2039     if (ic->op == CALL || ic->op == PCALL)
2040       break;
2041
2042   if (!ic)
2043     {
2044       fprintf (stderr, "found parameter push with no function call\n");
2045       return;
2046     }
2047
2048   /* if the registers have been saved already or don't need to be then
2049      do nothing */
2050   if (ic->regsSaved)
2051     return;
2052   if (IS_SYMOP(IC_LEFT(ic)) &&
2053       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
2054        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
2055     return;
2056
2057   /* save the registers in use at this time but skip the
2058      ones for the result */
2059   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2060                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2061
2062   ic->regsSaved = 1;
2063   if (options.useXstack)
2064     {
2065       int count = bitVectnBitsOn (rsave);
2066
2067       if (count == 1)
2068         {
2069           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2070           if (reg->type == REG_BIT)
2071             {
2072               emitcode ("mov", "a,%s", reg->base);
2073             }
2074           else
2075             {
2076               emitcode ("mov", "a,%s", reg->name);
2077             }
2078           emitcode ("mov", "r0,%s", spname);
2079           emitcode ("inc", "%s", spname);// allocate before use
2080           emitcode ("movx", "@r0,a");
2081           if (bitVectBitValue (rsave, R0_IDX))
2082             emitcode ("mov", "r0,a");
2083         }
2084       else if (count != 0)
2085         {
2086           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2087           int nBits = bitVectnBitsOn (rsavebits);
2088
2089           if (nBits != 0)
2090             {
2091               count = count - nBits + 1;
2092               /* remove all but the first bits as they are pushed all at once */
2093               rsave = bitVectCplAnd (rsave, rsavebits);
2094               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2095             }
2096
2097           if (bitVectBitValue (rsave, R0_IDX))
2098             {
2099               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2100             }
2101           emitcode ("mov", "r0,%s", spname);
2102           MOVA ("r0");
2103           emitcode ("add", "a,#%d", count);
2104           emitcode ("mov", "%s,a", spname);
2105           for (i = 0; i < mcs51_nRegs; i++)
2106             {
2107               if (bitVectBitValue (rsave, i))
2108                 {
2109                   regs * reg = mcs51_regWithIdx (i);
2110                   if (i == R0_IDX)
2111                     {
2112                       emitcode ("pop", "acc");
2113                       emitcode ("push", "acc");
2114                     }
2115                   else if (reg->type == REG_BIT)
2116                     {
2117                       emitcode ("mov", "a,%s", reg->base);
2118                     }
2119                   else
2120                     {
2121                       emitcode ("mov", "a,%s", reg->name);
2122                     }
2123                   emitcode ("movx", "@r0,a");
2124                   if (--count)
2125                     {
2126                       emitcode ("inc", "r0");
2127                     }
2128                 }
2129             }
2130           if (bitVectBitValue (rsave, R0_IDX))
2131             {
2132               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2133             }
2134         }
2135     }
2136   else
2137     {
2138       bool bits_pushed = FALSE;
2139       for (i = 0; i < mcs51_nRegs; i++)
2140         {
2141           if (bitVectBitValue (rsave, i))
2142             {
2143               bits_pushed = pushReg (i, bits_pushed);
2144             }
2145         }
2146     }
2147 }
2148
2149 /*-----------------------------------------------------------------*/
2150 /* unsaveRegisters - pop the pushed registers                      */
2151 /*-----------------------------------------------------------------*/
2152 static void
2153 unsaveRegisters (iCode * ic)
2154 {
2155   int i;
2156   bitVect *rsave;
2157
2158   /* restore the registers in use at this time but skip the
2159      ones for the result */
2160   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2161                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2162
2163   if (options.useXstack)
2164     {
2165       int count = bitVectnBitsOn (rsave);
2166
2167       if (count == 1)
2168         {
2169           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2170           emitcode ("mov", "r0,%s", spname);
2171           emitcode ("dec", "r0");
2172           emitcode ("movx", "a,@r0");
2173           if (reg->type == REG_BIT)
2174             {
2175               emitcode ("mov", "%s,a", reg->base);
2176             }
2177           else
2178             {
2179               emitcode ("mov", "%s,a", reg->name);
2180             }
2181           emitcode ("dec", "%s", spname);
2182         }
2183       else if (count != 0)
2184         {
2185           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2186           int nBits = bitVectnBitsOn (rsavebits);
2187
2188           if (nBits != 0)
2189             {
2190               count = count - nBits + 1;
2191               /* remove all but the first bits as they are popped all at once */
2192               rsave = bitVectCplAnd (rsave, rsavebits);
2193               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2194             }
2195
2196           emitcode ("mov", "r0,%s", spname);
2197           for (i = mcs51_nRegs; i >= 0; i--)
2198             {
2199               if (bitVectBitValue (rsave, i))
2200                 {
2201                   regs * reg = mcs51_regWithIdx (i);
2202                   emitcode ("dec", "r0");
2203                   emitcode ("movx", "a,@r0");
2204                   if (i == R0_IDX)
2205                     {
2206                       emitcode ("push", "acc");
2207                     }
2208                   else if (reg->type == REG_BIT)
2209                     {
2210                       emitcode ("mov", "%s,a", reg->base);
2211                     }
2212                   else
2213                     {
2214                       emitcode ("mov", "%s,a", reg->name);
2215                     }
2216                 }
2217             }
2218           emitcode ("mov", "%s,r0", spname);
2219           if (bitVectBitValue (rsave, R0_IDX))
2220             {
2221               emitcode ("pop", "ar0");
2222             }
2223         }
2224     }
2225   else
2226     {
2227       bool bits_popped = FALSE;
2228       for (i = mcs51_nRegs; i >= 0; i--)
2229         {
2230           if (bitVectBitValue (rsave, i))
2231             {
2232               bits_popped = popReg (i, bits_popped);
2233             }
2234         }
2235     }
2236 }
2237
2238
2239 /*-----------------------------------------------------------------*/
2240 /* pushSide -                                                      */
2241 /*-----------------------------------------------------------------*/
2242 static void
2243 pushSide (operand * oper, int size)
2244 {
2245   int offset = 0;
2246   while (size--)
2247     {
2248       char *l = aopGet (oper, offset++, FALSE, TRUE);
2249       if (AOP_TYPE (oper) != AOP_REG &&
2250           AOP_TYPE (oper) != AOP_DIR &&
2251           strcmp (l, "a"))
2252         {
2253           MOVA (l);
2254           emitcode ("push", "acc");
2255         }
2256       else
2257         {
2258           emitcode ("push", "%s", l);
2259         }
2260     }
2261 }
2262
2263 /*-----------------------------------------------------------------*/
2264 /* assignResultValue - also indicates if acc is in use afterwards  */
2265 /*-----------------------------------------------------------------*/
2266 static bool
2267 assignResultValue (operand * oper, operand * func)
2268 {
2269   int offset = 0;
2270   int size = AOP_SIZE (oper);
2271   bool accuse = FALSE;
2272   bool pushedA = FALSE;
2273
2274   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2275     {
2276       outBitC (oper);
2277       return FALSE;
2278     }
2279
2280   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2281     {
2282       emitcode ("push", "acc");
2283       pushedA = TRUE;
2284     }
2285   while (size--)
2286     {
2287       if ((offset == 3) && pushedA)
2288         emitcode ("pop", "acc");
2289       accuse |= aopPut (oper, fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2290       offset++;
2291     }
2292   return accuse;
2293 }
2294
2295
2296 /*-----------------------------------------------------------------*/
2297 /* genXpush - pushes onto the external stack                       */
2298 /*-----------------------------------------------------------------*/
2299 static void
2300 genXpush (iCode * ic)
2301 {
2302   asmop *aop = newAsmop (0);
2303   regs *r;
2304   int size, offset = 0;
2305
2306   D(emitcode (";     genXpush",""));
2307
2308   aopOp (IC_LEFT (ic), ic, FALSE);
2309   r = getFreePtr (ic, &aop, FALSE);
2310
2311   size = AOP_SIZE (IC_LEFT (ic));
2312
2313   if (size == 1)
2314     {
2315       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2316       emitcode ("mov", "%s,%s", r->name, spname);
2317       emitcode ("inc", "%s", spname); // allocate space first
2318       emitcode ("movx", "@%s,a", r->name);
2319     }
2320   else
2321     {
2322       // allocate space first
2323       emitcode ("mov", "%s,%s", r->name, spname);
2324       MOVA (r->name);
2325       emitcode ("add", "a,#%d", size);
2326       emitcode ("mov", "%s,a", spname);
2327
2328       while (size--)
2329         {
2330           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2331           emitcode ("movx", "@%s,a", r->name);
2332           emitcode ("inc", "%s", r->name);
2333         }
2334     }
2335
2336   freeAsmop (NULL, aop, ic, TRUE);
2337   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2338 }
2339
2340 /*-----------------------------------------------------------------*/
2341 /* genIpush - generate code for pushing this gets a little complex */
2342 /*-----------------------------------------------------------------*/
2343 static void
2344 genIpush (iCode * ic)
2345 {
2346   int size, offset = 0;
2347   char *l;
2348   char *prev = "";
2349
2350   D(emitcode (";     genIpush",""));
2351
2352   /* if this is not a parm push : ie. it is spill push
2353      and spill push is always done on the local stack */
2354   if (!ic->parmPush)
2355     {
2356
2357       /* and the item is spilt then do nothing */
2358       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2359         return;
2360
2361       aopOp (IC_LEFT (ic), ic, FALSE);
2362       size = AOP_SIZE (IC_LEFT (ic));
2363       /* push it on the stack */
2364       while (size--)
2365         {
2366           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2367           if (*l == '#')
2368             {
2369               MOVA (l);
2370               l = "acc";
2371             }
2372           emitcode ("push", "%s", l);
2373         }
2374       return;
2375     }
2376
2377   /* this is a parameter push: in this case we call
2378      the routine to find the call and save those
2379      registers that need to be saved */
2380   saveRegisters (ic);
2381
2382   /* if use external stack then call the external
2383      stack pushing routine */
2384   if (options.useXstack)
2385     {
2386       genXpush (ic);
2387       return;
2388     }
2389
2390   /* then do the push */
2391   aopOp (IC_LEFT (ic), ic, FALSE);
2392
2393   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2394   size = AOP_SIZE (IC_LEFT (ic));
2395
2396   while (size--)
2397     {
2398       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2399       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2400           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2401           strcmp (l, "a"))
2402         {
2403           if (strcmp (l, prev) || *l == '@')
2404             MOVA (l);
2405           emitcode ("push", "acc");
2406         }
2407       else
2408         {
2409           emitcode ("push", "%s", l);
2410         }
2411       prev = l;
2412     }
2413
2414   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2415 }
2416
2417 /*-----------------------------------------------------------------*/
2418 /* genIpop - recover the registers: can happen only for spilling   */
2419 /*-----------------------------------------------------------------*/
2420 static void
2421 genIpop (iCode * ic)
2422 {
2423   int size, offset;
2424
2425   D(emitcode (";     genIpop",""));
2426
2427   /* if the temp was not pushed then */
2428   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2429     return;
2430
2431   aopOp (IC_LEFT (ic), ic, FALSE);
2432   size = AOP_SIZE (IC_LEFT (ic));
2433   offset = (size - 1);
2434   while (size--)
2435     emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2436                                    FALSE, TRUE));
2437
2438   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2439 }
2440
2441 /*-----------------------------------------------------------------*/
2442 /* saveRBank - saves an entire register bank on the stack          */
2443 /*-----------------------------------------------------------------*/
2444 static void
2445 saveRBank (int bank, iCode * ic, bool pushPsw)
2446 {
2447   int i;
2448   int count = 8 + ((mcs51_nRegs > 8) ? 1 : 0) + (pushPsw ? 1 : 0);
2449   asmop *aop = NULL;
2450   regs *r = NULL;
2451
2452   if (options.useXstack)
2453     {
2454       if (!ic)
2455       {
2456           /* Assume r0 is available for use. */
2457           r = mcs51_regWithIdx (R0_IDX);;
2458       }
2459       else
2460       {
2461           aop = newAsmop (0);
2462           r = getFreePtr (ic, &aop, FALSE);
2463       }
2464       // allocate space first
2465       emitcode ("mov", "%s,%s", r->name, spname);
2466       MOVA (r->name);
2467       emitcode ("add", "a,#%d", count);
2468       emitcode ("mov", "%s,a", spname);
2469     }
2470
2471   for (i = 0; i < 8; i++)
2472     {
2473       if (options.useXstack)
2474         {
2475           emitcode ("mov", "a,(%s+%d)",
2476                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2477           emitcode ("movx", "@%s,a", r->name);
2478           if (--count)
2479             emitcode ("inc", "%s", r->name);
2480         }
2481       else
2482         emitcode ("push", "(%s+%d)",
2483                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2484     }
2485
2486   if (mcs51_nRegs > 8)
2487     {
2488       if (options.useXstack)
2489         {
2490           emitcode ("mov", "a,bits");
2491           emitcode ("movx", "@%s,a", r->name);
2492           if (--count)
2493             emitcode ("inc", "%s", r->name);
2494         }
2495       else
2496         {
2497           emitcode ("push", "bits");
2498         }
2499       BitBankUsed = 1;
2500     }
2501
2502   if (pushPsw)
2503     {
2504       if (options.useXstack)
2505         {
2506           emitcode ("mov", "a,psw");
2507           emitcode ("movx", "@%s,a", r->name);
2508
2509         }
2510       else
2511         {
2512           emitcode ("push", "psw");
2513         }
2514
2515       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2516     }
2517
2518   if (aop)
2519     {
2520       freeAsmop (NULL, aop, ic, TRUE);
2521     }
2522
2523   if (ic)
2524   {
2525     ic->bankSaved = 1;
2526   }
2527 }
2528
2529 /*-----------------------------------------------------------------*/
2530 /* unsaveRBank - restores the register bank from stack             */
2531 /*-----------------------------------------------------------------*/
2532 static void
2533 unsaveRBank (int bank, iCode * ic, bool popPsw)
2534 {
2535   int i;
2536   asmop *aop = NULL;
2537   regs *r = NULL;
2538
2539   if (options.useXstack)
2540     {
2541       if (!ic)
2542         {
2543           /* Assume r0 is available for use. */
2544           r = mcs51_regWithIdx (R0_IDX);;
2545         }
2546       else
2547         {
2548           aop = newAsmop (0);
2549           r = getFreePtr (ic, &aop, FALSE);
2550         }
2551       emitcode ("mov", "%s,%s", r->name, spname);
2552     }
2553
2554   if (popPsw)
2555     {
2556       if (options.useXstack)
2557         {
2558           emitcode ("dec", "%s", r->name);
2559           emitcode ("movx", "a,@%s", r->name);
2560           emitcode ("mov", "psw,a");
2561         }
2562       else
2563         {
2564           emitcode ("pop", "psw");
2565         }
2566     }
2567
2568   if (mcs51_nRegs > 8)
2569     {
2570       if (options.useXstack)
2571         {
2572           emitcode ("dec", "%s", r->name);
2573           emitcode ("movx", "a,@%s", r->name);
2574           emitcode ("mov", "bits,a");
2575         }
2576       else
2577         {
2578           emitcode ("pop", "bits");
2579         }
2580     }
2581
2582   for (i = 7; i >= 0; i--)
2583     {
2584       if (options.useXstack)
2585         {
2586           emitcode ("dec", "%s", r->name);
2587           emitcode ("movx", "a,@%s", r->name);
2588           emitcode ("mov", "(%s+%d),a",
2589                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2590         }
2591       else
2592         {
2593           emitcode ("pop", "(%s+%d)",
2594                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2595         }
2596     }
2597
2598   if (options.useXstack)
2599     {
2600       emitcode ("mov", "%s,%s", spname, r->name);
2601     }
2602
2603   if (aop)
2604     {
2605       freeAsmop (NULL, aop, ic, TRUE);
2606     }
2607 }
2608
2609 /*-----------------------------------------------------------------*/
2610 /* genSend - gen code for SEND                                     */
2611 /*-----------------------------------------------------------------*/
2612 static void genSend(set *sendSet)
2613 {
2614   iCode *sic;
2615   int bit_count = 0;
2616
2617   /* first we do all bit parameters */
2618   for (sic = setFirstItem (sendSet); sic;
2619        sic = setNextItem (sendSet))
2620     {
2621       if (sic->argreg > 12)
2622         {
2623           int bit = sic->argreg-13;
2624
2625           aopOp (IC_LEFT (sic), sic, FALSE);
2626
2627           /* if left is a literal then
2628              we know what the value is */
2629           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2630             {
2631               if (((int) operandLitValue (IC_LEFT (sic))))
2632                   emitcode ("setb", "b[%d]", bit);
2633               else
2634                   emitcode ("clr", "b[%d]", bit);
2635             }
2636           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2637             {
2638               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2639                 if (strcmp (l, "c"))
2640                     emitcode ("mov", "c,%s", l);
2641                 emitcode ("mov", "b[%d],c", bit);
2642             }
2643           else
2644             {
2645               /* we need to or */
2646               toBoolean (IC_LEFT (sic));
2647               /* set C, if a >= 1 */
2648               emitcode ("add", "a,#0xff");
2649               emitcode ("mov", "b[%d],c", bit);
2650             }
2651           bit_count++;
2652           BitBankUsed = 1;
2653
2654           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2655         }
2656     }
2657
2658   if (bit_count)
2659     {
2660       saveRegisters (setFirstItem (sendSet));
2661       emitcode ("mov", "bits,b");
2662     }
2663
2664   /* then we do all other parameters */
2665   for (sic = setFirstItem (sendSet); sic;
2666        sic = setNextItem (sendSet))
2667     {
2668       if (sic->argreg <= 12)
2669         {
2670           int size, offset = 0;
2671           aopOp (IC_LEFT (sic), sic, FALSE);
2672           size = AOP_SIZE (IC_LEFT (sic));
2673
2674           if (sic->argreg == 1)
2675             {
2676               while (size--)
2677                 {
2678                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2679                   if (strcmp (l, fReturn[offset]))
2680                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2681                   offset++;
2682                 }
2683             }
2684           else
2685             {
2686               while (size--)
2687                 {
2688                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2689                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2690                   offset++;
2691                 }
2692             }
2693           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2694         }
2695     }
2696 }
2697
2698 /*-----------------------------------------------------------------*/
2699 /* selectRegBank - emit code to select the register bank           */
2700 /*-----------------------------------------------------------------*/
2701 static void
2702 selectRegBank (short bank, bool keepFlags)
2703 {
2704   /* if f.e. result is in carry */
2705   if (keepFlags)
2706     {
2707       emitcode ("anl", "psw,#0xE7");
2708       if (bank)
2709         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2710     }
2711   else
2712     {
2713       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2714     }
2715 }
2716
2717 /*-----------------------------------------------------------------*/
2718 /* genCall - generates a call statement                            */
2719 /*-----------------------------------------------------------------*/
2720 static void
2721 genCall (iCode * ic)
2722 {
2723   sym_link *dtype;
2724   sym_link *etype;
2725 //  bool restoreBank = FALSE;
2726   bool swapBanks = FALSE;
2727   bool accuse = FALSE;
2728   bool accPushed = FALSE;
2729   bool resultInF0 = FALSE;
2730   bool assignResultGenerated = FALSE;
2731
2732   D(emitcode(";     genCall",""));
2733
2734   dtype = operandType (IC_LEFT (ic));
2735   etype = getSpec(dtype);
2736   /* if send set is not empty then assign */
2737   if (_G.sendSet)
2738     {
2739         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2740             genSend(reverseSet(_G.sendSet));
2741         } else {
2742             genSend(_G.sendSet);
2743         }
2744
2745       _G.sendSet = NULL;
2746     }
2747
2748   /* if we are calling a not _naked function that is not using
2749      the same register bank then we need to save the
2750      destination registers on the stack */
2751   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2752       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2753        !IFFUNC_ISISR (dtype))
2754     {
2755       swapBanks = TRUE;
2756     }
2757
2758   /* if caller saves & we have not saved then */
2759   if (!ic->regsSaved)
2760       saveRegisters (ic);
2761
2762   if (swapBanks)
2763     {
2764         emitcode ("mov", "psw,#0x%02x",
2765            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2766     }
2767
2768   /* make the call */
2769   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2770     {
2771       if (IFFUNC_CALLEESAVES(dtype))
2772         {
2773           werror (E_BANKED_WITH_CALLEESAVES);
2774         }
2775       else
2776         {
2777           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2778                      OP_SYMBOL (IC_LEFT (ic))->rname :
2779                      OP_SYMBOL (IC_LEFT (ic))->name);
2780
2781           emitcode ("mov", "r0,#%s", l);
2782           emitcode ("mov", "r1,#(%s >> 8)", l);
2783           emitcode ("mov", "r2,#(%s >> 16)", l);
2784           emitcode ("lcall", "__sdcc_banked_call");
2785         }
2786     }
2787   else
2788     {
2789       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2790                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2791                                 OP_SYMBOL (IC_LEFT (ic))->name));
2792     }
2793
2794   if (swapBanks)
2795     {
2796       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2797     }
2798
2799   /* if we need assign a result value */
2800   if ((IS_ITEMP (IC_RESULT (ic)) &&
2801        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2802        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2803         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2804         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2805       IS_TRUE_SYMOP (IC_RESULT (ic)))
2806     {
2807
2808       _G.accInUse++;
2809       aopOp (IC_RESULT (ic), ic, FALSE);
2810       _G.accInUse--;
2811
2812       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2813       assignResultGenerated = TRUE;
2814
2815       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2816     }
2817
2818   /* adjust the stack for parameters if required */
2819   if (ic->parmBytes)
2820     {
2821       int i;
2822       if (ic->parmBytes > 3)
2823         {
2824           if (accuse)
2825             {
2826               emitcode ("push", "acc");
2827               accPushed = TRUE;
2828             }
2829           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2830               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2831               !assignResultGenerated)
2832             {
2833               emitcode ("mov", "F0,c");
2834               resultInF0 = TRUE;
2835             }
2836
2837           emitcode ("mov", "a,%s", spname);
2838           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2839           emitcode ("mov", "%s,a", spname);
2840
2841           /* unsaveRegisters from xstack needs acc, but */
2842           /* unsaveRegisters from stack needs this popped */
2843           if (accPushed && !options.useXstack)
2844             {
2845               emitcode ("pop", "acc");
2846               accPushed = FALSE;
2847             }
2848         }
2849       else
2850         for (i = 0; i < ic->parmBytes; i++)
2851           emitcode ("dec", "%s", spname);
2852     }
2853
2854   /* if we had saved some registers then unsave them */
2855   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2856     {
2857       if (accuse && !accPushed && options.useXstack)
2858         {
2859           /* xstack needs acc, but doesn't touch normal stack */
2860           emitcode ("push", "acc");
2861           accPushed = TRUE;
2862         }
2863       unsaveRegisters (ic);
2864     }
2865
2866 //  /* if register bank was saved then pop them */
2867 //  if (restoreBank)
2868 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2869
2870   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
2871     {
2872       if (resultInF0)
2873           emitcode ("mov", "c,F0");
2874
2875       aopOp (IC_RESULT (ic), ic, FALSE);
2876       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2877       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2878     }
2879
2880   if (accPushed)
2881     emitcode ("pop", "acc");
2882 }
2883
2884 /*-----------------------------------------------------------------*/
2885 /* -10l - generates a call by pointer statement                */
2886 /*-----------------------------------------------------------------*/
2887 static void
2888 genPcall (iCode * ic)
2889 {
2890   sym_link *dtype;
2891   sym_link *etype;
2892   symbol *rlbl = newiTempLabel (NULL);
2893 //  bool restoreBank=FALSE;
2894   bool swapBanks = FALSE;
2895   bool resultInF0 = FALSE;
2896
2897   D(emitcode(";     genPCall",""));
2898
2899   dtype = operandType (IC_LEFT (ic))->next;
2900   etype = getSpec(dtype);
2901   /* if caller saves & we have not saved then */
2902   if (!ic->regsSaved)
2903     saveRegisters (ic);
2904
2905   /* if we are calling a not _naked function that is not using
2906      the same register bank then we need to save the
2907      destination registers on the stack */
2908   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2909       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2910       !IFFUNC_ISISR (dtype))
2911     {
2912 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2913 //    restoreBank=TRUE;
2914       swapBanks = TRUE;
2915       // need caution message to user here
2916     }
2917
2918   if (IS_LITERAL(etype))
2919     {
2920       /* if send set is not empty then assign */
2921       if (_G.sendSet)
2922         {
2923           genSend(reverseSet(_G.sendSet));
2924           _G.sendSet = NULL;
2925         }
2926
2927       if (swapBanks)
2928         {
2929           emitcode ("mov", "psw,#0x%02x",
2930            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2931         }
2932
2933       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2934         {
2935           if (IFFUNC_CALLEESAVES(dtype))
2936             {
2937               werror (E_BANKED_WITH_CALLEESAVES);
2938             }
2939           else
2940             {
2941               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
2942
2943               emitcode ("mov", "r0,#%s", l);
2944               emitcode ("mov", "r1,#(%s >> 8)", l);
2945               emitcode ("mov", "r2,#(%s >> 16)", l);
2946               emitcode ("lcall", "__sdcc_banked_call");
2947             }
2948         }
2949       else
2950         {
2951           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
2952         }
2953     }
2954   else
2955     {
2956       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2957         {
2958           if (IFFUNC_CALLEESAVES(dtype))
2959             {
2960               werror (E_BANKED_WITH_CALLEESAVES);
2961             }
2962           else
2963             {
2964               aopOp (IC_LEFT (ic), ic, FALSE);
2965
2966               if (!swapBanks)
2967                 {
2968                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2969                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2970                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2971                 }
2972               else
2973                 {
2974                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
2975                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2976                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2977                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2978                 }
2979
2980               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2981
2982               /* if send set is not empty then assign */
2983               if (_G.sendSet)
2984                 {
2985                   genSend(reverseSet(_G.sendSet));
2986                   _G.sendSet = NULL;
2987                 }
2988
2989               if (swapBanks)
2990                 {
2991                   emitcode ("mov", "psw,#0x%02x",
2992                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2993                 }
2994
2995               /* make the call */
2996               emitcode ("lcall", "__sdcc_banked_call");
2997             }
2998         }
2999       else
3000         {
3001           /* push the return address on to the stack */
3002           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3003           emitcode ("push", "acc");
3004           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3005           emitcode ("push", "acc");
3006
3007           /* now push the calling address */
3008           aopOp (IC_LEFT (ic), ic, FALSE);
3009
3010           pushSide (IC_LEFT (ic), FPTRSIZE);
3011
3012           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3013
3014           /* if send set is not empty the assign */
3015           if (_G.sendSet)
3016             {
3017               genSend(reverseSet(_G.sendSet));
3018               _G.sendSet = NULL;
3019             }
3020
3021           if (swapBanks)
3022             {
3023               emitcode ("mov", "psw,#0x%02x",
3024                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3025             }
3026
3027           /* make the call */
3028           emitcode ("ret", "");
3029           emitcode ("", "%05d$:", (rlbl->key + 100));
3030         }
3031     }
3032   if (swapBanks)
3033     {
3034       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3035     }
3036
3037   /* if we need assign a result value */
3038   if ((IS_ITEMP (IC_RESULT (ic)) &&
3039        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3040        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3041         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3042       IS_TRUE_SYMOP (IC_RESULT (ic)))
3043     {
3044
3045       _G.accInUse++;
3046       aopOp (IC_RESULT (ic), ic, FALSE);
3047       _G.accInUse--;
3048
3049       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3050
3051       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3052     }
3053
3054   /* adjust the stack for parameters if required */
3055   if (ic->parmBytes)
3056     {
3057       int i;
3058       if (ic->parmBytes > 3)
3059         {
3060           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3061               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3062             {
3063               emitcode ("mov", "F0,c");
3064               resultInF0 = TRUE;
3065             }
3066
3067           emitcode ("mov", "a,%s", spname);
3068           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3069           emitcode ("mov", "%s,a", spname);
3070         }
3071       else
3072         for (i = 0; i < ic->parmBytes; i++)
3073           emitcode ("dec", "%s", spname);
3074
3075     }
3076
3077 //  /* if register bank was saved then unsave them */
3078 //  if (restoreBank)
3079 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3080
3081   /* if we had saved some registers then unsave them */
3082   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3083     unsaveRegisters (ic);
3084
3085   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3086     {
3087       if (resultInF0)
3088           emitcode ("mov", "c,F0");
3089
3090       aopOp (IC_RESULT (ic), ic, FALSE);
3091       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3092       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3093     }
3094 }
3095
3096 /*-----------------------------------------------------------------*/
3097 /* resultRemat - result  is rematerializable                       */
3098 /*-----------------------------------------------------------------*/
3099 static int
3100 resultRemat (iCode * ic)
3101 {
3102   if (SKIP_IC (ic) || ic->op == IFX)
3103     return 0;
3104
3105   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3106     {
3107       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3108       if (sym->remat && !POINTER_SET (ic))
3109         return 1;
3110     }
3111
3112   return 0;
3113 }
3114
3115 #if defined(__BORLANDC__) || defined(_MSC_VER)
3116 #define STRCASECMP stricmp
3117 #else
3118 #define STRCASECMP strcasecmp
3119 #endif
3120
3121 /*-----------------------------------------------------------------*/
3122 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3123 /*-----------------------------------------------------------------*/
3124 static int
3125 regsCmp(void *p1, void *p2)
3126 {
3127   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3128 }
3129
3130 static bool
3131 inExcludeList (char *s)
3132 {
3133   const char *p = setFirstItem(options.excludeRegsSet);
3134
3135   if (p == NULL || STRCASECMP(p, "none") == 0)
3136     return FALSE;
3137
3138
3139   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3140 }
3141
3142 /*-----------------------------------------------------------------*/
3143 /* genFunction - generated code for function entry                 */
3144 /*-----------------------------------------------------------------*/
3145 static void
3146 genFunction (iCode * ic)
3147 {
3148   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3149   sym_link *ftype;
3150   bool     switchedPSW = FALSE;
3151   int      calleesaves_saved_register = -1;
3152   int      stackAdjust = sym->stack;
3153   int      accIsFree = sym->recvSize < 4;
3154   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3155   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3156
3157   _G.nRegsSaved = 0;
3158   /* create the function header */
3159   emitcode (";", "-----------------------------------------");
3160   emitcode (";", " function %s", sym->name);
3161   emitcode (";", "-----------------------------------------");
3162
3163   emitcode ("", "%s:", sym->rname);
3164   ftype = operandType (IC_LEFT (ic));
3165   _G.currentFunc = sym;
3166
3167   if (IFFUNC_ISNAKED(ftype))
3168   {
3169       emitcode(";", "naked function: no prologue.");
3170       return;
3171   }
3172
3173   /* here we need to generate the equates for the
3174      register bank if required */
3175   if (FUNC_REGBANK (ftype) != rbank)
3176     {
3177       int i;
3178
3179       rbank = FUNC_REGBANK (ftype);
3180       for (i = 0; i < mcs51_nRegs; i++)
3181         {
3182           if (regs8051[i].type != REG_BIT)
3183             {
3184               if (strcmp (regs8051[i].base, "0") == 0)
3185                 emitcode ("", "%s = 0x%02x",
3186                           regs8051[i].dname,
3187                           8 * rbank + regs8051[i].offset);
3188               else
3189                 emitcode ("", "%s = %s + 0x%02x",
3190                           regs8051[i].dname,
3191                           regs8051[i].base,
3192                           8 * rbank + regs8051[i].offset);
3193             }
3194         }
3195     }
3196
3197   /* if this is an interrupt service routine then
3198      save acc, b, dpl, dph  */
3199   if (IFFUNC_ISISR (sym->type))
3200     {
3201
3202       if (!inExcludeList ("acc"))
3203         emitcode ("push", "acc");
3204       if (!inExcludeList ("b"))
3205         emitcode ("push", "b");
3206       if (!inExcludeList ("dpl"))
3207         emitcode ("push", "dpl");
3208       if (!inExcludeList ("dph"))
3209         emitcode ("push", "dph");
3210       /* if this isr has no bank i.e. is going to
3211          run with bank 0 , then we need to save more
3212          registers :-) */
3213       if (!FUNC_REGBANK (sym->type))
3214         {
3215
3216           /* if this function does not call any other
3217              function then we can be economical and
3218              save only those registers that are used */
3219           if (!IFFUNC_HASFCALL(sym->type))
3220             {
3221               int i;
3222
3223               /* if any registers used */
3224               if (sym->regsUsed)
3225                 {
3226                   bool bits_pushed = FALSE;
3227                   /* save the registers used */
3228                   for (i = 0; i < sym->regsUsed->size; i++)
3229                     {
3230                       if (bitVectBitValue (sym->regsUsed, i))
3231                         bits_pushed = pushReg (i, bits_pushed);
3232                     }
3233                 }
3234             }
3235           else
3236             {
3237
3238               /* this function has a function call. We cannot
3239                  determines register usage so we will have to push the
3240                  entire bank */
3241                 saveRBank (0, ic, FALSE);
3242                 if (options.parms_in_bank1) {
3243                     int i;
3244                     for (i=0; i < 8 ; i++ ) {
3245                         emitcode ("push","%s",rb1regs[i]);
3246                     }
3247                 }
3248             }
3249         }
3250         else
3251         {
3252             /* This ISR uses a non-zero bank.
3253              *
3254              * We assume that the bank is available for our
3255              * exclusive use.
3256              *
3257              * However, if this ISR calls a function which uses some
3258              * other bank, we must save that bank entirely.
3259              */
3260             unsigned long banksToSave = 0;
3261
3262             if (IFFUNC_HASFCALL(sym->type))
3263             {
3264
3265 #define MAX_REGISTER_BANKS 4
3266
3267                 iCode *i;
3268                 int ix;
3269
3270                 for (i = ic; i; i = i->next)
3271                 {
3272                     if (i->op == ENDFUNCTION)
3273                     {
3274                         /* we got to the end OK. */
3275                         break;
3276                     }
3277
3278                     if (i->op == CALL)
3279                     {
3280                         sym_link *dtype;
3281
3282                         dtype = operandType (IC_LEFT(i));
3283                         if (dtype
3284                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3285                         {
3286                              /* Mark this bank for saving. */
3287                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3288                              {
3289                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3290                              }
3291                              else
3292                              {
3293                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3294                              }
3295
3296                              /* And note that we don't need to do it in
3297                               * genCall.
3298                               */
3299                              i->bankSaved = 1;
3300                         }
3301                     }
3302                     if (i->op == PCALL)
3303                     {
3304                         /* This is a mess; we have no idea what
3305                          * register bank the called function might
3306                          * use.
3307                          *
3308                          * The only thing I can think of to do is
3309                          * throw a warning and hope.
3310                          */
3311                         werror(W_FUNCPTR_IN_USING_ISR);
3312                     }
3313                 }
3314
3315                 if (banksToSave && options.useXstack)
3316                 {
3317                     /* Since we aren't passing it an ic,
3318                      * saveRBank will assume r0 is available to abuse.
3319                      *
3320                      * So switch to our (trashable) bank now, so
3321                      * the caller's R0 isn't trashed.
3322                      */
3323                     emitcode ("push", "psw");
3324                     emitcode ("mov", "psw,#0x%02x",
3325                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3326                     switchedPSW = TRUE;
3327                 }
3328
3329                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3330                 {
3331                      if (banksToSave & (1 << ix))
3332                      {
3333                          saveRBank(ix, NULL, FALSE);
3334                      }
3335                 }
3336             }
3337             // TODO: this needs a closer look
3338             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3339         }
3340
3341       /* Set the register bank to the desired value if nothing else */
3342       /* has done so yet. */
3343       if (!switchedPSW)
3344         {
3345           emitcode ("push", "psw");
3346           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3347         }
3348     }
3349   else
3350     {
3351       /* This is a non-ISR function. The caller has already switched register */
3352       /* banks, if necessary, so just handle the callee-saves option. */
3353
3354       /* if callee-save to be used for this function
3355          then save the registers being used in this function */
3356       if (IFFUNC_CALLEESAVES(sym->type))
3357         {
3358           int i;
3359
3360           /* if any registers used */
3361           if (sym->regsUsed)
3362             {
3363               bool bits_pushed = FALSE;
3364               /* save the registers used */
3365               for (i = 0; i < sym->regsUsed->size; i++)
3366                 {
3367                   if (bitVectBitValue (sym->regsUsed, i))
3368                     {
3369                       /* remember one saved register for later usage */
3370                       if (calleesaves_saved_register < 0)
3371                         calleesaves_saved_register = i;
3372                       bits_pushed = pushReg (i, bits_pushed);
3373                       _G.nRegsSaved++;
3374                     }
3375                 }
3376             }
3377         }
3378     }
3379
3380
3381   if (fReentrant)
3382     {
3383       if (options.useXstack)
3384         {
3385           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3386             {
3387               emitcode ("mov", "r0,%s", spname);
3388               emitcode ("inc", "%s", spname);
3389               emitcode ("xch", "a,_bpx");
3390               emitcode ("movx", "@r0,a");
3391               emitcode ("inc", "r0");
3392               emitcode ("mov", "a,r0");
3393               emitcode ("xch", "a,_bpx");
3394             }
3395           if (sym->stack)
3396             {
3397               emitcode ("push", "_bp");     /* save the callers stack  */
3398               emitcode ("mov", "_bp,sp");
3399             }
3400         }
3401       else
3402         {
3403           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3404             {
3405               /* set up the stack */
3406               emitcode ("push", "_bp");     /* save the callers stack  */
3407               emitcode ("mov", "_bp,sp");
3408             }
3409         }
3410     }
3411
3412   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3413   /* before setting up the stack frame completely. */
3414   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3415     {
3416       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3417
3418       if (rsym->isitmp)
3419         {
3420           if (rsym && rsym->regType == REG_CND)
3421             rsym = NULL;
3422           if (rsym && (rsym->accuse || rsym->ruonly))
3423             rsym = NULL;
3424           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3425             rsym = rsym->usl.spillLoc;
3426         }
3427
3428       /* If the RECEIVE operand immediately spills to the first entry on the */
3429       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3430       /* rather than the usual @r0/r1 machinations. */
3431       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3432         {
3433           int ofs;
3434
3435           _G.current_iCode = ric;
3436           D(emitcode (";     genReceive",""));
3437           for (ofs=0; ofs < sym->recvSize; ofs++)
3438             {
3439               if (!strcmp (fReturn[ofs], "a"))
3440                 emitcode ("push", "acc");
3441               else
3442                 emitcode ("push", fReturn[ofs]);
3443             }
3444           stackAdjust -= sym->recvSize;
3445           if (stackAdjust<0)
3446             {
3447               assert (stackAdjust>=0);
3448               stackAdjust = 0;
3449             }
3450           _G.current_iCode = ic;
3451           ric->generated = 1;
3452           accIsFree = 1;
3453         }
3454       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3455       /* to free up the accumulator. */
3456       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3457         {
3458           int ofs;
3459
3460           _G.current_iCode = ric;
3461           D(emitcode (";     genReceive",""));
3462           for (ofs=0; ofs < sym->recvSize; ofs++)
3463             {
3464               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3465             }
3466           _G.current_iCode = ic;
3467           ric->generated = 1;
3468           accIsFree = 1;
3469         }
3470     }
3471
3472   /* adjust the stack for the function */
3473   if (stackAdjust)
3474     {
3475       int i = stackAdjust;
3476       if (i > 256)
3477         werror (W_STACK_OVERFLOW, sym->name);
3478
3479       if (i > 3 && accIsFree)
3480         {
3481           emitcode ("mov", "a,sp");
3482           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3483           emitcode ("mov", "sp,a");
3484         }
3485       else if (i > 5)
3486         {
3487           /* The accumulator is not free, so we will need another register */
3488           /* to clobber. No need to worry about a possible conflict with */
3489           /* the above early RECEIVE optimizations since they would have */
3490           /* freed the accumulator if they were generated. */
3491
3492           if (IFFUNC_CALLEESAVES(sym->type))
3493             {
3494               /* if it's a callee-saves function we need a saved register */
3495               if (calleesaves_saved_register >= 0)
3496                 {
3497                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3498                   emitcode ("mov", "a,sp");
3499                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3500                   emitcode ("mov", "sp,a");
3501                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3502                 }
3503               else
3504                 /* do it the hard way */
3505                 while (i--)
3506                   emitcode ("inc", "sp");
3507             }
3508           else
3509             {
3510               /* not callee-saves, we can clobber r0 */
3511               emitcode ("mov", "r0,a");
3512               emitcode ("mov", "a,sp");
3513               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3514               emitcode ("mov", "sp,a");
3515               emitcode ("mov", "a,r0");
3516             }
3517         }
3518       else
3519         while (i--)
3520           emitcode ("inc", "sp");
3521     }
3522
3523   if (sym->xstack)
3524     {
3525       char i = ((char) sym->xstack & 0xff);
3526
3527       if (i > 3 && accIsFree)
3528         {
3529           emitcode ("mov", "a,_spx");
3530           emitcode ("add", "a,#0x%02x", i);
3531           emitcode ("mov", "_spx,a");
3532         }
3533       else if (i > 5)
3534         {
3535           emitcode ("push", "acc");
3536           emitcode ("mov", "a,_spx");
3537           emitcode ("add", "a,#0x%02x", i);
3538           emitcode ("mov", "_spx,a");
3539           emitcode ("pop", "acc");
3540         }
3541       else
3542         {
3543           while (i--)
3544             emitcode ("inc", "_spx");
3545         }
3546     }
3547
3548   /* if critical function then turn interrupts off */
3549   if (IFFUNC_ISCRITICAL (ftype))
3550     {
3551       symbol *tlbl = newiTempLabel (NULL);
3552       emitcode ("setb", "c");
3553       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3554       emitcode ("clr", "c");
3555       emitcode ("", "%05d$:", (tlbl->key + 100));
3556       emitcode ("push", "psw"); /* save old ea via c in psw */
3557     }
3558 }
3559
3560 /*-----------------------------------------------------------------*/
3561 /* genEndFunction - generates epilogue for functions               */
3562 /*-----------------------------------------------------------------*/
3563 static void
3564 genEndFunction (iCode * ic)
3565 {
3566   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3567   lineNode *lnp = lineCurr;
3568   bitVect  *regsUsed;
3569   bitVect  *regsUsedPrologue;
3570   bitVect  *regsUnneeded;
3571   int      idx;
3572
3573   _G.currentFunc = NULL;
3574   if (IFFUNC_ISNAKED(sym->type))
3575   {
3576       emitcode(";", "naked function: no epilogue.");
3577       if (options.debug && currFunc)
3578         debugFile->writeEndFunction (currFunc, ic, 0);
3579       return;
3580   }
3581
3582   if (IFFUNC_ISCRITICAL (sym->type))
3583     {
3584       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3585         {
3586           emitcode ("rlc", "a");   /* save c in a */
3587           emitcode ("pop", "psw"); /* restore ea via c in psw */
3588           emitcode ("mov", "ea,c");
3589           emitcode ("rrc", "a");   /* restore c from a */
3590         }
3591       else
3592         {
3593           emitcode ("pop", "psw"); /* restore ea via c in psw */
3594           emitcode ("mov", "ea,c");
3595         }
3596     }
3597
3598   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3599     {
3600       if (options.useXstack)
3601         {
3602           if (sym->stack)
3603             {
3604               emitcode ("mov", "sp,_bp");
3605               emitcode ("pop", "_bp");
3606             }
3607           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3608             {
3609               emitcode ("xch", "a,_bpx");
3610               emitcode ("mov", "r0,a");
3611               emitcode ("dec", "r0");
3612               emitcode ("movx", "a,@r0");
3613               emitcode ("xch", "a,_bpx");
3614               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3615             }
3616         }
3617       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3618         {
3619           emitcode ("mov", "sp,_bp");
3620           emitcode ("pop", "_bp");
3621         }
3622     }
3623
3624   /* restore the register bank  */
3625   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3626   {
3627     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3628      || !options.useXstack)
3629     {
3630         /* Special case of ISR using non-zero bank with useXstack
3631          * is handled below.
3632          */
3633         emitcode ("pop", "psw");
3634     }
3635   }
3636
3637   if (IFFUNC_ISISR (sym->type))
3638     {
3639
3640       /* now we need to restore the registers */
3641       /* if this isr has no bank i.e. is going to
3642          run with bank 0 , then we need to save more
3643          registers :-) */
3644       if (!FUNC_REGBANK (sym->type))
3645         {
3646           /* if this function does not call any other
3647              function then we can be economical and
3648              save only those registers that are used */
3649           if (!IFFUNC_HASFCALL(sym->type))
3650             {
3651               int i;
3652
3653               /* if any registers used */
3654               if (sym->regsUsed)
3655                 {
3656                   bool bits_popped = FALSE;
3657                   /* save the registers used */
3658                   for (i = sym->regsUsed->size; i >= 0; i--)
3659                     {
3660                       if (bitVectBitValue (sym->regsUsed, i))
3661                         bits_popped = popReg (i, bits_popped);
3662                     }
3663                 }
3664             }
3665           else
3666             {
3667               if (options.parms_in_bank1) {
3668                   int i;
3669                   for (i = 7 ; i >= 0 ; i-- ) {
3670                       emitcode ("pop","%s",rb1regs[i]);
3671                   }
3672               }
3673               /* this function has  a function call cannot
3674                  determines register usage so we will have to pop the
3675                  entire bank */
3676               unsaveRBank (0, ic, FALSE);
3677             }
3678         }
3679         else
3680         {
3681             /* This ISR uses a non-zero bank.
3682              *
3683              * Restore any register banks saved by genFunction
3684              * in reverse order.
3685              */
3686             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3687             int ix;
3688
3689             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3690             {
3691                 if (savedBanks & (1 << ix))
3692                 {
3693                     unsaveRBank(ix, NULL, FALSE);
3694                 }
3695             }
3696
3697             if (options.useXstack)
3698             {
3699                 /* Restore bank AFTER calling unsaveRBank,
3700                  * since it can trash r0.
3701                  */
3702                 emitcode ("pop", "psw");
3703             }
3704         }
3705
3706       if (!inExcludeList ("dph"))
3707         emitcode ("pop", "dph");
3708       if (!inExcludeList ("dpl"))
3709         emitcode ("pop", "dpl");
3710       if (!inExcludeList ("b"))
3711         emitcode ("pop", "b");
3712       if (!inExcludeList ("acc"))
3713         emitcode ("pop", "acc");
3714
3715       /* if debug then send end of function */
3716       if (options.debug && currFunc)
3717         {
3718           debugFile->writeEndFunction (currFunc, ic, 1);
3719         }
3720
3721       emitcode ("reti", "");
3722     }
3723   else
3724     {
3725       if (IFFUNC_CALLEESAVES(sym->type))
3726         {
3727           int i;
3728
3729           /* if any registers used */
3730           if (sym->regsUsed)
3731             {
3732               /* save the registers used */
3733               for (i = sym->regsUsed->size; i >= 0; i--)
3734                 {
3735                   if (bitVectBitValue (sym->regsUsed, i) ||
3736                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3737                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3738                 }
3739             }
3740           else if (mcs51_ptrRegReq)
3741             {
3742               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3743               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3744             }
3745
3746         }
3747
3748       /* if debug then send end of function */
3749       if (options.debug && currFunc)
3750         {
3751           debugFile->writeEndFunction (currFunc, ic, 1);
3752         }
3753
3754       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3755         {
3756           emitcode ("ljmp", "__sdcc_banked_ret");
3757         }
3758       else
3759         {
3760           emitcode ("ret", "");
3761         }
3762     }
3763
3764   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3765     return;
3766
3767   /* If this was an interrupt handler using bank 0 that called another */
3768   /* function, then all registers must be saved; nothing to optimized. */
3769   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3770       && !FUNC_REGBANK(sym->type))
3771     return;
3772
3773   /* There are no push/pops to optimize if not callee-saves or ISR */
3774   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3775     return;
3776
3777   /* If there were stack parameters, we cannot optimize without also    */
3778   /* fixing all of the stack offsets; this is too dificult to consider. */
3779   if (FUNC_HASSTACKPARM(sym->type))
3780     return;
3781
3782   /* Compute the registers actually used */
3783   regsUsed = newBitVect (mcs51_nRegs);
3784   regsUsedPrologue = newBitVect (mcs51_nRegs);
3785   while (lnp)
3786     {
3787       if (lnp->ic && lnp->ic->op == FUNCTION)
3788         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3789       else
3790         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3791
3792       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3793           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3794         break;
3795       if (!lnp->prev)
3796         break;
3797       lnp = lnp->prev;
3798     }
3799
3800   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3801       && !bitVectBitValue (regsUsed, CND_IDX))
3802     {
3803       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3804       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3805           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3806         bitVectUnSetBit (regsUsed, CND_IDX);
3807     }
3808   else
3809     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3810
3811   /* If this was an interrupt handler that called another function */
3812   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3813   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3814     {
3815       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3816       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3817       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3818       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3819       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3820     }
3821
3822   /* Remove the unneeded push/pops */
3823   regsUnneeded = newBitVect (mcs51_nRegs);
3824   while (lnp)
3825     {
3826       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3827         {
3828           if (!strncmp(lnp->line, "push", 4))
3829             {
3830               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3831               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3832                 {
3833                   connectLine (lnp->prev, lnp->next);
3834                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3835                 }
3836             }
3837           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3838             {
3839               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3840               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3841                 {
3842                   connectLine (lnp->prev, lnp->next);
3843                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3844                 }
3845             }
3846         }
3847       lnp = lnp->next;
3848     }
3849
3850   for (idx = 0; idx < regsUnneeded->size; idx++)
3851     if (bitVectBitValue (regsUnneeded, idx))
3852       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3853
3854   freeBitVect (regsUnneeded);
3855   freeBitVect (regsUsed);
3856   freeBitVect (regsUsedPrologue);
3857 }
3858
3859 /*-----------------------------------------------------------------*/
3860 /* genRet - generate code for return statement                     */
3861 /*-----------------------------------------------------------------*/
3862 static void
3863 genRet (iCode * ic)
3864 {
3865   int size, offset = 0, pushed = 0;
3866
3867   D(emitcode (";     genRet",""));
3868
3869   /* if we have no return value then
3870      just generate the "ret" */
3871   if (!IC_LEFT (ic))
3872     goto jumpret;
3873
3874   /* we have something to return then
3875      move the return value into place */
3876   aopOp (IC_LEFT (ic), ic, FALSE);
3877   size = AOP_SIZE (IC_LEFT (ic));
3878
3879
3880   if (IS_BIT(_G.currentFunc->etype))
3881     {
3882       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3883       size = 0;
3884     }
3885
3886   while (size--)
3887     {
3888       char *l;
3889       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3890         {
3891           /* #NOCHANGE */
3892           l = aopGet (IC_LEFT (ic), offset++,
3893                       FALSE, TRUE);
3894           emitcode ("push", "%s", l);
3895           pushed++;
3896         }
3897       else
3898         {
3899           l = aopGet (IC_LEFT (ic), offset,
3900                       FALSE, FALSE);
3901           if (strcmp (fReturn[offset], l))
3902             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3903         }
3904     }
3905
3906   while (pushed)
3907     {
3908       pushed--;
3909       if (strcmp (fReturn[pushed], "a"))
3910         emitcode ("pop", fReturn[pushed]);
3911       else
3912         emitcode ("pop", "acc");
3913     }
3914   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3915
3916 jumpret:
3917   /* generate a jump to the return label
3918      if the next is not the return statement */
3919   if (!(ic->next && ic->next->op == LABEL &&
3920         IC_LABEL (ic->next) == returnLabel))
3921
3922     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3923
3924 }
3925
3926 /*-----------------------------------------------------------------*/
3927 /* genLabel - generates a label                                    */
3928 /*-----------------------------------------------------------------*/
3929 static void
3930 genLabel (iCode * ic)
3931 {
3932   /* special case never generate */
3933   if (IC_LABEL (ic) == entryLabel)
3934     return;
3935
3936   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3937 }
3938
3939 /*-----------------------------------------------------------------*/
3940 /* genGoto - generates a ljmp                                      */
3941 /*-----------------------------------------------------------------*/
3942 static void
3943 genGoto (iCode * ic)
3944 {
3945   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3946 }
3947
3948 /*-----------------------------------------------------------------*/
3949 /* findLabelBackwards: walks back through the iCode chain looking  */
3950 /* for the given label. Returns number of iCode instructions     */
3951 /* between that label and given ic.          */
3952 /* Returns zero if label not found.          */
3953 /*-----------------------------------------------------------------*/
3954 static int
3955 findLabelBackwards (iCode * ic, int key)
3956 {
3957   int count = 0;
3958
3959   while (ic->prev)
3960     {
3961       ic = ic->prev;
3962       count++;
3963
3964       /* If we have any pushes or pops, we cannot predict the distance.
3965          I don't like this at all, this should be dealt with in the
3966          back-end */
3967       if (ic->op == IPUSH || ic->op == IPOP) {
3968         return 0;
3969       }
3970
3971       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3972         {
3973           return count;
3974         }
3975     }
3976
3977   return 0;
3978 }
3979
3980 /*-----------------------------------------------------------------*/
3981 /* genPlusIncr :- does addition with increment if possible         */
3982 /*-----------------------------------------------------------------*/
3983 static bool
3984 genPlusIncr (iCode * ic)
3985 {
3986   unsigned int icount;
3987   unsigned int size = getDataSize (IC_RESULT (ic));
3988
3989   /* will try to generate an increment */
3990   /* if the right side is not a literal
3991      we cannot */
3992   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3993     return FALSE;
3994
3995   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3996
3997   D(emitcode (";     genPlusIncr",""));
3998
3999   /* if increment >=16 bits in register or direct space */
4000   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
4001       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4002       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4003       (size > 1) &&
4004       (icount == 1))
4005     {
4006       symbol *tlbl;
4007       int emitTlbl;
4008       int labelRange;
4009
4010       /* If the next instruction is a goto and the goto target
4011        * is < 10 instructions previous to this, we can generate
4012        * jumps straight to that target.
4013        */
4014       if (ic->next && ic->next->op == GOTO
4015           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4016           && labelRange <= 10)
4017         {
4018           emitcode (";", "tail increment optimized");
4019           tlbl = IC_LABEL (ic->next);
4020           emitTlbl = 0;
4021         }
4022       else
4023         {
4024           tlbl = newiTempLabel (NULL);
4025           emitTlbl = 1;
4026         }
4027       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4028       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4029           IS_AOP_PREG (IC_RESULT (ic)))
4030         emitcode ("cjne", "%s,#0x00,%05d$",
4031                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4032                   tlbl->key + 100);
4033       else
4034         {
4035           emitcode ("clr", "a");
4036           emitcode ("cjne", "a,%s,%05d$",
4037                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4038                     tlbl->key + 100);
4039         }
4040
4041       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4042       if (size > 2)
4043         {
4044           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4045               IS_AOP_PREG (IC_RESULT (ic)))
4046             emitcode ("cjne", "%s,#0x00,%05d$",
4047                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4048                       tlbl->key + 100);
4049           else
4050             emitcode ("cjne", "a,%s,%05d$",
4051                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4052                       tlbl->key + 100);
4053
4054           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4055         }
4056       if (size > 3)
4057         {
4058           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4059               IS_AOP_PREG (IC_RESULT (ic)))
4060             emitcode ("cjne", "%s,#0x00,%05d$",
4061                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4062                       tlbl->key + 100);
4063           else
4064             {
4065               emitcode ("cjne", "a,%s,%05d$",
4066                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4067                         tlbl->key + 100);
4068             }
4069           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4070         }
4071
4072       if (emitTlbl)
4073         {
4074           emitcode ("", "%05d$:", tlbl->key + 100);
4075         }
4076       return TRUE;
4077     }
4078
4079   /* if result is dptr */
4080   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4081       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4082       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4083       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4084     {
4085       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4086         return FALSE;
4087
4088       if (icount > 9)
4089         return FALSE;
4090
4091       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4092         return FALSE;
4093
4094       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
4095       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
4096       while (icount--)
4097         emitcode ("inc", "dptr");
4098
4099       return TRUE;
4100     }
4101
4102   /* if the literal value of the right hand side
4103      is greater than 4 then it is not worth it */
4104   if (icount > 4)
4105     return FALSE;
4106
4107   /* if the sizes are greater than 1 then we cannot */
4108   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4109       AOP_SIZE (IC_LEFT (ic)) > 1)
4110     return FALSE;
4111
4112   /* we can if the aops of the left & result match or
4113      if they are in registers and the registers are the
4114      same */
4115   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4116     {
4117
4118       if (icount > 3)
4119         {
4120           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4121           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4122           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4123         }
4124       else
4125         {
4126
4127           while (icount--)
4128             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4129         }
4130
4131       return TRUE;
4132     }
4133
4134   return FALSE;
4135 }
4136
4137 /*-----------------------------------------------------------------*/
4138 /* outBitAcc - output a bit in acc                                 */
4139 /*-----------------------------------------------------------------*/
4140 static void
4141 outBitAcc (operand * result)
4142 {
4143   symbol *tlbl = newiTempLabel (NULL);
4144   /* if the result is a bit */
4145   if (AOP_TYPE (result) == AOP_CRY)
4146     {
4147       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4148     }
4149   else
4150     {
4151       emitcode ("jz", "%05d$", tlbl->key + 100);
4152       emitcode ("mov", "a,%s", one);
4153       emitcode ("", "%05d$:", tlbl->key + 100);
4154       outAcc (result);
4155     }
4156 }
4157
4158 /*-----------------------------------------------------------------*/
4159 /* genPlusBits - generates code for addition of two bits           */
4160 /*-----------------------------------------------------------------*/
4161 static void
4162 genPlusBits (iCode * ic)
4163 {
4164   D(emitcode (";     genPlusBits",""));
4165
4166   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4167     {
4168       symbol *lbl = newiTempLabel (NULL);
4169       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4170       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4171       emitcode ("cpl", "c");
4172       emitcode ("", "%05d$:", (lbl->key + 100));
4173       outBitC (IC_RESULT (ic));
4174     }
4175   else
4176     {
4177       emitcode ("clr", "a");
4178       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4179       emitcode ("rlc", "a");
4180       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4181       emitcode ("addc", "a,#0x00");
4182       outAcc (IC_RESULT (ic));
4183     }
4184 }
4185
4186 #if 0
4187 /* This is the original version of this code.
4188
4189  * This is being kept around for reference,
4190  * because I am not entirely sure I got it right...
4191  */
4192 static void
4193 adjustArithmeticResult (iCode * ic)
4194 {
4195   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4196       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4197       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4198     aopPut (IC_RESULT (ic),
4199             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4200             2,
4201             isOperandVolatile (IC_RESULT (ic), FALSE));
4202
4203   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4204       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4205       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4206     aopPut (IC_RESULT (ic),
4207             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4208             2,
4209             isOperandVolatile (IC_RESULT (ic), FALSE));
4210
4211   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4212       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4213       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4214       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4215       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4216     {
4217       char buffer[5];
4218       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4219       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
4220     }
4221 }
4222 #else
4223 /* This is the pure and virtuous version of this code.
4224  * I'm pretty certain it's right, but not enough to toss the old
4225  * code just yet...
4226  */
4227 static void
4228 adjustArithmeticResult (iCode * ic)
4229 {
4230   if (opIsGptr (IC_RESULT (ic)) &&
4231       opIsGptr (IC_LEFT (ic)) &&
4232       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4233     {
4234       aopPut (IC_RESULT (ic),
4235               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4236               GPTRSIZE - 1,
4237               isOperandVolatile (IC_RESULT (ic), FALSE));
4238     }
4239
4240   if (opIsGptr (IC_RESULT (ic)) &&
4241       opIsGptr (IC_RIGHT (ic)) &&
4242       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4243     {
4244       aopPut (IC_RESULT (ic),
4245               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4246               GPTRSIZE - 1,
4247               isOperandVolatile (IC_RESULT (ic), FALSE));
4248     }
4249
4250   if (opIsGptr (IC_RESULT (ic)) &&
4251       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4252       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4253       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4254       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4255     {
4256       char buffer[5];
4257       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4258       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4259     }
4260 }
4261 #endif
4262
4263 /*-----------------------------------------------------------------*/
4264 /* genPlus - generates code for addition                           */
4265 /*-----------------------------------------------------------------*/
4266 static void
4267 genPlus (iCode * ic)
4268 {
4269   int size, offset = 0;
4270   int skip_bytes = 0;
4271   char *add = "add";
4272   bool swappedLR = FALSE;
4273   operand *leftOp, *rightOp;
4274   operand * op;
4275
4276   /* special cases :- */
4277
4278   D(emitcode (";     genPlus",""));
4279
4280   aopOp (IC_LEFT (ic), ic, FALSE);
4281   aopOp (IC_RIGHT (ic), ic, FALSE);
4282   aopOp (IC_RESULT (ic), ic, TRUE);
4283
4284   /* if literal, literal on the right or
4285      if left requires ACC or right is already
4286      in ACC */
4287   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4288       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4289       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4290     {
4291       operand *t = IC_RIGHT (ic);
4292       IC_RIGHT (ic) = IC_LEFT (ic);
4293       IC_LEFT (ic) = t;
4294           swappedLR = TRUE;
4295     }
4296
4297   /* if both left & right are in bit
4298      space */
4299   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4300       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4301     {
4302       genPlusBits (ic);
4303       goto release;
4304     }
4305
4306   /* if left in bit space & right literal */
4307   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4308       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4309     {
4310       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4311       /* if result in bit space */
4312       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4313         {
4314           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4315             emitcode ("cpl", "c");
4316           outBitC (IC_RESULT (ic));
4317         }
4318       else
4319         {
4320           size = getDataSize (IC_RESULT (ic));
4321           while (size--)
4322             {
4323               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4324               emitcode ("addc", "a,#00");
4325               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4326             }
4327         }
4328       goto release;
4329     }
4330
4331   /* if I can do an increment instead
4332      of add then GOOD for ME */
4333   if (genPlusIncr (ic) == TRUE)
4334     goto release;
4335
4336   size = getDataSize (IC_RESULT (ic));
4337   leftOp = IC_LEFT(ic);
4338   rightOp = IC_RIGHT(ic);
4339   op = IC_LEFT(ic);
4340
4341   /* if this is an add for an array access
4342      at a 256 byte boundary */
4343   if ( 2 == size
4344        && AOP_TYPE (op) == AOP_IMMD
4345        && IS_SYMOP (op)
4346        && IS_SPEC (OP_SYM_ETYPE (op))
4347        && SPEC_ABSA (OP_SYM_ETYPE (op))
4348        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4349      )
4350     {
4351       D(emitcode (";     genPlus aligned array",""));
4352       aopPut (IC_RESULT (ic),
4353               aopGet (rightOp, 0, FALSE, FALSE),
4354               0,
4355               isOperandVolatile (IC_RESULT (ic), FALSE));
4356
4357       if( 1 == getDataSize (IC_RIGHT (ic)) )
4358         {
4359           aopPut (IC_RESULT (ic),
4360                   aopGet (leftOp, 1, FALSE, FALSE),
4361                   1,
4362                   isOperandVolatile (IC_RESULT (ic), FALSE));
4363         }
4364       else
4365         {
4366           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4367           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4368           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4369         }
4370       goto release;
4371     }
4372
4373   /* if the lower bytes of a literal are zero skip the addition */
4374   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4375     {
4376        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4377               (skip_bytes+1 < size))
4378          {
4379            skip_bytes++;
4380          }
4381        if (skip_bytes)
4382          D(emitcode (";     genPlus shortcut",""));
4383     }
4384
4385   while (size--)
4386     {
4387       if( offset >= skip_bytes )
4388         {
4389           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4390             {
4391               bool pushedB;
4392               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4393               pushedB = pushB ();
4394               emitcode("xch", "a,b");
4395               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4396               emitcode (add, "a,b");
4397               popB (pushedB);
4398             }
4399           else if (aopGetUsesAcc (leftOp, offset))
4400             {
4401               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4402               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4403             }
4404           else
4405             {
4406               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4407               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4408             }
4409           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4410           add = "addc";  /* further adds must propagate carry */
4411         }
4412       else
4413         {
4414           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4415               isOperandVolatile (IC_RESULT (ic), FALSE))
4416             {
4417               /* just move */
4418               aopPut (IC_RESULT (ic),
4419                       aopGet (leftOp, offset, FALSE, FALSE),
4420                       offset,
4421                       isOperandVolatile (IC_RESULT (ic), FALSE));
4422             }
4423         }
4424       offset++;
4425     }
4426
4427   adjustArithmeticResult (ic);
4428
4429 release:
4430   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4431   if (!swappedLR)
4432     {
4433       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4434       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4435     }
4436   else
4437     {
4438       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4439       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4440     }
4441 }
4442
4443 /*-----------------------------------------------------------------*/
4444 /* genMinusDec :- does subtraction with decrement if possible      */
4445 /*-----------------------------------------------------------------*/
4446 static bool
4447 genMinusDec (iCode * ic)
4448 {
4449   unsigned int icount;
4450   unsigned int size = getDataSize (IC_RESULT (ic));
4451
4452   /* will try to generate an increment */
4453   /* if the right side is not a literal
4454      we cannot */
4455   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4456     return FALSE;
4457
4458   /* if the literal value of the right hand side
4459      is greater than 4 then it is not worth it */
4460   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4461     return FALSE;
4462
4463   D(emitcode (";     genMinusDec",""));
4464
4465   /* if decrement >=16 bits in register or direct space */
4466   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
4467       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4468       (size > 1) &&
4469       (icount == 1))
4470     {
4471       symbol *tlbl;
4472       int emitTlbl;
4473       int labelRange;
4474
4475       /* If the next instruction is a goto and the goto target
4476        * is <= 10 instructions previous to this, we can generate
4477        * jumps straight to that target.
4478        */
4479       if (ic->next && ic->next->op == GOTO
4480           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4481           && labelRange <= 10)
4482         {
4483           emitcode (";", "tail decrement optimized");
4484           tlbl = IC_LABEL (ic->next);
4485           emitTlbl = 0;
4486         }
4487       else
4488         {
4489           tlbl = newiTempLabel (NULL);
4490           emitTlbl = 1;
4491         }
4492
4493       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4494       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4495           IS_AOP_PREG (IC_RESULT (ic)))
4496         emitcode ("cjne", "%s,#0xff,%05d$"
4497                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4498                   ,tlbl->key + 100);
4499       else
4500         {
4501           emitcode ("mov", "a,#0xff");
4502           emitcode ("cjne", "a,%s,%05d$"
4503                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4504                     ,tlbl->key + 100);
4505         }
4506       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4507       if (size > 2)
4508         {
4509           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4510               IS_AOP_PREG (IC_RESULT (ic)))
4511             emitcode ("cjne", "%s,#0xff,%05d$"
4512                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4513                       ,tlbl->key + 100);
4514           else
4515             {
4516               emitcode ("cjne", "a,%s,%05d$"
4517                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4518                         ,tlbl->key + 100);
4519             }
4520           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4521         }
4522       if (size > 3)
4523         {
4524           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4525               IS_AOP_PREG (IC_RESULT (ic)))
4526             emitcode ("cjne", "%s,#0xff,%05d$"
4527                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4528                       ,tlbl->key + 100);
4529           else
4530             {
4531               emitcode ("cjne", "a,%s,%05d$"
4532                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4533                         ,tlbl->key + 100);
4534             }
4535           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4536         }
4537       if (emitTlbl)
4538         {
4539           emitcode ("", "%05d$:", tlbl->key + 100);
4540         }
4541       return TRUE;
4542     }
4543
4544   /* if the sizes are greater than 1 then we cannot */
4545   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4546       AOP_SIZE (IC_LEFT (ic)) > 1)
4547     return FALSE;
4548
4549   /* we can if the aops of the left & result match or
4550      if they are in registers and the registers are the
4551      same */
4552   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4553     {
4554       char *l;
4555
4556       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4557         {
4558           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4559           l = "a";
4560         }
4561       else
4562         {
4563           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4564         }
4565
4566       while (icount--)
4567         emitcode ("dec", "%s", l);
4568
4569       if (AOP_NEEDSACC (IC_RESULT (ic)))
4570         aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4571
4572       return TRUE;
4573     }
4574
4575   return FALSE;
4576 }
4577
4578 /*-----------------------------------------------------------------*/
4579 /* addSign - complete with sign                                    */
4580 /*-----------------------------------------------------------------*/
4581 static void
4582 addSign (operand * result, int offset, int sign)
4583 {
4584   int size = (getDataSize (result) - offset);
4585   if (size > 0)
4586     {
4587       if (sign)
4588         {
4589           emitcode ("rlc", "a");
4590           emitcode ("subb", "a,acc");
4591           while (size--)
4592             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4593         }
4594       else
4595         while (size--)
4596           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4597     }
4598 }
4599
4600 /*-----------------------------------------------------------------*/
4601 /* genMinusBits - generates code for subtraction  of two bits      */
4602 /*-----------------------------------------------------------------*/
4603 static void
4604 genMinusBits (iCode * ic)
4605 {
4606   symbol *lbl = newiTempLabel (NULL);
4607
4608   D(emitcode (";     genMinusBits",""));
4609
4610   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4611     {
4612       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4613       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4614       emitcode ("cpl", "c");
4615       emitcode ("", "%05d$:", (lbl->key + 100));
4616       outBitC (IC_RESULT (ic));
4617     }
4618   else
4619     {
4620       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4621       emitcode ("subb", "a,acc");
4622       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4623       emitcode ("inc", "a");
4624       emitcode ("", "%05d$:", (lbl->key + 100));
4625       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4626       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4627     }
4628 }
4629
4630 /*-----------------------------------------------------------------*/
4631 /* genMinus - generates code for subtraction                       */
4632 /*-----------------------------------------------------------------*/
4633 static void
4634 genMinus (iCode * ic)
4635 {
4636   int size, offset = 0;
4637
4638   D(emitcode (";     genMinus",""));
4639
4640   aopOp (IC_LEFT (ic), ic, FALSE);
4641   aopOp (IC_RIGHT (ic), ic, FALSE);
4642   aopOp (IC_RESULT (ic), ic, TRUE);
4643
4644   /* special cases :- */
4645   /* if both left & right are in bit space */
4646   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4647       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4648     {
4649       genMinusBits (ic);
4650       goto release;
4651     }
4652
4653   /* if I can do an decrement instead
4654      of subtract then GOOD for ME */
4655   if (genMinusDec (ic) == TRUE)
4656     goto release;
4657
4658   size = getDataSize (IC_RESULT (ic));
4659
4660   /* if literal, add a,#-lit, else normal subb */
4661   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4662     {
4663       unsigned long lit = 0L;
4664       bool useCarry = FALSE;
4665
4666       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4667       lit = -(long) lit;
4668
4669       while (size--)
4670         {
4671           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4672             {
4673             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4674               if (!offset && !size && lit== (unsigned long) -1)
4675                 {
4676                   emitcode ("dec", "a");
4677                 }
4678               else if (!useCarry)
4679                 {
4680                   /* first add without previous c */
4681                   emitcode ("add", "a,#0x%02x",
4682                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4683                   useCarry = TRUE;
4684                 }
4685               else
4686                 {
4687                   emitcode ("addc", "a,#0x%02x",
4688                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4689                 }
4690               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4691             }
4692           else
4693             {
4694               /* no need to add zeroes */
4695               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4696                 {
4697                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4698                           offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4699                 }
4700               offset++;
4701             }
4702         }
4703     }
4704   else
4705     {
4706       operand *leftOp, *rightOp;
4707
4708       leftOp = IC_LEFT(ic);
4709       rightOp = IC_RIGHT(ic);
4710
4711       while (size--)
4712         {
4713           if (aopGetUsesAcc(rightOp, offset)) {
4714             if (aopGetUsesAcc(leftOp, offset)) {
4715               bool pushedB;
4716
4717               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4718               pushedB = pushB ();
4719               emitcode ("mov", "b,a");
4720               if (offset == 0)
4721                 CLRC;
4722               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4723               emitcode ("subb", "a,b");
4724               popB (pushedB);
4725             } else {
4726               /* reverse subtraction with 2's complement */
4727               if (offset == 0)
4728                 emitcode( "setb", "c");
4729                else
4730                 emitcode( "cpl", "c");
4731               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4732               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4733               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4734               emitcode("cpl", "a");
4735               if (size) /* skip if last byte */
4736                 emitcode( "cpl", "c");
4737             }
4738           } else {
4739             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4740             if (offset == 0)
4741               CLRC;
4742             emitcode ("subb", "a,%s",
4743                       aopGet(rightOp, offset, FALSE, TRUE));
4744           }
4745
4746           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4747         }
4748     }
4749
4750
4751   adjustArithmeticResult (ic);
4752
4753 release:
4754   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4755   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4756   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4757 }
4758
4759
4760 /*-----------------------------------------------------------------*/
4761 /* genMultbits :- multiplication of bits                           */
4762 /*-----------------------------------------------------------------*/
4763 static void
4764 genMultbits (operand * left,
4765              operand * right,
4766              operand * result)
4767 {
4768   D(emitcode (";     genMultbits",""));
4769
4770   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4771   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4772   outBitC (result);
4773 }
4774
4775 /*-----------------------------------------------------------------*/
4776 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4777 /*-----------------------------------------------------------------*/
4778 static void
4779 genMultOneByte (operand * left,
4780                 operand * right,
4781                 operand * result)
4782 {
4783   symbol *lbl;
4784   int size = AOP_SIZE (result);
4785   bool runtimeSign, compiletimeSign;
4786   bool lUnsigned, rUnsigned, pushedB;
4787
4788   D(emitcode (";     genMultOneByte",""));
4789
4790   if (size < 1 || size > 2)
4791     {
4792       /* this should never happen */
4793       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4794                AOP_SIZE(result), __FILE__, lineno);
4795       exit (1);
4796     }
4797
4798   /* (if two literals: the value is computed before) */
4799   /* if one literal, literal on the right */
4800   if (AOP_TYPE (left) == AOP_LIT)
4801     {
4802       operand *t = right;
4803       right = left;
4804       left = t;
4805       /* emitcode (";", "swapped left and right"); */
4806     }
4807   /* if no literal, unsigned on the right: shorter code */
4808   if (   AOP_TYPE (right) != AOP_LIT
4809       && SPEC_USIGN (getSpec (operandType (left))))
4810     {
4811       operand *t = right;
4812       right = left;
4813       left = t;
4814     }
4815
4816   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4817   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4818
4819   pushedB = pushB ();
4820
4821   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4822                    no need to take care about the signedness! */
4823       || (lUnsigned && rUnsigned))
4824     {
4825       /* just an unsigned 8 * 8 = 8 multiply
4826          or 8u * 8u = 16u */
4827       /* emitcode (";","unsigned"); */
4828       /* TODO: check for accumulator clash between left & right aops? */
4829
4830       if (AOP_TYPE (right) == AOP_LIT)
4831         {
4832           /* moving to accumulator first helps peepholes */
4833           MOVA (aopGet (left, 0, FALSE, FALSE));
4834           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4835         }
4836       else
4837         {
4838           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4839           MOVA (aopGet (left, 0, FALSE, FALSE));
4840         }
4841
4842       emitcode ("mul", "ab");
4843       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4844       if (size == 2)
4845         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4846
4847       popB (pushedB);
4848       return;
4849     }
4850
4851   /* we have to do a signed multiply */
4852   /* emitcode (";", "signed"); */
4853
4854   /* now sign adjust for both left & right */
4855
4856   /* let's see what's needed: */
4857   /* apply negative sign during runtime */
4858   runtimeSign = FALSE;
4859   /* negative sign from literals */
4860   compiletimeSign = FALSE;
4861
4862   if (!lUnsigned)
4863     {
4864       if (AOP_TYPE(left) == AOP_LIT)
4865         {
4866           /* signed literal */
4867           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4868           if (val < 0)
4869             compiletimeSign = TRUE;
4870         }
4871       else
4872         /* signed but not literal */
4873         runtimeSign = TRUE;
4874     }
4875
4876   if (!rUnsigned)
4877     {
4878       if (AOP_TYPE(right) == AOP_LIT)
4879         {
4880           /* signed literal */
4881           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4882           if (val < 0)
4883             compiletimeSign ^= TRUE;
4884         }
4885       else
4886         /* signed but not literal */
4887         runtimeSign = TRUE;
4888     }
4889
4890   /* initialize F0, which stores the runtime sign */
4891   if (runtimeSign)
4892     {
4893       if (compiletimeSign)
4894         emitcode ("setb", "F0"); /* set sign flag */
4895       else
4896         emitcode ("clr", "F0"); /* reset sign flag */
4897     }
4898
4899   /* save the signs of the operands */
4900   if (AOP_TYPE(right) == AOP_LIT)
4901     {
4902       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4903
4904       if (!rUnsigned && val < 0)
4905         emitcode ("mov", "b,#0x%02x", -val);
4906       else
4907         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4908     }
4909   else /* ! literal */
4910     {
4911       if (rUnsigned)  /* emitcode (";", "signed"); */
4912
4913         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4914       else
4915         {
4916           MOVA (aopGet (right, 0, FALSE, FALSE));
4917           lbl = newiTempLabel (NULL);
4918           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4919           emitcode ("cpl", "F0"); /* complement sign flag */
4920           emitcode ("cpl", "a");  /* 2's complement */
4921           emitcode ("inc", "a");
4922           emitcode ("", "%05d$:", (lbl->key + 100));
4923           emitcode ("mov", "b,a");
4924         }
4925     }
4926
4927   if (AOP_TYPE(left) == AOP_LIT)
4928     {
4929       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4930
4931       if (!lUnsigned && val < 0)
4932         emitcode ("mov", "a,#0x%02x", -val);
4933       else
4934         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4935     }
4936   else /* ! literal */
4937     {
4938       MOVA (aopGet (left, 0, FALSE, FALSE));
4939
4940       if (!lUnsigned)
4941         {
4942           lbl = newiTempLabel (NULL);
4943           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4944           emitcode ("cpl", "F0"); /* complement sign flag */
4945           emitcode ("cpl", "a"); /* 2's complement */
4946           emitcode ("inc", "a");
4947           emitcode ("", "%05d$:", (lbl->key + 100));
4948         }
4949     }
4950
4951   /* now the multiplication */
4952   emitcode ("mul", "ab");
4953   if (runtimeSign || compiletimeSign)
4954     {
4955       lbl = newiTempLabel (NULL);
4956       if (runtimeSign)
4957         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4958       emitcode ("cpl", "a"); /* lsb 2's complement */
4959       if (size != 2)
4960         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4961       else
4962         {
4963           emitcode ("add", "a,#1"); /* this sets carry flag */
4964           emitcode ("xch", "a,b");
4965           emitcode ("cpl", "a"); /* msb 2's complement */
4966           emitcode ("addc", "a,#0");
4967           emitcode ("xch", "a,b");
4968         }
4969       emitcode ("", "%05d$:", (lbl->key + 100));
4970     }
4971   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4972   if (size == 2)
4973     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4974
4975   popB (pushedB);
4976 }
4977
4978 /*-----------------------------------------------------------------*/
4979 /* genMult - generates code for multiplication                     */
4980 /*-----------------------------------------------------------------*/
4981 static void
4982 genMult (iCode * ic)
4983 {
4984   operand *left = IC_LEFT (ic);
4985   operand *right = IC_RIGHT (ic);
4986   operand *result = IC_RESULT (ic);
4987
4988   D(emitcode (";     genMult",""));
4989
4990   /* assign the asmops */
4991   aopOp (left, ic, FALSE);
4992   aopOp (right, ic, FALSE);
4993   aopOp (result, ic, TRUE);
4994
4995   /* special cases first */
4996   /* both are bits */
4997   if (AOP_TYPE (left) == AOP_CRY &&
4998       AOP_TYPE (right) == AOP_CRY)
4999     {
5000       genMultbits (left, right, result);
5001       goto release;
5002     }
5003
5004   /* if both are of size == 1 */
5005 #if 0 // one of them can be a sloc shared with the result
5006     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5007 #else
5008   if (getSize(operandType(left)) == 1 &&
5009       getSize(operandType(right)) == 1)
5010 #endif
5011     {
5012       genMultOneByte (left, right, result);
5013       goto release;
5014     }
5015
5016   /* should have been converted to function call */
5017     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5018              getSize(OP_SYMBOL(right)->type));
5019   assert (0);
5020
5021 release:
5022   freeAsmop (result, NULL, ic, TRUE);
5023   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5024   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5025 }
5026
5027 /*-----------------------------------------------------------------*/
5028 /* genDivbits :- division of bits                                  */
5029 /*-----------------------------------------------------------------*/
5030 static void
5031 genDivbits (operand * left,
5032             operand * right,
5033             operand * result)
5034 {
5035   char *l;
5036   bool pushedB;
5037
5038   D(emitcode (";     genDivbits",""));
5039
5040   pushedB = pushB ();
5041
5042   /* the result must be bit */
5043   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5044   l = aopGet (left, 0, FALSE, FALSE);
5045
5046   MOVA (l);
5047
5048   emitcode ("div", "ab");
5049   emitcode ("rrc", "a");
5050
5051   popB (pushedB);
5052
5053   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5054 }
5055
5056 /*-----------------------------------------------------------------*/
5057 /* genDivOneByte : 8 bit division                                  */
5058 /*-----------------------------------------------------------------*/
5059 static void
5060 genDivOneByte (operand * left,
5061                operand * right,
5062                operand * result)
5063 {
5064   bool lUnsigned, rUnsigned, pushedB;
5065   bool runtimeSign, compiletimeSign;
5066   bool accuse = FALSE;
5067   bool pushedA = FALSE;
5068   symbol *lbl;
5069   int size, offset;
5070
5071   D(emitcode (";     genDivOneByte",""));
5072
5073   /* Why is it necessary that genDivOneByte() can return an int result?
5074      Have a look at:
5075
5076         volatile unsigned char uc;
5077         volatile signed char sc1, sc2;
5078         volatile int i;
5079
5080         uc  = 255;
5081         sc1 = -1;
5082         i = uc / sc1;
5083
5084      Or:
5085
5086         sc1 = -128;
5087         sc2 = -1;
5088         i = sc1 / sc2;
5089
5090      In all cases a one byte result would overflow, the following cast to int
5091      would return the wrong result.
5092
5093      Two possible solution:
5094         a) cast operands to int, if ((unsigned) / (signed)) or
5095            ((signed) / (signed))
5096         b) return an 16 bit signed int; this is what we're doing here!
5097   */
5098
5099   size = AOP_SIZE (result) - 1;
5100   offset = 1;
5101   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5102   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5103
5104   pushedB = pushB ();
5105
5106   /* signed or unsigned */
5107   if (lUnsigned && rUnsigned)
5108     {
5109       /* unsigned is easy */
5110       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5111       MOVA (aopGet (left, 0, FALSE, FALSE));
5112       emitcode ("div", "ab");
5113       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5114       while (size--)
5115         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5116
5117       popB (pushedB);
5118       return;
5119     }
5120
5121   /* signed is a little bit more difficult */
5122
5123   /* now sign adjust for both left & right */
5124
5125   /* let's see what's needed: */
5126   /* apply negative sign during runtime */
5127   runtimeSign = FALSE;
5128   /* negative sign from literals */
5129   compiletimeSign = FALSE;
5130
5131   if (!lUnsigned)
5132     {
5133       if (AOP_TYPE(left) == AOP_LIT)
5134         {
5135           /* signed literal */
5136           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5137           if (val < 0)
5138             compiletimeSign = TRUE;
5139         }
5140       else
5141         /* signed but not literal */
5142         runtimeSign = TRUE;
5143     }
5144
5145   if (!rUnsigned)
5146     {
5147       if (AOP_TYPE(right) == AOP_LIT)
5148         {
5149           /* signed literal */
5150           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5151           if (val < 0)
5152             compiletimeSign ^= TRUE;
5153         }
5154       else
5155         /* signed but not literal */
5156         runtimeSign = TRUE;
5157     }
5158
5159   /* initialize F0, which stores the runtime sign */
5160   if (runtimeSign)
5161     {
5162       if (compiletimeSign)
5163         emitcode ("setb", "F0"); /* set sign flag */
5164       else
5165         emitcode ("clr", "F0"); /* reset sign flag */
5166     }
5167
5168   /* save the signs of the operands */
5169   if (AOP_TYPE(right) == AOP_LIT)
5170     {
5171       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5172
5173       if (!rUnsigned && val < 0)
5174         emitcode ("mov", "b,#0x%02x", -val);
5175       else
5176         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5177     }
5178   else /* ! literal */
5179     {
5180       if (rUnsigned)
5181         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5182       else
5183         {
5184           MOVA (aopGet (right, 0, FALSE, FALSE));
5185           lbl = newiTempLabel (NULL);
5186           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5187           emitcode ("cpl", "F0"); /* complement sign flag */
5188           emitcode ("cpl", "a");  /* 2's complement */
5189           emitcode ("inc", "a");
5190           emitcode ("", "%05d$:", (lbl->key + 100));
5191           emitcode ("mov", "b,a");
5192         }
5193     }
5194
5195   if (AOP_TYPE(left) == AOP_LIT)
5196     {
5197       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5198
5199       if (!lUnsigned && val < 0)
5200         emitcode ("mov", "a,#0x%02x", -val);
5201       else
5202         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5203     }
5204   else /* ! literal */
5205     {
5206       MOVA (aopGet (left, 0, FALSE, FALSE));
5207
5208       if (!lUnsigned)
5209         {
5210           lbl = newiTempLabel (NULL);
5211           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5212           emitcode ("cpl", "F0"); /* complement sign flag */
5213           emitcode ("cpl", "a");  /* 2's complement */
5214           emitcode ("inc", "a");
5215           emitcode ("", "%05d$:", (lbl->key + 100));
5216         }
5217     }
5218
5219   /* now the division */
5220   emitcode ("div", "ab");
5221
5222   if (runtimeSign || compiletimeSign)
5223     {
5224       lbl = newiTempLabel (NULL);
5225       if (runtimeSign)
5226         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5227       emitcode ("cpl", "a"); /* lsb 2's complement */
5228       emitcode ("inc", "a");
5229       emitcode ("", "%05d$:", (lbl->key + 100));
5230
5231       accuse = aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5232       if (size > 0)
5233         {
5234           /* msb is 0x00 or 0xff depending on the sign */
5235           if (runtimeSign)
5236             {
5237               if (accuse)
5238                 {
5239                   emitcode ("push", "acc");
5240                   pushedA = TRUE;
5241                 }
5242               emitcode ("mov", "c,F0");
5243               emitcode ("subb", "a,acc");
5244               while (size--)
5245                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5246             }
5247           else /* compiletimeSign */
5248             {
5249               if (aopPutUsesAcc (result, "#0xFF", offset))
5250                 {
5251                   emitcode ("push", "acc");
5252                   pushedA = TRUE;
5253                 }
5254               while (size--)
5255                 aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5256             }
5257         }
5258     }
5259   else
5260     {
5261       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5262       while (size--)
5263         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5264     }
5265
5266   if (pushedA)
5267     emitcode ("pop", "acc");
5268   popB (pushedB);
5269 }
5270
5271 /*-----------------------------------------------------------------*/
5272 /* genDiv - generates code for division                            */
5273 /*-----------------------------------------------------------------*/
5274 static void
5275 genDiv (iCode * ic)
5276 {
5277   operand *left = IC_LEFT (ic);
5278   operand *right = IC_RIGHT (ic);
5279   operand *result = IC_RESULT (ic);
5280
5281   D(emitcode (";     genDiv",""));
5282
5283   /* assign the amsops */
5284   aopOp (left, ic, FALSE);
5285   aopOp (right, ic, FALSE);
5286   aopOp (result, ic, TRUE);
5287
5288   /* special cases first */
5289   /* both are bits */
5290   if (AOP_TYPE (left) == AOP_CRY &&
5291       AOP_TYPE (right) == AOP_CRY)
5292     {
5293       genDivbits (left, right, result);
5294       goto release;
5295     }
5296
5297   /* if both are of size == 1 */
5298   if (AOP_SIZE (left) == 1 &&
5299       AOP_SIZE (right) == 1)
5300     {
5301       genDivOneByte (left, right, result);
5302       goto release;
5303     }
5304
5305   /* should have been converted to function call */
5306   assert (0);
5307 release:
5308   freeAsmop (result, NULL, ic, TRUE);
5309   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5310   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5311 }
5312
5313 /*-----------------------------------------------------------------*/
5314 /* genModbits :- modulus of bits                                   */
5315 /*-----------------------------------------------------------------*/
5316 static void
5317 genModbits (operand * left,
5318             operand * right,
5319             operand * result)
5320 {
5321   char *l;
5322   bool pushedB;
5323
5324   D(emitcode (";     genModbits",""));
5325
5326   pushedB = pushB ();
5327
5328   /* the result must be bit */
5329   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5330   l = aopGet (left, 0, FALSE, FALSE);
5331
5332   MOVA (l);
5333
5334   emitcode ("div", "ab");
5335   emitcode ("mov", "a,b");
5336   emitcode ("rrc", "a");
5337
5338   popB (pushedB);
5339
5340   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5341 }
5342
5343 /*-----------------------------------------------------------------*/
5344 /* genModOneByte : 8 bit modulus                                   */
5345 /*-----------------------------------------------------------------*/
5346 static void
5347 genModOneByte (operand * left,
5348                operand * right,
5349                operand * result)
5350 {
5351   bool lUnsigned, rUnsigned, pushedB;
5352   bool runtimeSign, compiletimeSign;
5353   symbol *lbl;
5354   int size, offset;
5355
5356   D(emitcode (";     genModOneByte",""));
5357
5358   size = AOP_SIZE (result) - 1;
5359   offset = 1;
5360   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5361   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5362
5363   /* if right is a literal, check it for 2^n */
5364   if (AOP_TYPE(right) == AOP_LIT)
5365     {
5366       unsigned char val = abs((int) operandLitValue(right));
5367       symbol *lbl2 = NULL;
5368
5369       switch (val)
5370         {
5371           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5372           case 2:
5373           case 4:
5374           case 8:
5375           case 16:
5376           case 32:
5377           case 64:
5378           case 128:
5379             if (lUnsigned)
5380               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5381                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5382               /* because iCode should have been changed to genAnd  */
5383               /* see file "SDCCopt.c", function "convertToFcall()" */
5384
5385             MOVA (aopGet (left, 0, FALSE, FALSE));
5386             emitcode ("mov", "c,acc.7");
5387             emitcode ("anl", "a,#0x%02x", val - 1);
5388             lbl = newiTempLabel (NULL);
5389             emitcode ("jz", "%05d$", (lbl->key + 100));
5390             emitcode ("jnc", "%05d$", (lbl->key + 100));
5391             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5392             if (size)
5393               {
5394                 int size2 = size;
5395                 int offs2 = offset;
5396
5397                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5398                 while (size2--)
5399                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
5400                 lbl2 = newiTempLabel (NULL);
5401                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5402               }
5403             emitcode ("", "%05d$:", (lbl->key + 100));
5404             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5405             while (size--)
5406               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5407             if (lbl2)
5408               {
5409                 emitcode ("", "%05d$:", (lbl2->key + 100));
5410               }
5411             return;
5412
5413           default:
5414             break;
5415         }
5416     }
5417
5418   pushedB = pushB ();
5419
5420   /* signed or unsigned */
5421   if (lUnsigned && rUnsigned)
5422     {
5423       /* unsigned is easy */
5424       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5425       MOVA (aopGet (left, 0, FALSE, FALSE));
5426       emitcode ("div", "ab");
5427       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5428       while (size--)
5429         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5430
5431       popB (pushedB);
5432       return;
5433     }
5434
5435   /* signed is a little bit more difficult */
5436
5437   /* now sign adjust for both left & right */
5438
5439   /* modulus: sign of the right operand has no influence on the result! */
5440   if (AOP_TYPE(right) == AOP_LIT)
5441     {
5442       signed char val = (char) operandLitValue(right);
5443
5444       if (!rUnsigned && val < 0)
5445         emitcode ("mov", "b,#0x%02x", -val);
5446       else
5447         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5448     }
5449   else /* not literal */
5450     {
5451       if (rUnsigned)
5452         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5453       else
5454         {
5455           MOVA (aopGet (right, 0, FALSE, FALSE));
5456           lbl = newiTempLabel (NULL);
5457           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5458           emitcode ("cpl", "a"); /* 2's complement */
5459           emitcode ("inc", "a");
5460           emitcode ("", "%05d$:", (lbl->key + 100));
5461           emitcode ("mov", "b,a");
5462         }
5463     }
5464
5465   /* let's see what's needed: */
5466   /* apply negative sign during runtime */
5467   runtimeSign = FALSE;
5468   /* negative sign from literals */
5469   compiletimeSign = FALSE;
5470
5471   /* sign adjust left side */
5472   if (AOP_TYPE(left) == AOP_LIT)
5473     {
5474       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5475
5476       if (!lUnsigned && val < 0)
5477         {
5478           compiletimeSign = TRUE; /* set sign flag */
5479           emitcode ("mov", "a,#0x%02x", -val);
5480         }
5481       else
5482         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5483     }
5484   else /* ! literal */
5485     {
5486       MOVA (aopGet (left, 0, FALSE, FALSE));
5487
5488       if (!lUnsigned)
5489         {
5490           runtimeSign = TRUE;
5491           emitcode ("clr", "F0"); /* clear sign flag */
5492
5493           lbl = newiTempLabel (NULL);
5494           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5495           emitcode ("setb", "F0"); /* set sign flag */
5496           emitcode ("cpl", "a");   /* 2's complement */
5497           emitcode ("inc", "a");
5498           emitcode ("", "%05d$:", (lbl->key + 100));
5499         }
5500     }
5501
5502   /* now the modulus */
5503   emitcode ("div", "ab");
5504
5505   if (runtimeSign || compiletimeSign)
5506     {
5507       emitcode ("mov", "a,b");
5508       lbl = newiTempLabel (NULL);
5509       if (runtimeSign)
5510         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5511       emitcode ("cpl", "a"); /* 2's complement */
5512       emitcode ("inc", "a");
5513       emitcode ("", "%05d$:", (lbl->key + 100));
5514
5515       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5516       if (size > 0)
5517         {
5518           /* msb is 0x00 or 0xff depending on the sign */
5519           if (runtimeSign)
5520             {
5521               emitcode ("mov", "c,F0");
5522               emitcode ("subb", "a,acc");
5523               while (size--)
5524                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5525             }
5526           else /* compiletimeSign */
5527             while (size--)
5528               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5529         }
5530     }
5531   else
5532     {
5533       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5534       while (size--)
5535         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5536     }
5537
5538   popB (pushedB);
5539 }
5540
5541 /*-----------------------------------------------------------------*/
5542 /* genMod - generates code for division                            */
5543 /*-----------------------------------------------------------------*/
5544 static void
5545 genMod (iCode * ic)
5546 {
5547   operand *left = IC_LEFT (ic);
5548   operand *right = IC_RIGHT (ic);
5549   operand *result = IC_RESULT (ic);
5550
5551   D(emitcode (";     genMod",""));
5552
5553   /* assign the asmops */
5554   aopOp (left, ic, FALSE);
5555   aopOp (right, ic, FALSE);
5556   aopOp (result, ic, TRUE);
5557
5558   /* special cases first */
5559   /* both are bits */
5560   if (AOP_TYPE (left) == AOP_CRY &&
5561       AOP_TYPE (right) == AOP_CRY)
5562     {
5563       genModbits (left, right, result);
5564       goto release;
5565     }
5566
5567   /* if both are of size == 1 */
5568   if (AOP_SIZE (left) == 1 &&
5569       AOP_SIZE (right) == 1)
5570     {
5571       genModOneByte (left, right, result);
5572       goto release;
5573     }
5574
5575   /* should have been converted to function call */
5576   assert (0);
5577
5578 release:
5579   freeAsmop (result, NULL, ic, TRUE);
5580   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5581   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5582 }
5583
5584 /*-----------------------------------------------------------------*/
5585 /* genIfxJump :- will create a jump depending on the ifx           */
5586 /*-----------------------------------------------------------------*/
5587 static void
5588 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5589 {
5590   symbol *jlbl;
5591   symbol *tlbl = newiTempLabel (NULL);
5592   char *inst;
5593
5594   D(emitcode (";     genIfxJump",""));
5595
5596   /* if true label then we jump if condition
5597      supplied is true */
5598   if (IC_TRUE (ic))
5599     {
5600       jlbl = IC_TRUE (ic);
5601       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5602                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5603     }
5604   else
5605     {
5606       /* false label is present */
5607       jlbl = IC_FALSE (ic);
5608       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5609                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5610     }
5611   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5612     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5613   else
5614     emitcode (inst, "%05d$", tlbl->key + 100);
5615   freeForBranchAsmop (result);
5616   freeForBranchAsmop (right);
5617   freeForBranchAsmop (left);
5618   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5619   emitcode ("", "%05d$:", tlbl->key + 100);
5620
5621   /* mark the icode as generated */
5622   ic->generated = 1;
5623 }
5624
5625 /*-----------------------------------------------------------------*/
5626 /* genCmp :- greater or less than comparison                       */
5627 /*-----------------------------------------------------------------*/
5628 static void
5629 genCmp (operand * left, operand * right,
5630         operand * result, iCode * ifx, int sign, iCode *ic)
5631 {
5632   int size, offset = 0;
5633   unsigned long lit = 0L;
5634   bool rightInB;
5635
5636   D(emitcode (";     genCmp",""));
5637
5638   /* if left & right are bit variables */
5639   if (AOP_TYPE (left) == AOP_CRY &&
5640       AOP_TYPE (right) == AOP_CRY)
5641     {
5642       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5643       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5644     }
5645   else
5646     {
5647       /* subtract right from left if at the
5648          end the carry flag is set then we know that
5649          left is greater than right */
5650       size = max (AOP_SIZE (left), AOP_SIZE (right));
5651
5652       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5653       if ((size == 1) && !sign &&
5654           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5655         {
5656           symbol *lbl = newiTempLabel (NULL);
5657           emitcode ("cjne", "%s,%s,%05d$",
5658                     aopGet (left, offset, FALSE, FALSE),
5659                     aopGet (right, offset, FALSE, FALSE),
5660                     lbl->key + 100);
5661           emitcode ("", "%05d$:", lbl->key + 100);
5662         }
5663       else
5664         {
5665           if (AOP_TYPE (right) == AOP_LIT)
5666             {
5667               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5668               /* optimize if(x < 0) or if(x >= 0) */
5669               if (lit == 0L)
5670                 {
5671                   if (!sign)
5672                     {
5673                       CLRC;
5674                     }
5675                   else
5676                     {
5677                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5678                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5679                         {
5680                           genIfxJump (ifx, "acc.7", left, right, result);
5681                           freeAsmop (right, NULL, ic, TRUE);
5682                           freeAsmop (left, NULL, ic, TRUE);
5683
5684                           return;
5685                         }
5686                       else
5687                         emitcode ("rlc", "a");
5688                     }
5689                   goto release;
5690                 }
5691             }
5692           CLRC;
5693           while (size--)
5694             {
5695               bool pushedB = FALSE;
5696               rightInB = aopGetUsesAcc(right, offset);
5697               if (rightInB)
5698                 {
5699                   pushedB = pushB ();
5700                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5701                 }
5702               MOVA (aopGet (left, offset, FALSE, FALSE));
5703               if (sign && size == 0)
5704                 {
5705                   emitcode ("xrl", "a,#0x80");
5706                   if (AOP_TYPE (right) == AOP_LIT)
5707                     {
5708                       unsigned long lit = (unsigned long)
5709                       floatFromVal (AOP (right)->aopu.aop_lit);
5710                       emitcode ("subb", "a,#0x%02x",
5711                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5712                     }
5713                   else
5714                     {
5715                       if (!rightInB)
5716                         {
5717                           pushedB = pushB ();
5718                           rightInB++;
5719                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5720                         }
5721                       emitcode ("xrl", "b,#0x80");
5722                       emitcode ("subb", "a,b");
5723                     }
5724                 }
5725               else
5726                 {
5727                   if (rightInB)
5728                     emitcode ("subb", "a,b");
5729                   else
5730                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5731                 }
5732               if (rightInB)
5733                 popB (pushedB);
5734               offset++;
5735             }
5736         }
5737     }
5738
5739 release:
5740   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5741   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5742   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5743     {
5744       outBitC (result);
5745     }
5746   else
5747     {
5748       /* if the result is used in the next
5749          ifx conditional branch then generate
5750          code a little differently */
5751       if (ifx)
5752         genIfxJump (ifx, "c", NULL, NULL, result);
5753       else
5754         outBitC (result);
5755       /* leave the result in acc */
5756     }
5757 }
5758
5759 /*-----------------------------------------------------------------*/
5760 /* genCmpGt :- greater than comparison                             */
5761 /*-----------------------------------------------------------------*/
5762 static void
5763 genCmpGt (iCode * ic, iCode * ifx)
5764 {
5765   operand *left, *right, *result;
5766   sym_link *letype, *retype;
5767   int sign;
5768
5769   D(emitcode (";     genCmpGt",""));
5770
5771   left = IC_LEFT (ic);
5772   right = IC_RIGHT (ic);
5773   result = IC_RESULT (ic);
5774
5775   letype = getSpec (operandType (left));
5776   retype = getSpec (operandType (right));
5777   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5778            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5779   /* assign the amsops */
5780   aopOp (result, ic, TRUE);
5781   aopOp (left, ic, FALSE);
5782   aopOp (right, ic, FALSE);
5783
5784   genCmp (right, left, result, ifx, sign, ic);
5785
5786   freeAsmop (result, NULL, ic, TRUE);
5787 }
5788
5789 /*-----------------------------------------------------------------*/
5790 /* genCmpLt - less than comparisons                                */
5791 /*-----------------------------------------------------------------*/
5792 static void
5793 genCmpLt (iCode * ic, iCode * ifx)
5794 {
5795   operand *left, *right, *result;
5796   sym_link *letype, *retype;
5797   int sign;
5798
5799   D(emitcode (";     genCmpLt",""));
5800
5801   left = IC_LEFT (ic);
5802   right = IC_RIGHT (ic);
5803   result = IC_RESULT (ic);
5804
5805   letype = getSpec (operandType (left));
5806   retype = getSpec (operandType (right));
5807   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5808            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5809   /* assign the amsops */
5810   aopOp (result, ic, TRUE);
5811   aopOp (left, ic, FALSE);
5812   aopOp (right, ic, FALSE);
5813
5814   genCmp (left, right, result, ifx, sign, ic);
5815
5816   freeAsmop (result, NULL, ic, TRUE);
5817 }
5818
5819 /*-----------------------------------------------------------------*/
5820 /* gencjneshort - compare and jump if not equal                    */
5821 /*-----------------------------------------------------------------*/
5822 static void
5823 gencjneshort (operand * left, operand * right, symbol * lbl)
5824 {
5825   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5826   int offset = 0;
5827   unsigned long lit = 0L;
5828
5829   /* if the left side is a literal or
5830      if the right is in a pointer register and left
5831      is not */
5832   if ((AOP_TYPE (left) == AOP_LIT) ||
5833       (AOP_TYPE (left) == AOP_IMMD) ||
5834       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5835     {
5836       operand *t = right;
5837       right = left;
5838       left = t;
5839     }
5840
5841   if (AOP_TYPE (right) == AOP_LIT)
5842     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5843
5844   /* if the right side is a literal then anything goes */
5845   if (AOP_TYPE (right) == AOP_LIT &&
5846       AOP_TYPE (left) != AOP_DIR  &&
5847       AOP_TYPE (left) != AOP_IMMD)
5848     {
5849       while (size--)
5850         {
5851           emitcode ("cjne", "%s,%s,%05d$",
5852                     aopGet (left, offset, FALSE, FALSE),
5853                     aopGet (right, offset, FALSE, FALSE),
5854                     lbl->key + 100);
5855           offset++;
5856         }
5857     }
5858
5859   /* if the right side is in a register or in direct space or
5860      if the left is a pointer register & right is not */
5861   else if (AOP_TYPE (right) == AOP_REG ||
5862            AOP_TYPE (right) == AOP_DIR ||
5863            AOP_TYPE (right) == AOP_LIT ||
5864            AOP_TYPE (right) == AOP_IMMD ||
5865            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5866            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5867     {
5868       while (size--)
5869         {
5870           MOVA (aopGet (left, offset, FALSE, FALSE));
5871           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5872               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5873             emitcode ("jnz", "%05d$", lbl->key + 100);
5874           else
5875             emitcode ("cjne", "a,%s,%05d$",
5876                       aopGet (right, offset, FALSE, TRUE),
5877                       lbl->key + 100);
5878           offset++;
5879         }
5880     }
5881   else
5882     {
5883       /* right is a pointer reg need both a & b */
5884       while (size--)
5885         {
5886           char *l;
5887           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5888           wassertl(!BINUSE, "B was in use");
5889           l = aopGet (left, offset, FALSE, FALSE);
5890           if (strcmp (l, "b"))
5891             emitcode ("mov", "b,%s", l);
5892           MOVA (aopGet (right, offset, FALSE, FALSE));
5893           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5894           offset++;
5895         }
5896     }
5897 }
5898
5899 /*-----------------------------------------------------------------*/
5900 /* gencjne - compare and jump if not equal                         */
5901 /*-----------------------------------------------------------------*/
5902 static void
5903 gencjne (operand * left, operand * right, symbol * lbl)
5904 {
5905   symbol *tlbl = newiTempLabel (NULL);
5906
5907   gencjneshort (left, right, lbl);
5908
5909   emitcode ("mov", "a,%s", one);
5910   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5911   emitcode ("", "%05d$:", lbl->key + 100);
5912   emitcode ("clr", "a");
5913   emitcode ("", "%05d$:", tlbl->key + 100);
5914 }
5915
5916 /*-----------------------------------------------------------------*/
5917 /* genCmpEq - generates code for equal to                          */
5918 /*-----------------------------------------------------------------*/
5919 static void
5920 genCmpEq (iCode * ic, iCode * ifx)
5921 {
5922   bool swappedLR = FALSE;
5923   operand *left, *right, *result;
5924
5925   D(emitcode (";     genCmpEq",""));
5926
5927   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5928   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5929   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5930
5931   /* if literal, literal on the right or
5932      if the right is in a pointer register and left
5933      is not */
5934   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5935       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5936     {
5937       operand *t = IC_RIGHT (ic);
5938       IC_RIGHT (ic) = IC_LEFT (ic);
5939       IC_LEFT (ic) = t;
5940           swappedLR = TRUE;
5941     }
5942
5943   if (ifx && !AOP_SIZE (result))
5944     {
5945       symbol *tlbl;
5946       /* if they are both bit variables */
5947       if (AOP_TYPE (left) == AOP_CRY &&
5948           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5949         {
5950           if (AOP_TYPE (right) == AOP_LIT)
5951             {
5952               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5953               if (lit == 0L)
5954                 {
5955                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5956                   emitcode ("cpl", "c");
5957                 }
5958               else if (lit == 1L)
5959                 {
5960                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5961                 }
5962               else
5963                 {
5964                   emitcode ("clr", "c");
5965                 }
5966               /* AOP_TYPE(right) == AOP_CRY */
5967             }
5968           else
5969             {
5970               symbol *lbl = newiTempLabel (NULL);
5971               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5972               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5973               emitcode ("cpl", "c");
5974               emitcode ("", "%05d$:", (lbl->key + 100));
5975             }
5976           /* if true label then we jump if condition
5977              supplied is true */
5978           tlbl = newiTempLabel (NULL);
5979           if (IC_TRUE (ifx))
5980             {
5981               emitcode ("jnc", "%05d$", tlbl->key + 100);
5982               freeForBranchAsmop (result);
5983               freeForBranchAsmop (right);
5984               freeForBranchAsmop (left);
5985               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5986             }
5987           else
5988             {
5989               emitcode ("jc", "%05d$", tlbl->key + 100);
5990               freeForBranchAsmop (result);
5991               freeForBranchAsmop (right);
5992               freeForBranchAsmop (left);
5993               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5994             }
5995           emitcode ("", "%05d$:", tlbl->key + 100);
5996         }
5997       else
5998         {
5999           tlbl = newiTempLabel (NULL);
6000           gencjneshort (left, right, tlbl);
6001           if (IC_TRUE (ifx))
6002             {
6003               freeForBranchAsmop (result);
6004               freeForBranchAsmop (right);
6005               freeForBranchAsmop (left);
6006               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6007               emitcode ("", "%05d$:", tlbl->key + 100);
6008             }
6009           else
6010             {
6011               symbol *lbl = newiTempLabel (NULL);
6012               emitcode ("sjmp", "%05d$", lbl->key + 100);
6013               emitcode ("", "%05d$:", tlbl->key + 100);
6014               freeForBranchAsmop (result);
6015               freeForBranchAsmop (right);
6016               freeForBranchAsmop (left);
6017               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6018               emitcode ("", "%05d$:", lbl->key + 100);
6019             }
6020         }
6021       /* mark the icode as generated */
6022       ifx->generated = 1;
6023       goto release;
6024     }
6025
6026   /* if they are both bit variables */
6027   if (AOP_TYPE (left) == AOP_CRY &&
6028       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6029     {
6030       if (AOP_TYPE (right) == AOP_LIT)
6031         {
6032           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6033           if (lit == 0L)
6034             {
6035               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6036               emitcode ("cpl", "c");
6037             }
6038           else if (lit == 1L)
6039             {
6040               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6041             }
6042           else
6043             {
6044               emitcode ("clr", "c");
6045             }
6046           /* AOP_TYPE(right) == AOP_CRY */
6047         }
6048       else
6049         {
6050           symbol *lbl = newiTempLabel (NULL);
6051           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6052           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6053           emitcode ("cpl", "c");
6054           emitcode ("", "%05d$:", (lbl->key + 100));
6055         }
6056       /* c = 1 if egal */
6057       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6058         {
6059           outBitC (result);
6060           goto release;
6061         }
6062       if (ifx)
6063         {
6064           genIfxJump (ifx, "c", left, right, result);
6065           goto release;
6066         }
6067       /* if the result is used in an arithmetic operation
6068          then put the result in place */
6069       outBitC (result);
6070     }
6071   else
6072     {
6073       gencjne (left, right, newiTempLabel (NULL));
6074       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6075         {
6076           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6077           goto release;
6078         }
6079       if (ifx)
6080         {
6081           genIfxJump (ifx, "a", left, right, result);
6082           goto release;
6083         }
6084       /* if the result is used in an arithmetic operation
6085          then put the result in place */
6086       if (AOP_TYPE (result) != AOP_CRY)
6087         outAcc (result);
6088       /* leave the result in acc */
6089     }
6090
6091 release:
6092   freeAsmop (result, NULL, ic, TRUE);
6093   if (!swappedLR)
6094     {
6095       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6096       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6097     }
6098   else
6099     {
6100       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6101       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6102     }
6103 }
6104
6105 /*-----------------------------------------------------------------*/
6106 /* ifxForOp - returns the icode containing the ifx for operand     */
6107 /*-----------------------------------------------------------------*/
6108 static iCode *
6109 ifxForOp (operand * op, iCode * ic)
6110 {
6111   /* if true symbol then needs to be assigned */
6112   if (IS_TRUE_SYMOP (op))
6113     return NULL;
6114
6115   /* if this has register type condition and
6116      the next instruction is ifx with the same operand
6117      and live to of the operand is upto the ifx only then */
6118   if (ic->next &&
6119       ic->next->op == IFX &&
6120       IC_COND (ic->next)->key == op->key &&
6121       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6122     return ic->next;
6123
6124   return NULL;
6125 }
6126
6127 /*-----------------------------------------------------------------*/
6128 /* hasInc - operand is incremented before any other use            */
6129 /*-----------------------------------------------------------------*/
6130 static iCode *
6131 hasInc (operand *op, iCode *ic,int osize)
6132 {
6133   sym_link *type = operandType(op);
6134   sym_link *retype = getSpec (type);
6135   iCode *lic = ic->next;
6136   int isize ;
6137
6138   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6139   if (!IS_SYMOP(op)) return NULL;
6140
6141   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6142   if (IS_AGGREGATE(type->next)) return NULL;
6143   if (osize != (isize = getSize(type->next))) return NULL;
6144
6145   while (lic) {
6146     /* if operand of the form op = op + <sizeof *op> */
6147     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6148         isOperandEqual(IC_RESULT(lic),op) &&
6149         isOperandLiteral(IC_RIGHT(lic)) &&
6150         operandLitValue(IC_RIGHT(lic)) == isize) {
6151       return lic;
6152     }
6153     /* if the operand used or deffed */
6154     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6155       return NULL;
6156     }
6157     /* if GOTO or IFX */
6158     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6159     lic = lic->next;
6160   }
6161   return NULL;
6162 }
6163
6164 /*-----------------------------------------------------------------*/
6165 /* genAndOp - for && operation                                     */
6166 /*-----------------------------------------------------------------*/
6167 static void
6168 genAndOp (iCode * ic)
6169 {
6170   operand *left, *right, *result;
6171   symbol *tlbl;
6172
6173   D(emitcode (";     genAndOp",""));
6174
6175   /* note here that && operations that are in an
6176      if statement are taken away by backPatchLabels
6177      only those used in arthmetic operations remain */
6178   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6179   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6180   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6181
6182   /* if both are bit variables */
6183   if (AOP_TYPE (left) == AOP_CRY &&
6184       AOP_TYPE (right) == AOP_CRY)
6185     {
6186       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6187       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6188       outBitC (result);
6189     }
6190   else
6191     {
6192       tlbl = newiTempLabel (NULL);
6193       toBoolean (left);
6194       emitcode ("jz", "%05d$", tlbl->key + 100);
6195       toBoolean (right);
6196       emitcode ("", "%05d$:", tlbl->key + 100);
6197       outBitAcc (result);
6198     }
6199
6200   freeAsmop (result, NULL, ic, TRUE);
6201   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6202   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6203 }
6204
6205
6206 /*-----------------------------------------------------------------*/
6207 /* genOrOp - for || operation                                      */
6208 /*-----------------------------------------------------------------*/
6209 static void
6210 genOrOp (iCode * ic)
6211 {
6212   operand *left, *right, *result;
6213   symbol *tlbl;
6214
6215   D(emitcode (";     genOrOp",""));
6216
6217   /* note here that || operations that are in an
6218      if statement are taken away by backPatchLabels
6219      only those used in arthmetic operations remain */
6220   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6221   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6222   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6223
6224   /* if both are bit variables */
6225   if (AOP_TYPE (left) == AOP_CRY &&
6226       AOP_TYPE (right) == AOP_CRY)
6227     {
6228       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6229       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6230       outBitC (result);
6231     }
6232   else
6233     {
6234       tlbl = newiTempLabel (NULL);
6235       toBoolean (left);
6236       emitcode ("jnz", "%05d$", tlbl->key + 100);
6237       toBoolean (right);
6238       emitcode ("", "%05d$:", tlbl->key + 100);
6239       outBitAcc (result);
6240     }
6241
6242   freeAsmop (result, NULL, ic, TRUE);
6243   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6244   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6245 }
6246
6247 /*-----------------------------------------------------------------*/
6248 /* isLiteralBit - test if lit == 2^n                               */
6249 /*-----------------------------------------------------------------*/
6250 static int
6251 isLiteralBit (unsigned long lit)
6252 {
6253   unsigned long pw[32] =
6254   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6255    0x100L, 0x200L, 0x400L, 0x800L,
6256    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6257    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6258    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6259    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6260    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6261   int idx;
6262
6263   for (idx = 0; idx < 32; idx++)
6264     if (lit == pw[idx])
6265       return idx + 1;
6266   return 0;
6267 }
6268
6269 /*-----------------------------------------------------------------*/
6270 /* continueIfTrue -                                                */
6271 /*-----------------------------------------------------------------*/
6272 static void
6273 continueIfTrue (iCode * ic)
6274 {
6275   if (IC_TRUE (ic))
6276     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6277   ic->generated = 1;
6278 }
6279
6280 /*-----------------------------------------------------------------*/
6281 /* jmpIfTrue -                                                     */
6282 /*-----------------------------------------------------------------*/
6283 static void
6284 jumpIfTrue (iCode * ic)
6285 {
6286   if (!IC_TRUE (ic))
6287     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6288   ic->generated = 1;
6289 }
6290
6291 /*-----------------------------------------------------------------*/
6292 /* jmpTrueOrFalse -                                                */
6293 /*-----------------------------------------------------------------*/
6294 static void
6295 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6296 {
6297   // ugly but optimized by peephole
6298   if (IC_TRUE (ic))
6299     {
6300       symbol *nlbl = newiTempLabel (NULL);
6301       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6302       emitcode ("", "%05d$:", tlbl->key + 100);
6303       freeForBranchAsmop (result);
6304       freeForBranchAsmop (right);
6305       freeForBranchAsmop (left);
6306       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6307       emitcode ("", "%05d$:", nlbl->key + 100);
6308     }
6309   else
6310     {
6311       freeForBranchAsmop (result);
6312       freeForBranchAsmop (right);
6313       freeForBranchAsmop (left);
6314       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6315       emitcode ("", "%05d$:", tlbl->key + 100);
6316     }
6317   ic->generated = 1;
6318 }
6319
6320 /*-----------------------------------------------------------------*/
6321 /* genAnd  - code for and                                          */
6322 /*-----------------------------------------------------------------*/
6323 static void
6324 genAnd (iCode * ic, iCode * ifx)
6325 {
6326   operand *left, *right, *result;
6327   int size, offset = 0;
6328   unsigned long lit = 0L;
6329   int bytelit = 0;
6330   char buffer[10];
6331
6332   D(emitcode (";     genAnd",""));
6333
6334   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6335   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6336   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6337
6338 #ifdef DEBUG_TYPE
6339   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6340             AOP_TYPE (result),
6341             AOP_TYPE (left), AOP_TYPE (right));
6342   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6343             AOP_SIZE (result),
6344             AOP_SIZE (left), AOP_SIZE (right));
6345 #endif
6346
6347   /* if left is a literal & right is not then exchange them */
6348   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6349       AOP_NEEDSACC (left))
6350     {
6351       operand *tmp = right;
6352       right = left;
6353       left = tmp;
6354     }
6355
6356   /* if result = right then exchange left and right */
6357   if (sameRegs (AOP (result), AOP (right)))
6358     {
6359       operand *tmp = right;
6360       right = left;
6361       left = tmp;
6362     }
6363
6364   /* if right is bit then exchange them */
6365   if (AOP_TYPE (right) == AOP_CRY &&
6366       AOP_TYPE (left) != AOP_CRY)
6367     {
6368       operand *tmp = right;
6369       right = left;
6370       left = tmp;
6371     }
6372   if (AOP_TYPE (right) == AOP_LIT)
6373     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6374
6375   size = AOP_SIZE (result);
6376
6377   // if(bit & yy)
6378   // result = bit & yy;
6379   if (AOP_TYPE (left) == AOP_CRY)
6380     {
6381       // c = bit & literal;
6382       if (AOP_TYPE (right) == AOP_LIT)
6383         {
6384           if (lit & 1)
6385             {
6386               if (size && sameRegs (AOP (result), AOP (left)))
6387                 // no change
6388                 goto release;
6389               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6390             }
6391           else
6392             {
6393               // bit(result) = 0;
6394               if (size && (AOP_TYPE (result) == AOP_CRY))
6395                 {
6396                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6397                   goto release;
6398                 }
6399               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6400                 {
6401                   jumpIfTrue (ifx);
6402                   goto release;
6403                 }
6404               emitcode ("clr", "c");
6405             }
6406         }
6407       else
6408         {
6409           if (AOP_TYPE (right) == AOP_CRY)
6410             {
6411               // c = bit & bit;
6412               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6413               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6414             }
6415           else
6416             {
6417               // c = bit & val;
6418               MOVA (aopGet (right, 0, FALSE, FALSE));
6419               // c = lsb
6420               emitcode ("rrc", "a");
6421               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6422             }
6423         }
6424       // bit = c
6425       // val = c
6426       if (size)
6427         outBitC (result);
6428       // if(bit & ...)
6429       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6430         genIfxJump (ifx, "c", left, right, result);
6431       goto release;
6432     }
6433
6434   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6435   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6436   if ((AOP_TYPE (right) == AOP_LIT) &&
6437       (AOP_TYPE (result) == AOP_CRY) &&
6438       (AOP_TYPE (left) != AOP_CRY))
6439     {
6440       int posbit = isLiteralBit (lit);
6441       /* left &  2^n */
6442       if (posbit)
6443         {
6444           posbit--;
6445           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6446           // bit = left & 2^n
6447           if (size)
6448             {
6449               switch (posbit & 0x07)
6450                 {
6451                   case 0: emitcode ("rrc", "a");
6452                           break;
6453                   case 7: emitcode ("rlc", "a");
6454                           break;
6455                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6456                           break;
6457                 }
6458             }
6459           // if(left &  2^n)
6460           else
6461             {
6462               if (ifx)
6463                 {
6464                   SNPRINTF (buffer, sizeof(buffer),
6465                             "acc.%d", posbit & 0x07);
6466                   genIfxJump (ifx, buffer, left, right, result);
6467                 }
6468               else
6469                 {// what is this case? just found it in ds390/gen.c
6470                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6471                 }
6472               goto release;
6473             }
6474         }
6475       else
6476         {
6477           symbol *tlbl = newiTempLabel (NULL);
6478           int sizel = AOP_SIZE (left);
6479           if (size)
6480             emitcode ("setb", "c");
6481           while (sizel--)
6482             {
6483               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6484                 {
6485                   MOVA (aopGet (left, offset, FALSE, FALSE));
6486                   // byte ==  2^n ?
6487                   if ((posbit = isLiteralBit (bytelit)) != 0)
6488                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6489                   else
6490                     {
6491                       if (bytelit != 0x0FFL)
6492                         emitcode ("anl", "a,%s",
6493                                   aopGet (right, offset, FALSE, TRUE));
6494                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6495                     }
6496                 }
6497               offset++;
6498             }
6499           // bit = left & literal
6500           if (size)
6501             {
6502               emitcode ("clr", "c");
6503               emitcode ("", "%05d$:", tlbl->key + 100);
6504             }
6505           // if(left & literal)
6506           else
6507             {
6508               if (ifx)
6509                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6510               else
6511                 emitcode ("", "%05d$:", tlbl->key + 100);
6512               goto release;
6513             }
6514         }
6515       outBitC (result);
6516       goto release;
6517     }
6518
6519   /* if left is same as result */
6520   if (sameRegs (AOP (result), AOP (left)))
6521     {
6522       for (; size--; offset++)
6523         {
6524           if (AOP_TYPE (right) == AOP_LIT)
6525             {
6526               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6527               if (bytelit == 0x0FF)
6528                 {
6529                   /* dummy read of volatile operand */
6530                   if (isOperandVolatile (left, FALSE))
6531                     MOVA (aopGet (left, offset, FALSE, FALSE));
6532                   else
6533                     continue;
6534                 }
6535               else if (bytelit == 0)
6536                 {
6537                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6538                 }
6539               else if (IS_AOP_PREG (result))
6540                 {
6541                   MOVA (aopGet (left, offset, FALSE, TRUE));
6542                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6543                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6544                 }
6545               else
6546                 emitcode ("anl", "%s,%s",
6547                           aopGet (left, offset, FALSE, TRUE),
6548                           aopGet (right, offset, FALSE, FALSE));
6549             }
6550           else
6551             {
6552               if (AOP_TYPE (left) == AOP_ACC)
6553                 {
6554                   if (offset)
6555                     emitcode("mov", "a,b");
6556                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6557                 }
6558               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6559                 {
6560                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6561                   MOVA (aopGet (right, offset, FALSE, FALSE));
6562                   emitcode ("anl", "a,b");
6563                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6564                 }
6565               else if (aopGetUsesAcc (left, offset))
6566                 {
6567                   MOVA (aopGet (left, offset, FALSE, FALSE));
6568                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6569                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6570                 }
6571               else
6572                 {
6573                   MOVA (aopGet (right, offset, FALSE, FALSE));
6574                   if (IS_AOP_PREG (result))
6575                     {
6576                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6577                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6578                     }
6579                   else
6580                     emitcode ("anl", "%s,a",
6581                               aopGet (left, offset, FALSE, TRUE));
6582                 }
6583             }
6584         }
6585     }
6586   else
6587     {
6588       // left & result in different registers
6589       if (AOP_TYPE (result) == AOP_CRY)
6590         {
6591           // result = bit
6592           // if(size), result in bit
6593           // if(!size && ifx), conditional oper: if(left & right)
6594           symbol *tlbl = newiTempLabel (NULL);
6595           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6596           if (size)
6597             emitcode ("setb", "c");
6598           while (sizer--)
6599             {
6600               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6601                   && AOP_TYPE(left)==AOP_ACC)
6602                 {
6603                   if (offset)
6604                     emitcode("mov", "a,b");
6605                   emitcode ("anl", "a,%s",
6606                             aopGet (right, offset, FALSE, FALSE));
6607                 } else {
6608                   if (AOP_TYPE(left)==AOP_ACC)
6609                     {
6610                       if (!offset)
6611                         {
6612                           bool pushedB = pushB ();
6613                           emitcode("mov", "b,a");
6614                           MOVA (aopGet (right, offset, FALSE, FALSE));
6615                           emitcode("anl", "a,b");
6616                           popB (pushedB);
6617                         }
6618                       else
6619                         {
6620                           MOVA (aopGet (right, offset, FALSE, FALSE));
6621                           emitcode("anl", "a,b");
6622                         }
6623                     } else {
6624                       MOVA (aopGet (right, offset, FALSE, FALSE));
6625                       emitcode ("anl", "a,%s",
6626                                 aopGet (left, offset, FALSE, FALSE));
6627                     }
6628                 }
6629               emitcode ("jnz", "%05d$", tlbl->key + 100);
6630               offset++;
6631             }
6632           if (size)
6633             {
6634               CLRC;
6635               emitcode ("", "%05d$:", tlbl->key + 100);
6636               outBitC (result);
6637             }
6638           else if (ifx)
6639             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6640           else
6641             emitcode ("", "%05d$:", tlbl->key + 100);
6642         }
6643       else
6644         {
6645           for (; (size--); offset++)
6646             {
6647               // normal case
6648               // result = left & right
6649               if (AOP_TYPE (right) == AOP_LIT)
6650                 {
6651                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6652                   if (bytelit == 0x0FF)
6653                     {
6654                       aopPut (result,
6655                               aopGet (left, offset, FALSE, FALSE),
6656                               offset,
6657                               isOperandVolatile (result, FALSE));
6658                       continue;
6659                     }
6660                   else if (bytelit == 0)
6661                     {
6662                       /* dummy read of volatile operand */
6663                       if (isOperandVolatile (left, FALSE))
6664                         MOVA (aopGet (left, offset, FALSE, FALSE));
6665                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6666                       continue;
6667                     }
6668                   else if (AOP_TYPE (left) == AOP_ACC)
6669                     {
6670                       if (!offset)
6671                         {
6672                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6673                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6674                           continue;
6675                         }
6676                       else
6677                         {
6678                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6679                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6680                           continue;
6681                         }
6682                     }
6683                 }
6684               // faster than result <- left, anl result,right
6685               // and better if result is SFR
6686               if (AOP_TYPE (left) == AOP_ACC)
6687                 {
6688                   if (offset)
6689                     emitcode("mov", "a,b");
6690                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6691                 }
6692               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6693                 {
6694                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6695                   MOVA (aopGet (right, offset, FALSE, FALSE));
6696                   emitcode ("anl", "a,b");
6697                 }
6698               else if (aopGetUsesAcc (left, offset))
6699                 {
6700                   MOVA (aopGet (left, offset, FALSE, FALSE));
6701                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6702                 }
6703               else
6704                 {
6705                   MOVA (aopGet (right, offset, FALSE, FALSE));
6706                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6707                 }
6708               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6709             }
6710         }
6711     }
6712
6713 release:
6714   freeAsmop (result, NULL, ic, TRUE);
6715   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6716   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6717 }
6718
6719 /*-----------------------------------------------------------------*/
6720 /* genOr  - code for or                                            */
6721 /*-----------------------------------------------------------------*/
6722 static void
6723 genOr (iCode * ic, iCode * ifx)
6724 {
6725   operand *left, *right, *result;
6726   int size, offset = 0;
6727   unsigned long lit = 0L;
6728   int bytelit = 0;
6729
6730   D(emitcode (";     genOr",""));
6731
6732   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6733   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6734   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6735
6736 #ifdef DEBUG_TYPE
6737   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6738             AOP_TYPE (result),
6739             AOP_TYPE (left), AOP_TYPE (right));
6740   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6741             AOP_SIZE (result),
6742             AOP_SIZE (left), AOP_SIZE (right));
6743 #endif
6744
6745   /* if left is a literal & right is not then exchange them */
6746   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6747       AOP_NEEDSACC (left))
6748     {
6749       operand *tmp = right;
6750       right = left;
6751       left = tmp;
6752     }
6753
6754   /* if result = right then exchange them */
6755   if (sameRegs (AOP (result), AOP (right)))
6756     {
6757       operand *tmp = right;
6758       right = left;
6759       left = tmp;
6760     }
6761
6762   /* if right is bit then exchange them */
6763   if (AOP_TYPE (right) == AOP_CRY &&
6764       AOP_TYPE (left) != AOP_CRY)
6765     {
6766       operand *tmp = right;
6767       right = left;
6768       left = tmp;
6769     }
6770   if (AOP_TYPE (right) == AOP_LIT)
6771     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6772
6773   size = AOP_SIZE (result);
6774
6775   // if(bit | yy)
6776   // xx = bit | yy;
6777   if (AOP_TYPE (left) == AOP_CRY)
6778     {
6779       if (AOP_TYPE (right) == AOP_LIT)
6780         {
6781           // c = bit | literal;
6782           if (lit)
6783             {
6784               // lit != 0 => result = 1
6785               if (AOP_TYPE (result) == AOP_CRY)
6786                 {
6787                   if (size)
6788                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6789                   else if (ifx)
6790                     continueIfTrue (ifx);
6791                   goto release;
6792                 }
6793               emitcode ("setb", "c");
6794             }
6795           else
6796             {
6797               // lit == 0 => result = left
6798               if (size && sameRegs (AOP (result), AOP (left)))
6799                 goto release;
6800               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6801             }
6802         }
6803       else
6804         {
6805           if (AOP_TYPE (right) == AOP_CRY)
6806             {
6807               // c = bit | bit;
6808               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6809               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6810             }
6811           else
6812             {
6813               // c = bit | val;
6814               symbol *tlbl = newiTempLabel (NULL);
6815               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6816                 emitcode ("setb", "c");
6817               emitcode ("jb", "%s,%05d$",
6818                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6819               toBoolean (right);
6820               emitcode ("jnz", "%05d$", tlbl->key + 100);
6821               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6822                 {
6823                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6824                   goto release;
6825                 }
6826               else
6827                 {
6828                   CLRC;
6829                   emitcode ("", "%05d$:", tlbl->key + 100);
6830                 }
6831             }
6832         }
6833       // bit = c
6834       // val = c
6835       if (size)
6836         outBitC (result);
6837       // if(bit | ...)
6838       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6839         genIfxJump (ifx, "c", left, right, result);
6840       goto release;
6841     }
6842
6843   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6844   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6845   if ((AOP_TYPE (right) == AOP_LIT) &&
6846       (AOP_TYPE (result) == AOP_CRY) &&
6847       (AOP_TYPE (left) != AOP_CRY))
6848     {
6849       if (lit)
6850         {
6851           // result = 1
6852           if (size)
6853             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6854           else
6855             continueIfTrue (ifx);
6856           goto release;
6857         }
6858       else
6859         {
6860           // lit = 0, result = boolean(left)
6861           if (size)
6862             emitcode ("setb", "c");
6863           toBoolean (right);
6864           if (size)
6865             {
6866               symbol *tlbl = newiTempLabel (NULL);
6867               emitcode ("jnz", "%05d$", tlbl->key + 100);
6868               CLRC;
6869               emitcode ("", "%05d$:", tlbl->key + 100);
6870             }
6871           else
6872             {
6873               genIfxJump (ifx, "a", left, right, result);
6874               goto release;
6875             }
6876         }
6877       outBitC (result);
6878       goto release;
6879     }
6880
6881   /* if left is same as result */
6882   if (sameRegs (AOP (result), AOP (left)))
6883     {
6884       for (; size--; offset++)
6885         {
6886           if (AOP_TYPE (right) == AOP_LIT)
6887             {
6888               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6889               if (bytelit == 0)
6890                 {
6891                   /* dummy read of volatile operand */
6892                   if (isOperandVolatile (left, FALSE))
6893                     MOVA (aopGet (left, offset, FALSE, FALSE));
6894                   else
6895                     continue;
6896                 }
6897               else if (bytelit == 0x0FF)
6898                 {
6899                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6900                 }
6901               else if (IS_AOP_PREG (left))
6902                 {
6903                   MOVA (aopGet (left, offset, FALSE, TRUE));
6904                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6905                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6906                 }
6907               else
6908                 {
6909                   emitcode ("orl", "%s,%s",
6910                             aopGet (left, offset, FALSE, TRUE),
6911                             aopGet (right, offset, FALSE, FALSE));
6912                 }
6913             }
6914           else
6915             {
6916               if (AOP_TYPE (left) == AOP_ACC)
6917                 {
6918                   if (offset)
6919                     emitcode("mov", "a,b");
6920                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6921                 }
6922               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6923                 {
6924                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6925                   MOVA (aopGet (right, offset, FALSE, FALSE));
6926                   emitcode ("orl", "a,b");
6927                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6928                 }
6929               else if (aopGetUsesAcc (left, offset))
6930                 {
6931                   MOVA (aopGet (left, offset, FALSE, FALSE));
6932                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6933                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6934                 }
6935               else
6936                 {
6937                   MOVA (aopGet (right, offset, FALSE, FALSE));
6938                   if (IS_AOP_PREG (left))
6939                     {
6940                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6941                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6942                     }
6943                   else
6944                     {
6945                       emitcode ("orl", "%s,a",
6946                                 aopGet (left, offset, FALSE, TRUE));
6947                     }
6948                 }
6949             }
6950         }
6951     }
6952   else
6953     {
6954       // left & result in different registers
6955       if (AOP_TYPE (result) == AOP_CRY)
6956         {
6957           // result = bit
6958           // if(size), result in bit
6959           // if(!size && ifx), conditional oper: if(left | right)
6960           symbol *tlbl = newiTempLabel (NULL);
6961           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6962           if (size)
6963             emitcode ("setb", "c");
6964           while (sizer--)
6965             {
6966               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6967                 if (offset)
6968                   emitcode("mov", "a,b");
6969                 emitcode ("orl", "a,%s",
6970                           aopGet (right, offset, FALSE, FALSE));
6971               } else {
6972                 MOVA (aopGet (right, offset, FALSE, FALSE));
6973                 emitcode ("orl", "a,%s",
6974                           aopGet (left, offset, FALSE, FALSE));
6975               }
6976               emitcode ("jnz", "%05d$", tlbl->key + 100);
6977               offset++;
6978             }
6979           if (size)
6980             {
6981               CLRC;
6982               emitcode ("", "%05d$:", tlbl->key + 100);
6983               outBitC (result);
6984             }
6985           else if (ifx)
6986             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6987           else
6988             emitcode ("", "%05d$:", tlbl->key + 100);
6989         }
6990       else
6991         {
6992           for (; (size--); offset++)
6993             {
6994               // normal case
6995               // result = left | right
6996               if (AOP_TYPE (right) == AOP_LIT)
6997                 {
6998                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6999                   if (bytelit == 0)
7000                     {
7001                       aopPut (result,
7002                               aopGet (left, offset, FALSE, FALSE),
7003                               offset,
7004                               isOperandVolatile (result, FALSE));
7005                       continue;
7006                     }
7007                   else if (bytelit == 0x0FF)
7008                     {
7009                       /* dummy read of volatile operand */
7010                       if (isOperandVolatile (left, FALSE))
7011                         MOVA (aopGet (left, offset, FALSE, FALSE));
7012                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
7013                       continue;
7014                     }
7015                 }
7016               // faster than result <- left, anl result,right
7017               // and better if result is SFR
7018               if (AOP_TYPE (left) == AOP_ACC)
7019                 {
7020                   if (offset)
7021                     emitcode("mov", "a,b");
7022                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7023                 }
7024               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7025                 {
7026                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7027                   MOVA (aopGet (right, offset, FALSE, FALSE));
7028                   emitcode ("orl", "a,b");
7029                 }
7030               else if (aopGetUsesAcc (left, offset))
7031                 {
7032                   MOVA (aopGet (left, offset, FALSE, FALSE));
7033                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7034                 }
7035               else
7036                 {
7037                   MOVA (aopGet (right, offset, FALSE, FALSE));
7038                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7039                 }
7040               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7041             }
7042         }
7043     }
7044
7045 release:
7046   freeAsmop (result, NULL, ic, TRUE);
7047   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7048   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7049 }
7050
7051 /*-----------------------------------------------------------------*/
7052 /* genXor - code for xclusive or                                   */
7053 /*-----------------------------------------------------------------*/
7054 static void
7055 genXor (iCode * ic, iCode * ifx)
7056 {
7057   operand *left, *right, *result;
7058   int size, offset = 0;
7059   unsigned long lit = 0L;
7060   int bytelit = 0;
7061
7062   D(emitcode (";     genXor",""));
7063
7064   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7065   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7066   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7067
7068 #ifdef DEBUG_TYPE
7069   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7070             AOP_TYPE (result),
7071             AOP_TYPE (left), AOP_TYPE (right));
7072   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7073             AOP_SIZE (result),
7074             AOP_SIZE (left), AOP_SIZE (right));
7075 #endif
7076
7077   /* if left is a literal & right is not ||
7078      if left needs acc & right does not */
7079   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7080       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7081     {
7082       operand *tmp = right;
7083       right = left;
7084       left = tmp;
7085     }
7086
7087   /* if result = right then exchange them */
7088   if (sameRegs (AOP (result), AOP (right)))
7089     {
7090       operand *tmp = right;
7091       right = left;
7092       left = tmp;
7093     }
7094
7095   /* if right is bit then exchange them */
7096   if (AOP_TYPE (right) == AOP_CRY &&
7097       AOP_TYPE (left) != AOP_CRY)
7098     {
7099       operand *tmp = right;
7100       right = left;
7101       left = tmp;
7102     }
7103   if (AOP_TYPE (right) == AOP_LIT)
7104     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7105
7106   size = AOP_SIZE (result);
7107
7108   // if(bit ^ yy)
7109   // xx = bit ^ yy;
7110   if (AOP_TYPE (left) == AOP_CRY)
7111     {
7112       if (AOP_TYPE (right) == AOP_LIT)
7113         {
7114           // c = bit & literal;
7115           if (lit >> 1)
7116             {
7117               // lit>>1  != 0 => result = 1
7118               if (AOP_TYPE (result) == AOP_CRY)
7119                 {
7120                   if (size)
7121                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7122                   else if (ifx)
7123                     continueIfTrue (ifx);
7124                   goto release;
7125                 }
7126               emitcode ("setb", "c");
7127             }
7128           else
7129             {
7130               // lit == (0 or 1)
7131               if (lit == 0)
7132                 {
7133                   // lit == 0, result = left
7134                   if (size && sameRegs (AOP (result), AOP (left)))
7135                     goto release;
7136                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7137                 }
7138               else
7139                 {
7140                   // lit == 1, result = not(left)
7141                   if (size && sameRegs (AOP (result), AOP (left)))
7142                     {
7143                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7144                       goto release;
7145                     }
7146                   else
7147                     {
7148                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7149                       emitcode ("cpl", "c");
7150                     }
7151                 }
7152             }
7153
7154         }
7155       else
7156         {
7157           // right != literal
7158           symbol *tlbl = newiTempLabel (NULL);
7159           if (AOP_TYPE (right) == AOP_CRY)
7160             {
7161               // c = bit ^ bit;
7162               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7163             }
7164           else
7165             {
7166               int sizer = AOP_SIZE (right);
7167               // c = bit ^ val
7168               // if val>>1 != 0, result = 1
7169               emitcode ("setb", "c");
7170               while (sizer)
7171                 {
7172                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7173                   if (sizer == 1)
7174                     // test the msb of the lsb
7175                     emitcode ("anl", "a,#0xfe");
7176                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7177                   sizer--;
7178                 }
7179               // val = (0,1)
7180               emitcode ("rrc", "a");
7181             }
7182           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7183           emitcode ("cpl", "c");
7184           emitcode ("", "%05d$:", (tlbl->key + 100));
7185         }
7186       // bit = c
7187       // val = c
7188       if (size)
7189         outBitC (result);
7190       // if(bit | ...)
7191       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7192         genIfxJump (ifx, "c", left, right, result);
7193       goto release;
7194     }
7195
7196   /* if left is same as result */
7197   if (sameRegs (AOP (result), AOP (left)))
7198     {
7199       for (; size--; offset++)
7200         {
7201           if (AOP_TYPE (right) == AOP_LIT)
7202             {
7203               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7204               if (bytelit == 0)
7205                 {
7206                   /* dummy read of volatile operand */
7207                   if (isOperandVolatile (left, FALSE))
7208                     MOVA (aopGet (left, offset, FALSE, FALSE));
7209                   else
7210                     continue;
7211                 }
7212               else if (IS_AOP_PREG (left))
7213                 {
7214                   MOVA (aopGet (left, offset, FALSE, TRUE));
7215                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7216                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7217                 }
7218               else
7219                 {
7220                   emitcode ("xrl", "%s,%s",
7221                             aopGet (left, offset, FALSE, TRUE),
7222                             aopGet (right, offset, FALSE, FALSE));
7223                 }
7224             }
7225           else
7226             {
7227               if (AOP_TYPE (left) == AOP_ACC)
7228                 {
7229                   if (offset)
7230                     emitcode("mov", "a,b");
7231                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7232                 }
7233               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7234                 {
7235                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7236                   MOVA (aopGet (right, offset, FALSE, FALSE));
7237                   emitcode ("xrl", "a,b");
7238                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7239                 }
7240               else if (aopGetUsesAcc (left, offset))
7241                 {
7242                   MOVA (aopGet (left, offset, FALSE, FALSE));
7243                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7244                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7245                 }
7246               else
7247                 {
7248                   MOVA (aopGet (right, offset, FALSE, FALSE));
7249                   if (IS_AOP_PREG (left))
7250                     {
7251                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7252                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7253                     }
7254                   else
7255                     emitcode ("xrl", "%s,a",
7256                               aopGet (left, offset, FALSE, TRUE));
7257                 }
7258             }
7259         }
7260     }
7261   else
7262     {
7263       // left & result in different registers
7264       if (AOP_TYPE (result) == AOP_CRY)
7265         {
7266           // result = bit
7267           // if(size), result in bit
7268           // if(!size && ifx), conditional oper: if(left ^ right)
7269           symbol *tlbl = newiTempLabel (NULL);
7270           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7271           if (size)
7272             emitcode ("setb", "c");
7273           while (sizer--)
7274             {
7275               if ((AOP_TYPE (right) == AOP_LIT) &&
7276                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7277                 {
7278                   MOVA (aopGet (left, offset, FALSE, FALSE));
7279                 }
7280               else
7281                 {
7282                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7283                     if (offset)
7284                       emitcode("mov", "a,b");
7285                     emitcode ("xrl", "a,%s",
7286                               aopGet (right, offset, FALSE, FALSE));
7287                   } else {
7288                     MOVA (aopGet (right, offset, FALSE, FALSE));
7289                     emitcode ("xrl", "a,%s",
7290                               aopGet (left, offset, FALSE, FALSE));
7291                   }
7292                 }
7293               emitcode ("jnz", "%05d$", tlbl->key + 100);
7294               offset++;
7295             }
7296           if (size)
7297             {
7298               CLRC;
7299               emitcode ("", "%05d$:", tlbl->key + 100);
7300               outBitC (result);
7301             }
7302           else if (ifx)
7303             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7304         }
7305       else
7306         {
7307           for (; (size--); offset++)
7308             {
7309               // normal case
7310               // result = left & right
7311               if (AOP_TYPE (right) == AOP_LIT)
7312                 {
7313                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7314                   if (bytelit == 0)
7315                     {
7316                       aopPut (result,
7317                               aopGet (left, offset, FALSE, FALSE),
7318                               offset,
7319                               isOperandVolatile (result, FALSE));
7320                       continue;
7321                     }
7322                 }
7323               // faster than result <- left, anl result,right
7324               // and better if result is SFR
7325               if (AOP_TYPE (left) == AOP_ACC)
7326                 {
7327                   if (offset)
7328                     emitcode("mov", "a,b");
7329                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7330                 }
7331               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7332                 {
7333                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7334                   MOVA (aopGet (right, offset, FALSE, FALSE));
7335                   emitcode ("xrl", "a,b");
7336                 }
7337               else if (aopGetUsesAcc (left, offset))
7338                 {
7339                   MOVA (aopGet (left, offset, FALSE, FALSE));
7340                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7341                 }
7342               else
7343                 {
7344                   MOVA (aopGet (right, offset, FALSE, FALSE));
7345                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7346                 }
7347               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7348             }
7349         }
7350     }
7351
7352 release:
7353   freeAsmop (result, NULL, ic, TRUE);
7354   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7355   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7356 }
7357
7358 /*-----------------------------------------------------------------*/
7359 /* genInline - write the inline code out                           */
7360 /*-----------------------------------------------------------------*/
7361 static void
7362 genInline (iCode * ic)
7363 {
7364   char *buffer, *bp, *bp1;
7365
7366   D(emitcode (";     genInline",""));
7367
7368   _G.inLine += (!options.asmpeep);
7369
7370   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
7371   strcpy (buffer, IC_INLINE (ic));
7372
7373   /* emit each line as a code */
7374   while (*bp)
7375     {
7376       if (*bp == '\n')
7377         {
7378           *bp++ = '\0';
7379           emitcode (bp1, "");
7380           bp1 = bp;
7381         }
7382       else
7383         {
7384           /* Add \n for labels, not dirs such as c:\mydir */
7385           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7386             {
7387               bp++;
7388               *bp = '\0';
7389               bp++;
7390               emitcode (bp1, "");
7391               bp1 = bp;
7392             }
7393           else
7394             bp++;
7395         }
7396     }
7397   if (bp1 != bp)
7398     emitcode (bp1, "");
7399   /*     emitcode("",buffer); */
7400   _G.inLine -= (!options.asmpeep);
7401 }
7402
7403 /*-----------------------------------------------------------------*/
7404 /* genRRC - rotate right with carry                                */
7405 /*-----------------------------------------------------------------*/
7406 static void
7407 genRRC (iCode * ic)
7408 {
7409   operand *left, *result;
7410   int size, offset = 0;
7411   char *l;
7412
7413   D(emitcode (";     genRRC",""));
7414
7415   /* rotate right with carry */
7416   left = IC_LEFT (ic);
7417   result = IC_RESULT (ic);
7418   aopOp (left, ic, FALSE);
7419   aopOp (result, ic, FALSE);
7420
7421   /* move it to the result */
7422   size = AOP_SIZE (result);
7423   offset = size - 1;
7424   if (size == 1) { /* special case for 1 byte */
7425       l = aopGet (left, offset, FALSE, FALSE);
7426       MOVA (l);
7427       emitcode ("rr", "a");
7428       goto release;
7429   }
7430   /* no need to clear carry, bit7 will be written later */
7431   while (size--)
7432     {
7433       l = aopGet (left, offset, FALSE, FALSE);
7434       MOVA (l);
7435       emitcode ("rrc", "a");
7436       if (AOP_SIZE (result) > 1)
7437         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
7438     }
7439   /* now we need to put the carry into the
7440      highest order byte of the result */
7441   if (AOP_SIZE (result) > 1)
7442     {
7443       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7444       MOVA (l);
7445     }
7446   emitcode ("mov", "acc.7,c");
7447  release:
7448   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
7449   freeAsmop (result, NULL, ic, TRUE);
7450   freeAsmop (left, NULL, ic, TRUE);
7451 }
7452
7453 /*-----------------------------------------------------------------*/
7454 /* genRLC - generate code for rotate left with carry               */
7455 /*-----------------------------------------------------------------*/
7456 static void
7457 genRLC (iCode * ic)
7458 {
7459   operand *left, *result;
7460   int size, offset = 0;
7461   char *l;
7462
7463   D(emitcode (";     genRLC",""));
7464
7465   /* rotate right with carry */
7466   left = IC_LEFT (ic);
7467   result = IC_RESULT (ic);
7468   aopOp (left, ic, FALSE);
7469   aopOp (result, ic, FALSE);
7470
7471   /* move it to the result */
7472   size = AOP_SIZE (result);
7473   offset = 0;
7474   if (size--)
7475     {
7476       l = aopGet (left, offset, FALSE, FALSE);
7477       MOVA (l);
7478       if (size == 0) { /* special case for 1 byte */
7479               emitcode("rl","a");
7480               goto release;
7481       }
7482       emitcode("rlc","a"); /* bit0 will be written later */
7483       if (AOP_SIZE (result) > 1)
7484         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7485       while (size--)
7486         {
7487           l = aopGet (left, offset, FALSE, FALSE);
7488           MOVA (l);
7489           emitcode ("rlc", "a");
7490           if (AOP_SIZE (result) > 1)
7491             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7492         }
7493     }
7494   /* now we need to put the carry into the
7495      highest order byte of the result */
7496   if (AOP_SIZE (result) > 1)
7497     {
7498       l = aopGet (result, 0, FALSE, FALSE);
7499       MOVA (l);
7500     }
7501   emitcode ("mov", "acc.0,c");
7502  release:
7503   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7504   freeAsmop (result, NULL, ic, TRUE);
7505   freeAsmop (left, NULL, ic, TRUE);
7506 }
7507
7508 /*-----------------------------------------------------------------*/
7509 /* genGetHbit - generates code get highest order bit               */
7510 /*-----------------------------------------------------------------*/
7511 static void
7512 genGetHbit (iCode * ic)
7513 {
7514   operand *left, *result;
7515
7516   D(emitcode (";     genGetHbit",""));
7517
7518   left = IC_LEFT (ic);
7519   result = IC_RESULT (ic);
7520   aopOp (left, ic, FALSE);
7521   aopOp (result, ic, FALSE);
7522
7523   /* get the highest order byte into a */
7524   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7525   if (AOP_TYPE (result) == AOP_CRY)
7526     {
7527       emitcode ("rlc", "a");
7528       outBitC (result);
7529     }
7530   else
7531     {
7532       emitcode ("rl", "a");
7533       emitcode ("anl", "a,#0x01");
7534       outAcc (result);
7535     }
7536
7537   freeAsmop (result, NULL, ic, TRUE);
7538   freeAsmop (left, NULL, ic, TRUE);
7539 }
7540
7541 /*-----------------------------------------------------------------*/
7542 /* genGetAbit - generates code get a single bit                    */
7543 /*-----------------------------------------------------------------*/
7544 static void
7545 genGetAbit (iCode * ic)
7546 {
7547   operand *left, *right, *result;
7548   int shCount;
7549
7550   D(emitcode (";     genGetAbit",""));
7551
7552   left = IC_LEFT (ic);
7553   right = IC_RIGHT (ic);
7554   result = IC_RESULT (ic);
7555   aopOp (left, ic, FALSE);
7556   aopOp (right, ic, FALSE);
7557   aopOp (result, ic, FALSE);
7558
7559   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7560
7561   /* get the needed byte into a */
7562   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7563   shCount %= 8;
7564   if (AOP_TYPE (result) == AOP_CRY)
7565     {
7566       if ((shCount) == 7)
7567           emitcode ("rlc", "a");
7568       else if ((shCount) == 0)
7569           emitcode ("rrc", "a");
7570       else
7571           emitcode ("mov", "c,acc[%d]", shCount);
7572       outBitC (result);
7573     }
7574   else
7575     {
7576       switch (shCount)
7577         {
7578         case 2:
7579           emitcode ("rr", "a");
7580           //fallthrough
7581         case 1:
7582           emitcode ("rr", "a");
7583           //fallthrough
7584         case 0:
7585           emitcode ("anl", "a,#0x01");
7586           break;
7587         case 3:
7588         case 5:
7589           emitcode ("mov", "c,acc[%d]", shCount);
7590           emitcode ("clr", "a");
7591           emitcode ("rlc", "a");
7592           break;
7593         case 4:
7594           emitcode ("swap", "a");
7595           emitcode ("anl", "a,#0x01");
7596           break;
7597         case 6:
7598           emitcode ("rl", "a");
7599           //fallthrough
7600         case 7:
7601           emitcode ("rl", "a");
7602           emitcode ("anl", "a,#0x01");
7603           break;
7604         }
7605       outAcc (result);
7606     }
7607
7608   freeAsmop (result, NULL, ic, TRUE);
7609   freeAsmop (right, NULL, ic, TRUE);
7610   freeAsmop (left, NULL, ic, TRUE);
7611 }
7612
7613 /*-----------------------------------------------------------------*/
7614 /* genGetByte - generates code get a single byte                   */
7615 /*-----------------------------------------------------------------*/
7616 static void
7617 genGetByte (iCode * ic)
7618 {
7619   operand *left, *right, *result;
7620   int offset;
7621
7622   D(emitcode (";     genGetByte",""));
7623
7624   left = IC_LEFT (ic);
7625   right = IC_RIGHT (ic);
7626   result = IC_RESULT (ic);
7627   aopOp (left, ic, FALSE);
7628   aopOp (right, ic, FALSE);
7629   aopOp (result, ic, FALSE);
7630
7631   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7632   aopPut (result,
7633           aopGet (left, offset, FALSE, FALSE),
7634           0,
7635           isOperandVolatile (result, FALSE));
7636
7637   freeAsmop (result, NULL, ic, TRUE);
7638   freeAsmop (right, NULL, ic, TRUE);
7639   freeAsmop (left, NULL, ic, TRUE);
7640 }
7641
7642 /*-----------------------------------------------------------------*/
7643 /* genGetWord - generates code get two bytes                       */
7644 /*-----------------------------------------------------------------*/
7645 static void
7646 genGetWord (iCode * ic)
7647 {
7648   operand *left, *right, *result;
7649   int offset;
7650
7651   D(emitcode (";     genGetWord",""));
7652
7653   left = IC_LEFT (ic);
7654   right = IC_RIGHT (ic);
7655   result = IC_RESULT (ic);
7656   aopOp (left, ic, FALSE);
7657   aopOp (right, ic, FALSE);
7658   aopOp (result, ic, FALSE);
7659
7660   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7661   aopPut (result,
7662           aopGet (left, offset, FALSE, FALSE),
7663           0,
7664           isOperandVolatile (result, FALSE));
7665   aopPut (result,
7666           aopGet (left, offset+1, FALSE, FALSE),
7667           1,
7668           isOperandVolatile (result, FALSE));
7669
7670   freeAsmop (result, NULL, ic, TRUE);
7671   freeAsmop (right, NULL, ic, TRUE);
7672   freeAsmop (left, NULL, ic, TRUE);
7673 }
7674
7675 /*-----------------------------------------------------------------*/
7676 /* genSwap - generates code to swap nibbles or bytes               */
7677 /*-----------------------------------------------------------------*/
7678 static void
7679 genSwap (iCode * ic)
7680 {
7681   operand *left, *result;
7682
7683   D(emitcode (";     genSwap",""));
7684
7685   left = IC_LEFT (ic);
7686   result = IC_RESULT (ic);
7687   aopOp (left, ic, FALSE);
7688   aopOp (result, ic, FALSE);
7689
7690   switch (AOP_SIZE (left))
7691     {
7692     case 1: /* swap nibbles in byte */
7693       MOVA (aopGet (left, 0, FALSE, FALSE));
7694       emitcode ("swap", "a");
7695       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7696       break;
7697     case 2: /* swap bytes in word */
7698       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7699         {
7700           MOVA (aopGet (left, 0, FALSE, FALSE));
7701           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7702                   0, isOperandVolatile (result, FALSE));
7703           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7704         }
7705       else if (operandsEqu (left, result))
7706         {
7707           char * reg = "a";
7708           bool pushedB = FALSE, leftInB = FALSE;
7709
7710           MOVA (aopGet (left, 0, FALSE, FALSE));
7711           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7712             {
7713               pushedB = pushB ();
7714               emitcode ("mov", "b,a");
7715               reg = "b";
7716               leftInB = TRUE;
7717             }
7718           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7719                   0, isOperandVolatile (result, FALSE));
7720           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7721
7722           if (leftInB)
7723             popB (pushedB);
7724         }
7725       else
7726         {
7727           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7728                   0, isOperandVolatile (result, FALSE));
7729           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7730                   1, isOperandVolatile (result, FALSE));
7731         }
7732       break;
7733     default:
7734       wassertl(FALSE, "unsupported SWAP operand size");
7735     }
7736
7737   freeAsmop (result, NULL, ic, TRUE);
7738   freeAsmop (left, NULL, ic, TRUE);
7739 }
7740
7741
7742 /*-----------------------------------------------------------------*/
7743 /* AccRol - rotate left accumulator by known count                 */
7744 /*-----------------------------------------------------------------*/
7745 static void
7746 AccRol (int shCount)
7747 {
7748   shCount &= 0x0007;            // shCount : 0..7
7749
7750   switch (shCount)
7751     {
7752     case 0:
7753       break;
7754     case 1:
7755       emitcode ("rl", "a");
7756       break;
7757     case 2:
7758       emitcode ("rl", "a");
7759       emitcode ("rl", "a");
7760       break;
7761     case 3:
7762       emitcode ("swap", "a");
7763       emitcode ("rr", "a");
7764       break;
7765     case 4:
7766       emitcode ("swap", "a");
7767       break;
7768     case 5:
7769       emitcode ("swap", "a");
7770       emitcode ("rl", "a");
7771       break;
7772     case 6:
7773       emitcode ("rr", "a");
7774       emitcode ("rr", "a");
7775       break;
7776     case 7:
7777       emitcode ("rr", "a");
7778       break;
7779     }
7780 }
7781
7782 /*-----------------------------------------------------------------*/
7783 /* AccLsh - left shift accumulator by known count                  */
7784 /*-----------------------------------------------------------------*/
7785 static void
7786 AccLsh (int shCount)
7787 {
7788   if (shCount != 0)
7789     {
7790       if (shCount == 1)
7791         emitcode ("add", "a,acc");
7792       else if (shCount == 2)
7793         {
7794           emitcode ("add", "a,acc");
7795           emitcode ("add", "a,acc");
7796         }
7797       else
7798         {
7799           /* rotate left accumulator */
7800           AccRol (shCount);
7801           /* and kill the lower order bits */
7802           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7803         }
7804     }
7805 }
7806
7807 /*-----------------------------------------------------------------*/
7808 /* AccRsh - right shift accumulator by known count                 */
7809 /*-----------------------------------------------------------------*/
7810 static void
7811 AccRsh (int shCount)
7812 {
7813   if (shCount != 0)
7814     {
7815       if (shCount == 1)
7816         {
7817           CLRC;
7818           emitcode ("rrc", "a");
7819         }
7820       else
7821         {
7822           /* rotate right accumulator */
7823           AccRol (8 - shCount);
7824           /* and kill the higher order bits */
7825           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7826         }
7827     }
7828 }
7829
7830 /*-----------------------------------------------------------------*/
7831 /* AccSRsh - signed right shift accumulator by known count                 */
7832 /*-----------------------------------------------------------------*/
7833 static void
7834 AccSRsh (int shCount)
7835 {
7836   symbol *tlbl;
7837   if (shCount != 0)
7838     {
7839       if (shCount == 1)
7840         {
7841           emitcode ("mov", "c,acc.7");
7842           emitcode ("rrc", "a");
7843         }
7844       else if (shCount == 2)
7845         {
7846           emitcode ("mov", "c,acc.7");
7847           emitcode ("rrc", "a");
7848           emitcode ("mov", "c,acc.7");
7849           emitcode ("rrc", "a");
7850         }
7851       else
7852         {
7853           tlbl = newiTempLabel (NULL);
7854           /* rotate right accumulator */
7855           AccRol (8 - shCount);
7856           /* and kill the higher order bits */
7857           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7858           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7859           emitcode ("orl", "a,#0x%02x",
7860                     (unsigned char) ~SRMask[shCount]);
7861           emitcode ("", "%05d$:", tlbl->key + 100);
7862         }
7863     }
7864 }
7865
7866 /*-----------------------------------------------------------------*/
7867 /* shiftR1Left2Result - shift right one byte from left to result   */
7868 /*-----------------------------------------------------------------*/
7869 static void
7870 shiftR1Left2Result (operand * left, int offl,
7871                     operand * result, int offr,
7872                     int shCount, int sign)
7873 {
7874   MOVA (aopGet (left, offl, FALSE, FALSE));
7875   /* shift right accumulator */
7876   if (sign)
7877     AccSRsh (shCount);
7878   else
7879     AccRsh (shCount);
7880   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7881 }
7882
7883 /*-----------------------------------------------------------------*/
7884 /* shiftL1Left2Result - shift left one byte from left to result    */
7885 /*-----------------------------------------------------------------*/
7886 static void
7887 shiftL1Left2Result (operand * left, int offl,
7888                     operand * result, int offr, int shCount)
7889 {
7890   char *l;
7891   l = aopGet (left, offl, FALSE, FALSE);
7892   MOVA (l);
7893   /* shift left accumulator */
7894   AccLsh (shCount);
7895   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7896 }
7897
7898 /*-----------------------------------------------------------------*/
7899 /* movLeft2Result - move byte from left to result                  */
7900 /*-----------------------------------------------------------------*/
7901 static void
7902 movLeft2Result (operand * left, int offl,
7903                 operand * result, int offr, int sign)
7904 {
7905   char *l;
7906   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7907     {
7908       l = aopGet (left, offl, FALSE, FALSE);
7909
7910       if (*l == '@' && (IS_AOP_PREG (result)))
7911         {
7912           emitcode ("mov", "a,%s", l);
7913           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7914         }
7915       else
7916         {
7917           if (!sign)
7918             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7919           else
7920             {
7921               /* MSB sign in acc.7 ! */
7922               if (getDataSize (left) == offl + 1)
7923                 {
7924                   MOVA (l);
7925                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7926                 }
7927             }
7928         }
7929     }
7930 }
7931
7932 /*-----------------------------------------------------------------*/
7933 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7934 /*-----------------------------------------------------------------*/
7935 static void
7936 AccAXRrl1 (char *x)
7937 {
7938   emitcode ("rrc", "a");
7939   emitcode ("xch", "a,%s", x);
7940   emitcode ("rrc", "a");
7941   emitcode ("xch", "a,%s", x);
7942 }
7943
7944 /*-----------------------------------------------------------------*/
7945 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7946 /*-----------------------------------------------------------------*/
7947 static void
7948 AccAXLrl1 (char *x)
7949 {
7950   emitcode ("xch", "a,%s", x);
7951   emitcode ("rlc", "a");
7952   emitcode ("xch", "a,%s", x);
7953   emitcode ("rlc", "a");
7954 }
7955
7956 /*-----------------------------------------------------------------*/
7957 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7958 /*-----------------------------------------------------------------*/
7959 static void
7960 AccAXLsh1 (char *x)
7961 {
7962   emitcode ("xch", "a,%s", x);
7963   emitcode ("add", "a,acc");
7964   emitcode ("xch", "a,%s", x);
7965   emitcode ("rlc", "a");
7966 }
7967
7968 /*-----------------------------------------------------------------*/
7969 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7970 /*-----------------------------------------------------------------*/
7971 static void
7972 AccAXLsh (char *x, int shCount)
7973 {
7974   switch (shCount)
7975     {
7976     case 0:
7977       break;
7978     case 1:
7979       AccAXLsh1 (x);
7980       break;
7981     case 2:
7982       AccAXLsh1 (x);
7983       AccAXLsh1 (x);
7984       break;
7985     case 3:
7986     case 4:
7987     case 5:                     // AAAAABBB:CCCCCDDD
7988
7989       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7990
7991       emitcode ("anl", "a,#0x%02x",
7992                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7993
7994       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7995
7996       AccRol (shCount);         // DDDCCCCC:BBB00000
7997
7998       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7999
8000       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8001
8002       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8003
8004       emitcode ("anl", "a,#0x%02x",
8005                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8006
8007       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8008
8009       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8010
8011       break;
8012     case 6:                     // AAAAAABB:CCCCCCDD
8013       emitcode ("anl", "a,#0x%02x",
8014                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8015       emitcode ("mov", "c,acc.0");      // c = B
8016       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8017 #if 0 // REMOVE ME
8018       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8019       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8020 #else
8021       emitcode("rrc","a");
8022       emitcode("xch","a,%s", x);
8023       emitcode("rrc","a");
8024       emitcode("mov","c,acc.0"); //<< get correct bit
8025       emitcode("xch","a,%s", x);
8026
8027       emitcode("rrc","a");
8028       emitcode("xch","a,%s", x);
8029       emitcode("rrc","a");
8030       emitcode("xch","a,%s", x);
8031 #endif
8032       break;
8033     case 7:                     // a:x <<= 7
8034
8035       emitcode ("anl", "a,#0x%02x",
8036                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8037
8038       emitcode ("mov", "c,acc.0");      // c = B
8039
8040       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8041
8042       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8043
8044       break;
8045     default:
8046       break;
8047     }
8048 }
8049
8050 /*-----------------------------------------------------------------*/
8051 /* AccAXRsh - right shift a:x known count (0..7)                   */
8052 /*-----------------------------------------------------------------*/
8053 static void
8054 AccAXRsh (char *x, int shCount)
8055 {
8056   switch (shCount)
8057     {
8058     case 0:
8059       break;
8060     case 1:
8061       CLRC;
8062       AccAXRrl1 (x);            // 0->a:x
8063
8064       break;
8065     case 2:
8066       CLRC;
8067       AccAXRrl1 (x);            // 0->a:x
8068
8069       CLRC;
8070       AccAXRrl1 (x);            // 0->a:x
8071
8072       break;
8073     case 3:
8074     case 4:
8075     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8076
8077       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8078
8079       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8080
8081       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8082
8083       emitcode ("anl", "a,#0x%02x",
8084                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8085
8086       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8087
8088       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8089
8090       emitcode ("anl", "a,#0x%02x",
8091                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8092
8093       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8094
8095       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8096
8097       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8098
8099       break;
8100     case 6:                     // AABBBBBB:CCDDDDDD
8101
8102       emitcode ("mov", "c,acc.7");
8103       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8104
8105       emitcode ("mov", "c,acc.7");
8106       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8107
8108       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8109
8110       emitcode ("anl", "a,#0x%02x",
8111                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8112
8113       break;
8114     case 7:                     // ABBBBBBB:CDDDDDDD
8115
8116       emitcode ("mov", "c,acc.7");      // c = A
8117
8118       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8119
8120       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8121
8122       emitcode ("anl", "a,#0x%02x",
8123                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8124
8125       break;
8126     default:
8127       break;
8128     }
8129 }
8130
8131 /*-----------------------------------------------------------------*/
8132 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8133 /*-----------------------------------------------------------------*/
8134 static void
8135 AccAXRshS (char *x, int shCount)
8136 {
8137   symbol *tlbl;
8138   switch (shCount)
8139     {
8140     case 0:
8141       break;
8142     case 1:
8143       emitcode ("mov", "c,acc.7");
8144       AccAXRrl1 (x);            // s->a:x
8145
8146       break;
8147     case 2:
8148       emitcode ("mov", "c,acc.7");
8149       AccAXRrl1 (x);            // s->a:x
8150
8151       emitcode ("mov", "c,acc.7");
8152       AccAXRrl1 (x);            // s->a:x
8153
8154       break;
8155     case 3:
8156     case 4:
8157     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8158
8159       tlbl = newiTempLabel (NULL);
8160       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8161
8162       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8163
8164       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8165
8166       emitcode ("anl", "a,#0x%02x",
8167                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8168
8169       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8170
8171       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8172
8173       emitcode ("anl", "a,#0x%02x",
8174                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8175
8176       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8177
8178       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8179
8180       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8181
8182       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8183       emitcode ("orl", "a,#0x%02x",
8184                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8185
8186       emitcode ("", "%05d$:", tlbl->key + 100);
8187       break;                    // SSSSAAAA:BBBCCCCC
8188
8189     case 6:                     // AABBBBBB:CCDDDDDD
8190
8191       tlbl = newiTempLabel (NULL);
8192       emitcode ("mov", "c,acc.7");
8193       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8194
8195       emitcode ("mov", "c,acc.7");
8196       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8197
8198       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8199
8200       emitcode ("anl", "a,#0x%02x",
8201                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8202
8203       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8204       emitcode ("orl", "a,#0x%02x",
8205                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8206
8207       emitcode ("", "%05d$:", tlbl->key + 100);
8208       break;
8209     case 7:                     // ABBBBBBB:CDDDDDDD
8210
8211       tlbl = newiTempLabel (NULL);
8212       emitcode ("mov", "c,acc.7");      // c = A
8213
8214       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8215
8216       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8217
8218       emitcode ("anl", "a,#0x%02x",
8219                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8220
8221       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8222       emitcode ("orl", "a,#0x%02x",
8223                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8224
8225       emitcode ("", "%05d$:", tlbl->key + 100);
8226       break;
8227     default:
8228       break;
8229     }
8230 }
8231
8232 /*-----------------------------------------------------------------*/
8233 /* shiftL2Left2Result - shift left two bytes from left to result   */
8234 /*-----------------------------------------------------------------*/
8235 static void
8236 shiftL2Left2Result (operand * left, int offl,
8237                     operand * result, int offr, int shCount)
8238 {
8239   char * x;
8240   bool pushedB = FALSE;
8241   bool usedB = FALSE;
8242
8243   if (sameRegs (AOP (result), AOP (left)) &&
8244       ((offl + MSB16) == offr))
8245     {
8246       /* don't crash result[offr] */
8247       MOVA (aopGet (left, offl, FALSE, FALSE));
8248       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8249       x = aopGet (result, offr, FALSE, FALSE);
8250     }
8251   else if (aopGetUsesAcc (result, offr))
8252     {
8253       movLeft2Result (left, offl, result, offr, 0);
8254       pushedB = pushB ();
8255       usedB = TRUE;
8256       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8257       MOVA (aopGet (result, offr, FALSE, FALSE));
8258       emitcode ("xch", "a,b");
8259       x = "b";
8260     }
8261   else
8262     {
8263       movLeft2Result (left, offl, result, offr, 0);
8264       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8265       x = aopGet (result, offr, FALSE, FALSE);
8266     }
8267   /* ax << shCount (x = lsb(result)) */
8268   AccAXLsh (x, shCount);
8269   if (usedB)
8270     {
8271       emitcode ("xch", "a,b");
8272       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8273       aopPut (result, "b", offr + MSB16, isOperandVolatile (result, FALSE));
8274       popB (pushedB);
8275     }
8276   else
8277     {
8278       aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8279     }
8280 }
8281
8282
8283 /*-----------------------------------------------------------------*/
8284 /* shiftR2Left2Result - shift right two bytes from left to result  */
8285 /*-----------------------------------------------------------------*/
8286 static void
8287 shiftR2Left2Result (operand * left, int offl,
8288                     operand * result, int offr,
8289                     int shCount, int sign)
8290 {
8291   char * x;
8292   bool pushedB = FALSE;
8293   bool usedB = FALSE;
8294
8295   if (sameRegs (AOP (result), AOP (left)) &&
8296       ((offl + MSB16) == offr))
8297     {
8298       /* don't crash result[offr] */
8299       MOVA (aopGet (left, offl, FALSE, FALSE));
8300       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8301       x = aopGet (result, offr, FALSE, FALSE);
8302     }
8303   else if (aopGetUsesAcc (result, offr))
8304     {
8305       movLeft2Result (left, offl, result, offr, 0);
8306       pushedB = pushB ();
8307       usedB = TRUE;
8308       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8309       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8310       x = "b";
8311     }
8312   else
8313     {
8314       movLeft2Result (left, offl, result, offr, 0);
8315       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8316       x = aopGet (result, offr, FALSE, FALSE);
8317     }
8318   /* a:x >> shCount (x = lsb(result)) */
8319   if (sign)
8320     AccAXRshS (x, shCount);
8321   else
8322     AccAXRsh (x, shCount);
8323   if (usedB)
8324     {
8325       emitcode ("xch", "a,b");
8326       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8327       emitcode ("xch", "a,b");
8328       popB (pushedB);
8329     }
8330   if (getDataSize (result) > 1)
8331     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8332 }
8333
8334 /*-----------------------------------------------------------------*/
8335 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8336 /*-----------------------------------------------------------------*/
8337 static void
8338 shiftLLeftOrResult (operand * left, int offl,
8339                     operand * result, int offr, int shCount)
8340 {
8341   MOVA (aopGet (left, offl, FALSE, FALSE));
8342   /* shift left accumulator */
8343   AccLsh (shCount);
8344   /* or with result */
8345   if (aopGetUsesAcc (result, offr))
8346     {
8347       emitcode ("xch", "a,b");
8348       MOVA (aopGet (result, offr, FALSE, FALSE));
8349       emitcode ("orl", "a,b");
8350     }
8351   else
8352     {
8353       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8354     }
8355   /* back to result */
8356   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8357 }
8358
8359 /*-----------------------------------------------------------------*/
8360 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8361 /*-----------------------------------------------------------------*/
8362 static void
8363 shiftRLeftOrResult (operand * left, int offl,
8364                     operand * result, int offr, int shCount)
8365 {
8366   MOVA (aopGet (left, offl, FALSE, FALSE));
8367   /* shift right accumulator */
8368   AccRsh (shCount);
8369   /* or with result */
8370   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8371   /* back to result */
8372   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8373 }
8374
8375 /*-----------------------------------------------------------------*/
8376 /* genlshOne - left shift a one byte quantity by known count       */
8377 /*-----------------------------------------------------------------*/
8378 static void
8379 genlshOne (operand * result, operand * left, int shCount)
8380 {
8381   D(emitcode (";     genlshOne",""));
8382
8383   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8384 }
8385
8386 /*-----------------------------------------------------------------*/
8387 /* genlshTwo - left shift two bytes by known amount != 0           */
8388 /*-----------------------------------------------------------------*/
8389 static void
8390 genlshTwo (operand * result, operand * left, int shCount)
8391 {
8392   int size;
8393
8394   D(emitcode (";     genlshTwo",""));
8395
8396   size = getDataSize (result);
8397
8398   /* if shCount >= 8 */
8399   if (shCount >= 8)
8400     {
8401       shCount -= 8;
8402
8403       if (size > 1)
8404         {
8405           if (shCount)
8406             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8407           else
8408             movLeft2Result (left, LSB, result, MSB16, 0);
8409         }
8410       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8411     }
8412
8413   /*  1 <= shCount <= 7 */
8414   else
8415     {
8416       if (size == 1)
8417         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8418       else
8419         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8420     }
8421 }
8422
8423 /*-----------------------------------------------------------------*/
8424 /* shiftLLong - shift left one long from left to result            */
8425 /* offl = LSB or MSB16                                             */
8426 /*-----------------------------------------------------------------*/
8427 static void
8428 shiftLLong (operand * left, operand * result, int offr)
8429 {
8430   char *l;
8431   int size = AOP_SIZE (result);
8432
8433   if (size >= LSB + offr)
8434     {
8435       l = aopGet (left, LSB, FALSE, FALSE);
8436       MOVA (l);
8437       emitcode ("add", "a,acc");
8438       if (sameRegs (AOP (left), AOP (result)) &&
8439           size >= MSB16 + offr && offr != LSB)
8440         emitcode ("xch", "a,%s",
8441                   aopGet (left, LSB + offr, FALSE, FALSE));
8442       else
8443         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
8444     }
8445
8446   if (size >= MSB16 + offr)
8447     {
8448       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8449         {
8450           l = aopGet (left, MSB16, FALSE, FALSE);
8451           MOVA (l);
8452         }
8453       emitcode ("rlc", "a");
8454       if (sameRegs (AOP (left), AOP (result)) &&
8455           size >= MSB24 + offr && offr != LSB)
8456         emitcode ("xch", "a,%s",
8457                   aopGet (left, MSB16 + offr, FALSE, FALSE));
8458       else
8459         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
8460     }
8461
8462   if (size >= MSB24 + offr)
8463     {
8464       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8465         {
8466           l = aopGet (left, MSB24, FALSE, FALSE);
8467           MOVA (l);
8468         }
8469       emitcode ("rlc", "a");
8470       if (sameRegs (AOP (left), AOP (result)) &&
8471           size >= MSB32 + offr && offr != LSB)
8472         emitcode ("xch", "a,%s",
8473                   aopGet (left, MSB24 + offr, FALSE, FALSE));
8474       else
8475         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
8476     }
8477
8478   if (size > MSB32 + offr)
8479     {
8480       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8481         {
8482           l = aopGet (left, MSB32, FALSE, FALSE);
8483           MOVA (l);
8484         }
8485       emitcode ("rlc", "a");
8486       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
8487     }
8488   if (offr != LSB)
8489     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8490 }
8491
8492 /*-----------------------------------------------------------------*/
8493 /* genlshFour - shift four byte by a known amount != 0             */
8494 /*-----------------------------------------------------------------*/
8495 static void
8496 genlshFour (operand * result, operand * left, int shCount)
8497 {
8498   int size;
8499
8500   D(emitcode (";     genlshFour",""));
8501
8502   size = AOP_SIZE (result);
8503
8504   /* if shifting more that 3 bytes */
8505   if (shCount >= 24)
8506     {
8507       shCount -= 24;
8508       if (shCount)
8509         /* lowest order of left goes to the highest
8510            order of the destination */
8511         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8512       else
8513         movLeft2Result (left, LSB, result, MSB32, 0);
8514       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8515       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8516       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
8517       return;
8518     }
8519
8520   /* more than two bytes */
8521   else if (shCount >= 16)
8522     {
8523       /* lower order two bytes goes to higher order two bytes */
8524       shCount -= 16;
8525       /* if some more remaining */
8526       if (shCount)
8527         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8528       else
8529         {
8530           movLeft2Result (left, MSB16, result, MSB32, 0);
8531           movLeft2Result (left, LSB, result, MSB24, 0);
8532         }
8533       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8534       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8535       return;
8536     }
8537
8538   /* if more than 1 byte */
8539   else if (shCount >= 8)
8540     {
8541       /* lower order three bytes goes to higher order  three bytes */
8542       shCount -= 8;
8543       if (size == 2)
8544         {
8545           if (shCount)
8546             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8547           else
8548             movLeft2Result (left, LSB, result, MSB16, 0);
8549         }
8550       else
8551         {                       /* size = 4 */
8552           if (shCount == 0)
8553             {
8554               movLeft2Result (left, MSB24, result, MSB32, 0);
8555               movLeft2Result (left, MSB16, result, MSB24, 0);
8556               movLeft2Result (left, LSB, result, MSB16, 0);
8557               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8558             }
8559           else if (shCount == 1)
8560             shiftLLong (left, result, MSB16);
8561           else
8562             {
8563               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8564               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8565               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8566               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8567             }
8568         }
8569     }
8570
8571   /* 1 <= shCount <= 7 */
8572   else if (shCount <= 2)
8573     {
8574       shiftLLong (left, result, LSB);
8575       if (shCount == 2)
8576         shiftLLong (result, result, LSB);
8577     }
8578   /* 3 <= shCount <= 7, optimize */
8579   else
8580     {
8581       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8582       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8583       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8584     }
8585 }
8586
8587 /*-----------------------------------------------------------------*/
8588 /* genLeftShiftLiteral - left shifting by known count              */
8589 /*-----------------------------------------------------------------*/
8590 static void
8591 genLeftShiftLiteral (operand * left,
8592                      operand * right,
8593                      operand * result,
8594                      iCode * ic)
8595 {
8596   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8597   int size;
8598
8599   D(emitcode (";     genLeftShiftLiteral",""));
8600
8601   freeAsmop (right, NULL, ic, TRUE);
8602
8603   aopOp (left, ic, FALSE);
8604   aopOp (result, ic, FALSE);
8605
8606   size = getSize (operandType (result));
8607
8608 #if VIEW_SIZE
8609   emitcode ("; shift left ", "result %d, left %d", size,
8610             AOP_SIZE (left));
8611 #endif
8612
8613   /* I suppose that the left size >= result size */
8614   if (shCount == 0)
8615     {
8616       while (size--)
8617         {
8618           movLeft2Result (left, size, result, size, 0);
8619         }
8620     }
8621
8622   else if (shCount >= (size * 8))
8623     while (size--)
8624       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
8625   else
8626     {
8627       switch (size)
8628         {
8629         case 1:
8630           genlshOne (result, left, shCount);
8631           break;
8632
8633         case 2:
8634           genlshTwo (result, left, shCount);
8635           break;
8636
8637         case 4:
8638           genlshFour (result, left, shCount);
8639           break;
8640         default:
8641           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8642                   "*** ack! mystery literal shift!\n");
8643           break;
8644         }
8645     }
8646   freeAsmop (result, NULL, ic, TRUE);
8647   freeAsmop (left, NULL, ic, TRUE);
8648 }
8649
8650 /*-----------------------------------------------------------------*/
8651 /* genLeftShift - generates code for left shifting                 */
8652 /*-----------------------------------------------------------------*/
8653 static void
8654 genLeftShift (iCode * ic)
8655 {
8656   operand *left, *right, *result;
8657   int size, offset;
8658   char *l;
8659   symbol *tlbl, *tlbl1;
8660   bool pushedB;
8661
8662   D(emitcode (";     genLeftShift",""));
8663
8664   right = IC_RIGHT (ic);
8665   left = IC_LEFT (ic);
8666   result = IC_RESULT (ic);
8667
8668   aopOp (right, ic, FALSE);
8669
8670   /* if the shift count is known then do it
8671      as efficiently as possible */
8672   if (AOP_TYPE (right) == AOP_LIT)
8673     {
8674       genLeftShiftLiteral (left, right, result, ic);
8675       return;
8676     }
8677
8678   /* shift count is unknown then we have to form
8679      a loop get the loop count in B : Note: we take
8680      only the lower order byte since shifting
8681      more that 32 bits make no sense anyway, ( the
8682      largest size of an object can be only 32 bits ) */
8683
8684   pushedB = pushB ();
8685   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8686   emitcode ("inc", "b");
8687   freeAsmop (right, NULL, ic, TRUE);
8688   aopOp (left, ic, FALSE);
8689   aopOp (result, ic, FALSE);
8690
8691   /* now move the left to the result if they are not the same */
8692   if (!sameRegs (AOP (left), AOP (result)) &&
8693       AOP_SIZE (result) > 1)
8694     {
8695
8696       size = AOP_SIZE (result);
8697       offset = 0;
8698       while (size--)
8699         {
8700           l = aopGet (left, offset, FALSE, TRUE);
8701           if (*l == '@' && (IS_AOP_PREG (result)))
8702             {
8703
8704               emitcode ("mov", "a,%s", l);
8705               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8706             }
8707           else
8708             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8709           offset++;
8710         }
8711     }
8712
8713   tlbl = newiTempLabel (NULL);
8714   size = AOP_SIZE (result);
8715   offset = 0;
8716   tlbl1 = newiTempLabel (NULL);
8717
8718   /* if it is only one byte then */
8719   if (size == 1)
8720     {
8721       symbol *tlbl1 = newiTempLabel (NULL);
8722
8723       l = aopGet (left, 0, FALSE, FALSE);
8724       MOVA (l);
8725       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8726       emitcode ("", "%05d$:", tlbl->key + 100);
8727       emitcode ("add", "a,acc");
8728       emitcode ("", "%05d$:", tlbl1->key + 100);
8729       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8730       popB (pushedB);
8731       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8732       goto release;
8733     }
8734
8735   reAdjustPreg (AOP (result));
8736
8737   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8738   emitcode ("", "%05d$:", tlbl->key + 100);
8739   l = aopGet (result, offset, FALSE, FALSE);
8740   MOVA (l);
8741   emitcode ("add", "a,acc");
8742   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8743   while (--size)
8744     {
8745       l = aopGet (result, offset, FALSE, FALSE);
8746       MOVA (l);
8747       emitcode ("rlc", "a");
8748       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8749     }
8750   reAdjustPreg (AOP (result));
8751
8752   emitcode ("", "%05d$:", tlbl1->key + 100);
8753   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8754   popB (pushedB);
8755 release:
8756   freeAsmop (result, NULL, ic, TRUE);
8757   freeAsmop (left, NULL, ic, TRUE);
8758 }
8759
8760 /*-----------------------------------------------------------------*/
8761 /* genrshOne - right shift a one byte quantity by known count      */
8762 /*-----------------------------------------------------------------*/
8763 static void
8764 genrshOne (operand * result, operand * left,
8765            int shCount, int sign)
8766 {
8767   D(emitcode (";     genrshOne",""));
8768
8769   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8770 }
8771
8772 /*-----------------------------------------------------------------*/
8773 /* genrshTwo - right shift two bytes by known amount != 0          */
8774 /*-----------------------------------------------------------------*/
8775 static void
8776 genrshTwo (operand * result, operand * left,
8777            int shCount, int sign)
8778 {
8779   D(emitcode (";     genrshTwo",""));
8780
8781   /* if shCount >= 8 */
8782   if (shCount >= 8)
8783     {
8784       shCount -= 8;
8785       if (shCount)
8786         shiftR1Left2Result (left, MSB16, result, LSB,
8787                             shCount, sign);
8788       else
8789         movLeft2Result (left, MSB16, result, LSB, sign);
8790       addSign (result, MSB16, sign);
8791     }
8792
8793   /*  1 <= shCount <= 7 */
8794   else
8795     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8796 }
8797
8798 /*-----------------------------------------------------------------*/
8799 /* shiftRLong - shift right one long from left to result           */
8800 /* offl = LSB or MSB16                                             */
8801 /*-----------------------------------------------------------------*/
8802 static void
8803 shiftRLong (operand * left, int offl,
8804             operand * result, int sign)
8805 {
8806   bool useSameRegs = regsInCommon (left, result);
8807
8808   if (useSameRegs && offl>1)
8809     {
8810       // we are in big trouble, but this shouldn't happen
8811       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8812     }
8813
8814   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8815
8816   if (offl==MSB16)
8817     {
8818       // shift is > 8
8819       if (sign)
8820             {
8821           emitcode ("rlc", "a");
8822           emitcode ("subb", "a,acc");
8823           if (useSameRegs && sameReg (AOP (left), MSB32, AOP (result), MSB32))
8824                     {
8825               emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8826                     }
8827           else
8828                     {
8829               aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8830               MOVA (aopGet (left, MSB32, FALSE, FALSE));
8831                     }
8832             }
8833           else
8834             {
8835           aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8836             }
8837     }
8838
8839   if (!sign)
8840     {
8841       emitcode ("clr", "c");
8842     }
8843   else
8844     {
8845       emitcode ("mov", "c,acc.7");
8846     }
8847
8848   emitcode ("rrc", "a");
8849
8850   if (useSameRegs && offl==MSB16 &&
8851       sameReg (AOP (left), MSB24, AOP (result), MSB32-offl))
8852     {
8853       emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8854     }
8855   else
8856     {
8857       aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8858       MOVA (aopGet (left, MSB24, FALSE, FALSE));
8859     }
8860
8861   emitcode ("rrc", "a");
8862   if (useSameRegs && offl==1 &&
8863       sameReg (AOP (left), MSB16, AOP (result), MSB24-offl))
8864     {
8865       emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8866     }
8867   else
8868     {
8869       aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8870       MOVA (aopGet (left, MSB16, FALSE, FALSE));
8871     }
8872   emitcode ("rrc", "a");
8873   if (offl != LSB)
8874     {
8875       aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8876     }
8877   else
8878     {
8879       if (useSameRegs &&
8880           sameReg (AOP (left), LSB, AOP (result), MSB16-offl))
8881         {
8882           emitcode ("xch", "a,%s",aopGet (left, LSB, FALSE, FALSE));
8883         }
8884       else
8885         {
8886           aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8887           MOVA (aopGet (left, LSB, FALSE, FALSE));
8888             }
8889       emitcode ("rrc", "a");
8890       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8891     }
8892 }
8893
8894 /*-----------------------------------------------------------------*/
8895 /* genrshFour - shift four byte by a known amount != 0             */
8896 /*-----------------------------------------------------------------*/
8897 static void
8898 genrshFour (operand * result, operand * left,
8899             int shCount, int sign)
8900 {
8901   D(emitcode (";     genrshFour",""));
8902
8903   /* if shifting more that 3 bytes */
8904   if (shCount >= 24)
8905     {
8906       shCount -= 24;
8907       if (shCount)
8908         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8909       else
8910         movLeft2Result (left, MSB32, result, LSB, sign);
8911       addSign (result, MSB16, sign);
8912     }
8913   else if (shCount >= 16)
8914     {
8915       shCount -= 16;
8916       if (shCount)
8917         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8918       else
8919         {
8920           movLeft2Result (left, MSB24, result, LSB, 0);
8921           movLeft2Result (left, MSB32, result, MSB16, sign);
8922         }
8923       addSign (result, MSB24, sign);
8924     }
8925   else if (shCount >= 8)
8926     {
8927       shCount -= 8;
8928       if (shCount == 1)
8929         shiftRLong (left, MSB16, result, sign);
8930       else if (shCount == 0)
8931         {
8932           movLeft2Result (left, MSB16, result, LSB, 0);
8933           movLeft2Result (left, MSB24, result, MSB16, 0);
8934           movLeft2Result (left, MSB32, result, MSB24, sign);
8935           addSign (result, MSB32, sign);
8936         }
8937       else
8938         {
8939           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8940           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8941           /* the last shift is signed */
8942           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8943           addSign (result, MSB32, sign);
8944         }
8945     }
8946   else
8947     {                           /* 1 <= shCount <= 7 */
8948       if (shCount <= 2)
8949         {
8950           shiftRLong (left, LSB, result, sign);
8951           if (shCount == 2)
8952             shiftRLong (result, LSB, result, sign);
8953         }
8954       else
8955         {
8956           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8957           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8958           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8959         }
8960     }
8961 }
8962
8963 /*-----------------------------------------------------------------*/
8964 /* genRightShiftLiteral - right shifting by known count            */
8965 /*-----------------------------------------------------------------*/
8966 static void
8967 genRightShiftLiteral (operand * left,
8968                       operand * right,
8969                       operand * result,
8970                       iCode * ic,
8971                       int sign)
8972 {
8973   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8974   int size;
8975
8976   D(emitcode (";     genRightShiftLiteral",""));
8977
8978   freeAsmop (right, NULL, ic, TRUE);
8979
8980   aopOp (left, ic, FALSE);
8981   aopOp (result, ic, FALSE);
8982
8983 #if VIEW_SIZE
8984   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8985             AOP_SIZE (left));
8986 #endif
8987
8988   size = getDataSize (left);
8989   /* test the LEFT size !!! */
8990
8991   /* I suppose that the left size >= result size */
8992   if (shCount == 0)
8993     {
8994       size = getDataSize (result);
8995       while (size--)
8996         movLeft2Result (left, size, result, size, 0);
8997     }
8998
8999   else if (shCount >= (size * 8))
9000     {
9001       if (sign) {
9002         /* get sign in acc.7 */
9003         MOVA (aopGet (left, size - 1, FALSE, FALSE));
9004       }
9005       addSign (result, LSB, sign);
9006     }
9007   else
9008     {
9009       switch (size)
9010         {
9011         case 1:
9012           genrshOne (result, left, shCount, sign);
9013           break;
9014
9015         case 2:
9016           genrshTwo (result, left, shCount, sign);
9017           break;
9018
9019         case 4:
9020           genrshFour (result, left, shCount, sign);
9021           break;
9022         default:
9023           break;
9024         }
9025     }
9026   freeAsmop (result, NULL, ic, TRUE);
9027   freeAsmop (left, NULL, ic, TRUE);
9028 }
9029
9030 /*-----------------------------------------------------------------*/
9031 /* genSignedRightShift - right shift of signed number              */
9032 /*-----------------------------------------------------------------*/
9033 static void
9034 genSignedRightShift (iCode * ic)
9035 {
9036   operand *right, *left, *result;
9037   int size, offset;
9038   char *l;
9039   symbol *tlbl, *tlbl1;
9040   bool pushedB;
9041
9042   D(emitcode (";     genSignedRightShift",""));
9043
9044   /* we do it the hard way put the shift count in b
9045      and loop thru preserving the sign */
9046
9047   right = IC_RIGHT (ic);
9048   left = IC_LEFT (ic);
9049   result = IC_RESULT (ic);
9050
9051   aopOp (right, ic, FALSE);
9052
9053
9054   if (AOP_TYPE (right) == AOP_LIT)
9055     {
9056       genRightShiftLiteral (left, right, result, ic, 1);
9057       return;
9058     }
9059   /* shift count is unknown then we have to form
9060      a loop get the loop count in B : Note: we take
9061      only the lower order byte since shifting
9062      more that 32 bits make no sense anyway, ( the
9063      largest size of an object can be only 32 bits ) */
9064
9065   pushedB = pushB ();
9066   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
9067   emitcode ("inc", "b");
9068   freeAsmop (right, NULL, ic, TRUE);
9069   aopOp (left, ic, FALSE);
9070   aopOp (result, ic, FALSE);
9071
9072   /* now move the left to the result if they are not the
9073      same */
9074   if (!sameRegs (AOP (left), AOP (result)) &&
9075       AOP_SIZE (result) > 1)
9076     {
9077
9078       size = AOP_SIZE (result);
9079       offset = 0;
9080       while (size--)
9081         {
9082           l = aopGet (left, offset, FALSE, TRUE);
9083           if (*l == '@' && IS_AOP_PREG (result))
9084             {
9085
9086               emitcode ("mov", "a,%s", l);
9087               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9088             }
9089           else
9090             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
9091           offset++;
9092         }
9093     }
9094
9095   /* mov the highest order bit to OVR */
9096   tlbl = newiTempLabel (NULL);
9097   tlbl1 = newiTempLabel (NULL);
9098
9099   size = AOP_SIZE (result);
9100   offset = size - 1;
9101   MOVA (aopGet (left, offset, FALSE, FALSE));
9102   emitcode ("rlc", "a");
9103   emitcode ("mov", "ov,c");
9104   /* if it is only one byte then */
9105   if (size == 1)
9106     {
9107       l = aopGet (left, 0, FALSE, FALSE);
9108       MOVA (l);
9109       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9110       emitcode ("", "%05d$:", tlbl->key + 100);
9111       emitcode ("mov", "c,ov");
9112       emitcode ("rrc", "a");
9113       emitcode ("", "%05d$:", tlbl1->key + 100);
9114       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9115       popB (pushedB);
9116       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9117       goto release;
9118     }
9119
9120   reAdjustPreg (AOP (result));
9121   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9122   emitcode ("", "%05d$:", tlbl->key + 100);
9123   emitcode ("mov", "c,ov");
9124   while (size--)
9125     {
9126       l = aopGet (result, offset, FALSE, FALSE);
9127       MOVA (l);
9128       emitcode ("rrc", "a");
9129       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9130     }
9131   reAdjustPreg (AOP (result));
9132   emitcode ("", "%05d$:", tlbl1->key + 100);
9133   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9134   popB (pushedB);
9135
9136 release:
9137   freeAsmop (result, NULL, ic, TRUE);
9138   freeAsmop (left, NULL, ic, TRUE);
9139 }
9140
9141 /*-----------------------------------------------------------------*/
9142 /* genRightShift - generate code for right shifting                */
9143 /*-----------------------------------------------------------------*/
9144 static void
9145 genRightShift (iCode * ic)
9146 {
9147   operand *right, *left, *result;
9148   sym_link *letype;
9149   int size, offset;
9150   char *l;
9151   symbol *tlbl, *tlbl1;
9152   bool pushedB;
9153
9154   D(emitcode (";     genRightShift",""));
9155
9156   /* if signed then we do it the hard way preserve the
9157      sign bit moving it inwards */
9158   letype = getSpec (operandType (IC_LEFT (ic)));
9159
9160   if (!SPEC_USIGN (letype))
9161     {
9162       genSignedRightShift (ic);
9163       return;
9164     }
9165
9166   /* signed & unsigned types are treated the same : i.e. the
9167      signed is NOT propagated inwards : quoting from the
9168      ANSI - standard : "for E1 >> E2, is equivalent to division
9169      by 2**E2 if unsigned or if it has a non-negative value,
9170      otherwise the result is implementation defined ", MY definition
9171      is that the sign does not get propagated */
9172
9173   right = IC_RIGHT (ic);
9174   left = IC_LEFT (ic);
9175   result = IC_RESULT (ic);
9176
9177   aopOp (right, ic, FALSE);
9178
9179   /* if the shift count is known then do it
9180      as efficiently as possible */
9181   if (AOP_TYPE (right) == AOP_LIT)
9182     {
9183       genRightShiftLiteral (left, right, result, ic, 0);
9184       return;
9185     }
9186
9187   /* shift count is unknown then we have to form
9188      a loop get the loop count in B : Note: we take
9189      only the lower order byte since shifting
9190      more that 32 bits make no sense anyway, ( the
9191      largest size of an object can be only 32 bits ) */
9192
9193   pushedB = pushB ();
9194   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
9195   emitcode ("inc", "b");
9196   freeAsmop (right, NULL, ic, TRUE);
9197   aopOp (left, ic, FALSE);
9198   aopOp (result, ic, FALSE);
9199
9200   /* now move the left to the result if they are not the
9201      same */
9202   if (!sameRegs (AOP (left), AOP (result)) &&
9203       AOP_SIZE (result) > 1)
9204     {
9205
9206       size = AOP_SIZE (result);
9207       offset = 0;
9208       while (size--)
9209         {
9210           l = aopGet (left, offset, FALSE, TRUE);
9211           if (*l == '@' && IS_AOP_PREG (result))
9212             {
9213
9214               emitcode ("mov", "a,%s", l);
9215               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9216             }
9217           else
9218             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
9219           offset++;
9220         }
9221     }
9222
9223   tlbl = newiTempLabel (NULL);
9224   tlbl1 = newiTempLabel (NULL);
9225   size = AOP_SIZE (result);
9226   offset = size - 1;
9227
9228   /* if it is only one byte then */
9229   if (size == 1)
9230     {
9231       l = aopGet (left, 0, FALSE, FALSE);
9232       MOVA (l);
9233       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9234       emitcode ("", "%05d$:", tlbl->key + 100);
9235       CLRC;
9236       emitcode ("rrc", "a");
9237       emitcode ("", "%05d$:", tlbl1->key + 100);
9238       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9239       popB (pushedB);
9240       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9241       goto release;
9242     }
9243
9244   reAdjustPreg (AOP (result));
9245   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9246   emitcode ("", "%05d$:", tlbl->key + 100);
9247   CLRC;
9248   while (size--)
9249     {
9250       l = aopGet (result, offset, FALSE, FALSE);
9251       MOVA (l);
9252       emitcode ("rrc", "a");
9253       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9254     }
9255   reAdjustPreg (AOP (result));
9256
9257   emitcode ("", "%05d$:", tlbl1->key + 100);
9258   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9259   popB (pushedB);
9260
9261 release:
9262   freeAsmop (result, NULL, ic, TRUE);
9263   freeAsmop (left, NULL, ic, TRUE);
9264 }
9265
9266 /*-----------------------------------------------------------------*/
9267 /* emitPtrByteGet - emits code to get a byte into A through a      */
9268 /*                  pointer register (R0, R1, or DPTR). The        */
9269 /*                  original value of A can be preserved in B.     */
9270 /*-----------------------------------------------------------------*/
9271 static void
9272 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9273 {
9274   switch (p_type)
9275     {
9276     case IPOINTER:
9277     case POINTER:
9278       if (preserveAinB)
9279         emitcode ("mov", "b,a");
9280       emitcode ("mov", "a,@%s", rname);
9281       break;
9282
9283     case PPOINTER:
9284       if (preserveAinB)
9285         emitcode ("mov", "b,a");
9286       emitcode ("movx", "a,@%s", rname);
9287       break;
9288
9289     case FPOINTER:
9290       if (preserveAinB)
9291         emitcode ("mov", "b,a");
9292       emitcode ("movx", "a,@dptr");
9293       break;
9294
9295     case CPOINTER:
9296       if (preserveAinB)
9297         emitcode ("mov", "b,a");
9298       emitcode ("clr", "a");
9299       emitcode ("movc", "a,@a+dptr");
9300       break;
9301
9302     case GPOINTER:
9303       if (preserveAinB)
9304         {
9305           emitcode ("push", "b");
9306           emitcode ("push", "acc");
9307         }
9308       emitcode ("lcall", "__gptrget");
9309       if (preserveAinB)
9310         emitcode ("pop", "b");
9311       break;
9312     }
9313 }
9314
9315 /*-----------------------------------------------------------------*/
9316 /* emitPtrByteSet - emits code to set a byte from src through a    */
9317 /*                  pointer register (R0, R1, or DPTR).            */
9318 /*-----------------------------------------------------------------*/
9319 static void
9320 emitPtrByteSet (char *rname, int p_type, char *src)
9321 {
9322   switch (p_type)
9323     {
9324     case IPOINTER:
9325     case POINTER:
9326       if (*src=='@')
9327         {
9328           MOVA (src);
9329           emitcode ("mov", "@%s,a", rname);
9330         }
9331       else
9332         emitcode ("mov", "@%s,%s", rname, src);
9333       break;
9334
9335     case PPOINTER:
9336       MOVA (src);
9337       emitcode ("movx", "@%s,a", rname);
9338       break;
9339
9340     case FPOINTER:
9341       MOVA (src);
9342       emitcode ("movx", "@dptr,a");
9343       break;
9344
9345     case GPOINTER:
9346       MOVA (src);
9347       emitcode ("lcall", "__gptrput");
9348       break;
9349     }
9350 }
9351
9352 /*-----------------------------------------------------------------*/
9353 /* genUnpackBits - generates code for unpacking bits               */
9354 /*-----------------------------------------------------------------*/
9355 static void
9356 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9357 {
9358   int offset = 0;       /* result byte offset */
9359   int rsize;            /* result size */
9360   int rlen = 0;         /* remaining bitfield length */
9361   sym_link *etype;      /* bitfield type information */
9362   int blen;             /* bitfield length */
9363   int bstr;             /* bitfield starting bit within byte */
9364   char buffer[10];
9365
9366   D(emitcode (";     genUnpackBits",""));
9367
9368   etype = getSpec (operandType (result));
9369   rsize = getSize (operandType (result));
9370   blen = SPEC_BLEN (etype);
9371   bstr = SPEC_BSTR (etype);
9372
9373   if (ifx && blen <= 8)
9374     {
9375       emitPtrByteGet (rname, ptype, FALSE);
9376       if (blen == 1)
9377         {
9378           SNPRINTF (buffer, sizeof(buffer),
9379                     "acc.%d", bstr);
9380           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9381         }
9382       else
9383         {
9384           if (blen < 8)
9385             emitcode ("anl", "a,#0x%02x",
9386                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9387           genIfxJump (ifx, "a", NULL, NULL, NULL);
9388         }
9389       return;
9390     }
9391   wassert (!ifx);
9392
9393   /* If the bitfield length is less than a byte */
9394   if (blen < 8)
9395     {
9396       emitPtrByteGet (rname, ptype, FALSE);
9397       AccRol (8 - bstr);
9398       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9399       if (!SPEC_USIGN (etype))
9400         {
9401           /* signed bitfield */
9402           symbol *tlbl = newiTempLabel (NULL);
9403
9404           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9405           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9406           emitcode ("", "%05d$:", tlbl->key + 100);
9407         }
9408       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9409       goto finish;
9410     }
9411
9412   /* Bit field did not fit in a byte. Copy all
9413      but the partial byte at the end.  */
9414   for (rlen=blen;rlen>=8;rlen-=8)
9415     {
9416       emitPtrByteGet (rname, ptype, FALSE);
9417       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9418       if (rlen>8)
9419         emitcode ("inc", "%s", rname);
9420     }
9421
9422   /* Handle the partial byte at the end */
9423   if (rlen)
9424     {
9425       emitPtrByteGet (rname, ptype, FALSE);
9426       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9427       if (!SPEC_USIGN (etype))
9428         {
9429           /* signed bitfield */
9430           symbol *tlbl = newiTempLabel (NULL);
9431
9432           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9433           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9434           emitcode ("", "%05d$:", tlbl->key + 100);
9435         }
9436       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9437     }
9438
9439 finish:
9440   if (offset < rsize)
9441     {
9442       char *source;
9443
9444       if (SPEC_USIGN (etype))
9445         source = zero;
9446       else
9447         {
9448           /* signed bitfield: sign extension with 0x00 or 0xff */
9449           emitcode ("rlc", "a");
9450           emitcode ("subb", "a,acc");
9451
9452           source = "a";
9453         }
9454       rsize -= offset;
9455       while (rsize--)
9456         aopPut (result, source, offset++, isOperandVolatile (result, FALSE));
9457     }
9458 }
9459
9460
9461 /*-----------------------------------------------------------------*/
9462 /* genDataPointerGet - generates code when ptr offset is known     */
9463 /*-----------------------------------------------------------------*/
9464 static void
9465 genDataPointerGet (operand * left,
9466                    operand * result,
9467                    iCode * ic)
9468 {
9469   char *l;
9470   char buffer[256];
9471   int size, offset = 0;
9472
9473   D(emitcode (";     genDataPointerGet",""));
9474
9475   aopOp (result, ic, TRUE);
9476
9477   /* get the string representation of the name */
9478   l = aopGet (left, 0, FALSE, TRUE);
9479   size = AOP_SIZE (result);
9480   while (size--)
9481     {
9482       if (offset)
9483         sprintf (buffer, "(%s + %d)", l + 1, offset);
9484       else
9485         sprintf (buffer, "%s", l + 1);
9486       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
9487     }
9488
9489   freeAsmop (result, NULL, ic, TRUE);
9490   freeAsmop (left, NULL, ic, TRUE);
9491 }
9492
9493 /*-----------------------------------------------------------------*/
9494 /* genNearPointerGet - emitcode for near pointer fetch             */
9495 /*-----------------------------------------------------------------*/
9496 static void
9497 genNearPointerGet (operand * left,
9498                    operand * result,
9499                    iCode * ic,
9500                    iCode * pi,
9501                    iCode * ifx)
9502 {
9503   asmop *aop = NULL;
9504   regs *preg = NULL;
9505   char *rname;
9506   sym_link *rtype, *retype;
9507   sym_link *ltype = operandType (left);
9508   char buffer[80];
9509
9510   D(emitcode (";     genNearPointerGet",""));
9511
9512   rtype = operandType (result);
9513   retype = getSpec (rtype);
9514
9515   aopOp (left, ic, FALSE);
9516
9517   /* if left is rematerialisable and
9518      result is not bitfield variable type and
9519      the left is pointer to data space i.e
9520      lower 128 bytes of space */
9521   if (AOP_TYPE (left) == AOP_IMMD &&
9522       !IS_BITFIELD (retype) &&
9523       DCL_TYPE (ltype) == POINTER)
9524     {
9525       genDataPointerGet (left, result, ic);
9526       return;
9527     }
9528
9529  /* if the value is already in a pointer register
9530      then don't need anything more */
9531   if (!AOP_INPREG (AOP (left)))
9532     {
9533       if (IS_AOP_PREG (left))
9534         {
9535           // Aha, it is a pointer, just in disguise.
9536           rname = aopGet (left, 0, FALSE, FALSE);
9537           if (*rname != '@')
9538             {
9539               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9540                       __FILE__, __LINE__);
9541             }
9542           else
9543             {
9544               // Expected case.
9545               emitcode ("mov", "a%s,%s", rname + 1, rname);
9546               rname++;  // skip the '@'.
9547             }
9548         }
9549       else
9550         {
9551           /* otherwise get a free pointer register */
9552           aop = newAsmop (0);
9553           preg = getFreePtr (ic, &aop, FALSE);
9554           emitcode ("mov", "%s,%s",
9555                     preg->name,
9556                     aopGet (left, 0, FALSE, TRUE));
9557           rname = preg->name;
9558         }
9559     }
9560   else
9561     rname = aopGet (left, 0, FALSE, FALSE);
9562
9563   //aopOp (result, ic, FALSE);
9564   aopOp (result, ic, result?TRUE:FALSE);
9565
9566   /* if bitfield then unpack the bits */
9567   if (IS_BITFIELD (retype))
9568     genUnpackBits (result, rname, POINTER, ifx);
9569   else
9570     {
9571       /* we have can just get the values */
9572       int size = AOP_SIZE (result);
9573       int offset = 0;
9574
9575       while (size--)
9576         {
9577           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9578             {
9579
9580               emitcode ("mov", "a,@%s", rname);
9581               if (!ifx)
9582               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9583             }
9584           else
9585             {
9586               sprintf (buffer, "@%s", rname);
9587               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
9588             }
9589           offset++;
9590           if (size || pi)
9591             emitcode ("inc", "%s", rname);
9592         }
9593     }
9594
9595   /* now some housekeeping stuff */
9596   if (aop)       /* we had to allocate for this iCode */
9597     {
9598       if (pi) { /* post increment present */
9599         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9600       }
9601       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9602     }
9603   else
9604     {
9605       /* we did not allocate which means left
9606          already in a pointer register, then
9607          if size > 0 && this could be used again
9608          we have to point it back to where it
9609          belongs */
9610       if ((AOP_SIZE (result) > 1 &&
9611            !OP_SYMBOL (left)->remat &&
9612            (OP_SYMBOL (left)->liveTo > ic->seq ||
9613             ic->depth)) &&
9614           !pi)
9615         {
9616           int size = AOP_SIZE (result) - 1;
9617           while (size--)
9618             emitcode ("dec", "%s", rname);
9619         }
9620     }
9621
9622   if (ifx && !ifx->generated)
9623     {
9624       genIfxJump (ifx, "a", left, NULL, result);
9625     }
9626
9627   /* done */
9628   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9629   freeAsmop (left, NULL, ic, TRUE);
9630   if (pi) pi->generated = 1;
9631 }
9632
9633 /*-----------------------------------------------------------------*/
9634 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9635 /*-----------------------------------------------------------------*/
9636 static void
9637 genPagedPointerGet (operand * left,
9638                     operand * result,
9639                     iCode * ic,
9640                     iCode *pi,
9641                     iCode *ifx)
9642 {
9643   asmop *aop = NULL;
9644   regs *preg = NULL;
9645   char *rname;
9646   sym_link *rtype, *retype;
9647
9648   D(emitcode (";     genPagedPointerGet",""));
9649
9650   rtype = operandType (result);
9651   retype = getSpec (rtype);
9652
9653   aopOp (left, ic, FALSE);
9654
9655   /* if the value is already in a pointer register
9656      then don't need anything more */
9657   if (!AOP_INPREG (AOP (left)))
9658     {
9659       /* otherwise get a free pointer register */
9660       aop = newAsmop (0);
9661       preg = getFreePtr (ic, &aop, FALSE);
9662       emitcode ("mov", "%s,%s",
9663                 preg->name,
9664                 aopGet (left, 0, FALSE, TRUE));
9665       rname = preg->name;
9666     }
9667   else
9668     rname = aopGet (left, 0, FALSE, FALSE);
9669
9670   aopOp (result, ic, FALSE);
9671
9672   /* if bitfield then unpack the bits */
9673   if (IS_BITFIELD (retype))
9674     genUnpackBits (result, rname, PPOINTER, ifx);
9675   else
9676     {
9677       /* we have can just get the values */
9678       int size = AOP_SIZE (result);
9679       int offset = 0;
9680
9681       while (size--)
9682         {
9683
9684           emitcode ("movx", "a,@%s", rname);
9685           if (!ifx)
9686           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9687
9688           offset++;
9689
9690           if (size || pi)
9691             emitcode ("inc", "%s", rname);
9692         }
9693     }
9694
9695   /* now some housekeeping stuff */
9696   if (aop) /* we had to allocate for this iCode */
9697     {
9698       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9699       freeAsmop (NULL, aop, ic, TRUE);
9700     }
9701   else
9702     {
9703       /* we did not allocate which means left
9704          already in a pointer register, then
9705          if size > 0 && this could be used again
9706          we have to point it back to where it
9707          belongs */
9708       if ((AOP_SIZE (result) > 1 &&
9709            !OP_SYMBOL (left)->remat &&
9710            (OP_SYMBOL (left)->liveTo > ic->seq ||
9711             ic->depth)) &&
9712           !pi)
9713         {
9714           int size = AOP_SIZE (result) - 1;
9715           while (size--)
9716             emitcode ("dec", "%s", rname);
9717         }
9718     }
9719
9720   if (ifx && !ifx->generated)
9721     {
9722       genIfxJump (ifx, "a", left, NULL, result);
9723     }
9724
9725   /* done */
9726   freeAsmop (result, NULL, ic, TRUE);
9727   freeAsmop (left, NULL, ic, TRUE);
9728   if (pi) pi->generated = 1;
9729 }
9730
9731 /*--------------------------------------------------------------------*/
9732 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
9733 /*--------------------------------------------------------------------*/
9734 static void
9735 loadDptrFromOperand (operand *op, bool loadBToo)
9736 {
9737   if (AOP_TYPE (op) != AOP_STR)
9738     {
9739       /* if this is rematerializable */
9740       if (AOP_TYPE (op) == AOP_IMMD)
9741         {
9742           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
9743           if (loadBToo)
9744             {
9745               if (AOP(op)->aopu.aop_immd.from_cast_remat)
9746                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
9747               else
9748                 {
9749                   wassertl(FALSE, "need pointerCode");
9750                   emitcode ("", "; mov b,???");
9751                   /* genPointerGet and genPointerSet originally did different
9752                   ** things for this case. Both seem wrong.
9753                   ** from genPointerGet:
9754                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
9755                   ** from genPointerSet:
9756                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
9757                   */
9758                 }
9759             }
9760         }
9761       else if (AOP_TYPE (op) == AOP_DPTR)
9762         {
9763           if (loadBToo)
9764             {
9765               MOVA (aopGet (op, 0, FALSE, FALSE));
9766               emitcode ("push", "acc");
9767               MOVA (aopGet (op, 1, FALSE, FALSE));
9768               emitcode ("push", "acc");
9769               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9770               emitcode ("pop", "dph");
9771               emitcode ("pop", "dpl");
9772             }
9773           else
9774             {
9775               MOVA (aopGet (op, 0, FALSE, FALSE));
9776               emitcode ("push", "acc");
9777               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9778               emitcode ("pop", "dpl");
9779             }
9780         }
9781       else
9782         {                       /* we need to get it byte by byte */
9783           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9784           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9785           if (loadBToo)
9786             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9787         }
9788     }
9789 }
9790
9791 /*-----------------------------------------------------------------*/
9792 /* genFarPointerGet - gget value from far space                    */
9793 /*-----------------------------------------------------------------*/
9794 static void
9795 genFarPointerGet (operand * left,
9796                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9797 {
9798   int size, offset;
9799   sym_link *retype = getSpec (operandType (result));
9800
9801   D(emitcode (";     genFarPointerGet",""));
9802
9803   aopOp (left, ic, FALSE);
9804   loadDptrFromOperand (left, FALSE);
9805
9806   /* so dptr now contains the address */
9807   aopOp (result, ic, FALSE);
9808
9809   /* if bit then unpack */
9810   if (IS_BITFIELD (retype))
9811     genUnpackBits (result, "dptr", FPOINTER, ifx);
9812   else
9813     {
9814       size = AOP_SIZE (result);
9815       offset = 0;
9816
9817       while (size--)
9818         {
9819           emitcode ("movx", "a,@dptr");
9820           if (!ifx)
9821             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9822           if (size || pi)
9823             emitcode ("inc", "dptr");
9824         }
9825     }
9826
9827   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9828     {
9829     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9830     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9831     pi->generated = 1;
9832   }
9833
9834   if (ifx && !ifx->generated)
9835     {
9836       genIfxJump (ifx, "a", left, NULL, result);
9837     }
9838
9839   freeAsmop (result, NULL, ic, TRUE);
9840   freeAsmop (left, NULL, ic, TRUE);
9841 }
9842
9843 /*-----------------------------------------------------------------*/
9844 /* genCodePointerGet - gget value from code space                  */
9845 /*-----------------------------------------------------------------*/
9846 static void
9847 genCodePointerGet (operand * left,
9848                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9849 {
9850   int size, offset;
9851   sym_link *retype = getSpec (operandType (result));
9852
9853   D(emitcode (";     genCodePointerGet",""));
9854
9855   aopOp (left, ic, FALSE);
9856   loadDptrFromOperand (left, FALSE);
9857
9858   /* so dptr now contains the address */
9859   aopOp (result, ic, FALSE);
9860
9861   /* if bit then unpack */
9862   if (IS_BITFIELD (retype))
9863     genUnpackBits (result, "dptr", CPOINTER, ifx);
9864   else
9865     {
9866       size = AOP_SIZE (result);
9867       offset = 0;
9868
9869       while (size--)
9870         {
9871           emitcode ("clr", "a");
9872           emitcode ("movc", "a,@a+dptr");
9873           if (!ifx)
9874             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9875           if (size || pi)
9876             emitcode ("inc", "dptr");
9877         }
9878     }
9879
9880   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9881     {
9882     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9883     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9884     pi->generated = 1;
9885   }
9886
9887   if (ifx && !ifx->generated)
9888     {
9889       genIfxJump (ifx, "a", left, NULL, result);
9890     }
9891
9892   freeAsmop (result, NULL, ic, TRUE);
9893   freeAsmop (left, NULL, ic, TRUE);
9894 }
9895
9896 /*-----------------------------------------------------------------*/
9897 /* genGenPointerGet - gget value from generic pointer space        */
9898 /*-----------------------------------------------------------------*/
9899 static void
9900 genGenPointerGet (operand * left,
9901                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9902 {
9903   int size, offset;
9904   sym_link *retype = getSpec (operandType (result));
9905
9906   D(emitcode (";     genGenPointerGet",""));
9907
9908   aopOp (left, ic, FALSE);
9909   loadDptrFromOperand (left, TRUE);
9910
9911   /* so dptr know contains the address */
9912   aopOp (result, ic, FALSE);
9913
9914   /* if bit then unpack */
9915   if (IS_BITFIELD (retype))
9916     genUnpackBits (result, "dptr", GPOINTER, ifx);
9917   else
9918     {
9919       size = AOP_SIZE (result);
9920       offset = 0;
9921
9922       while (size--)
9923         {
9924           emitcode ("lcall", "__gptrget");
9925           if (!ifx)
9926           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9927           if (size || pi)
9928             emitcode ("inc", "dptr");
9929         }
9930     }
9931
9932   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9933     {
9934     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9935     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9936     pi->generated = 1;
9937   }
9938
9939   if (ifx && !ifx->generated)
9940     {
9941       genIfxJump (ifx, "a", left, NULL, result);
9942     }
9943
9944   freeAsmop (result, NULL, ic, TRUE);
9945   freeAsmop (left, NULL, ic, TRUE);
9946 }
9947
9948 /*-----------------------------------------------------------------*/
9949 /* genPointerGet - generate code for pointer get                   */
9950 /*-----------------------------------------------------------------*/
9951 static void
9952 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9953 {
9954   operand *left, *result;
9955   sym_link *type, *etype;
9956   int p_type;
9957
9958   D(emitcode (";     genPointerGet",""));
9959
9960   left = IC_LEFT (ic);
9961   result = IC_RESULT (ic);
9962
9963   if (getSize (operandType (result))>1)
9964     ifx = NULL;
9965
9966   /* depending on the type of pointer we need to
9967      move it to the correct pointer register */
9968   type = operandType (left);
9969   etype = getSpec (type);
9970   /* if left is of type of pointer then it is simple */
9971   if (IS_PTR (type) && !IS_FUNC (type->next))
9972     p_type = DCL_TYPE (type);
9973   else
9974     {
9975       /* we have to go by the storage class */
9976       p_type = PTR_TYPE (SPEC_OCLS (etype));
9977     }
9978
9979   /* special case when cast remat */
9980   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9981       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9982           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9983           type = operandType (left);
9984           p_type = DCL_TYPE (type);
9985   }
9986   /* now that we have the pointer type we assign
9987      the pointer values */
9988   switch (p_type)
9989     {
9990
9991     case POINTER:
9992     case IPOINTER:
9993       genNearPointerGet (left, result, ic, pi, ifx);
9994       break;
9995
9996     case PPOINTER:
9997       genPagedPointerGet (left, result, ic, pi, ifx);
9998       break;
9999
10000     case FPOINTER:
10001       genFarPointerGet (left, result, ic, pi, ifx);
10002       break;
10003
10004     case CPOINTER:
10005       genCodePointerGet (left, result, ic, pi, ifx);
10006       break;
10007
10008     case GPOINTER:
10009       genGenPointerGet (left, result, ic, pi, ifx);
10010       break;
10011     }
10012
10013 }
10014
10015
10016
10017 /*-----------------------------------------------------------------*/
10018 /* genPackBits - generates code for packed bit storage             */
10019 /*-----------------------------------------------------------------*/
10020 static void
10021 genPackBits (sym_link * etype,
10022              operand * right,
10023              char *rname, int p_type)
10024 {
10025   int offset = 0;       /* source byte offset */
10026   int rlen = 0;         /* remaining bitfield length */
10027   int blen;             /* bitfield length */
10028   int bstr;             /* bitfield starting bit within byte */
10029   int litval;           /* source literal value (if AOP_LIT) */
10030   unsigned char mask;   /* bitmask within current byte */
10031
10032   D(emitcode (";     genPackBits",""));
10033
10034   blen = SPEC_BLEN (etype);
10035   bstr = SPEC_BSTR (etype);
10036
10037   /* If the bitfield length is less than a byte */
10038   if (blen < 8)
10039     {
10040       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10041               (unsigned char) (0xFF >> (8 - bstr)));
10042
10043       if (AOP_TYPE (right) == AOP_LIT)
10044         {
10045           /* Case with a bitfield length <8 and literal source
10046           */
10047           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10048           litval <<= bstr;
10049           litval &= (~mask) & 0xff;
10050           emitPtrByteGet (rname, p_type, FALSE);
10051           if ((mask|litval)!=0xff)
10052             emitcode ("anl","a,#0x%02x", mask);
10053           if (litval)
10054             emitcode ("orl","a,#0x%02x", litval);
10055         }
10056       else
10057         {
10058           if ((blen==1) && (p_type!=GPOINTER))
10059             {
10060               /* Case with a bitfield length == 1 and no generic pointer
10061               */
10062               if (AOP_TYPE (right) == AOP_CRY)
10063                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10064               else
10065                 {
10066                   MOVA (aopGet (right, 0, FALSE, FALSE));
10067                   emitcode ("rrc","a");
10068                 }
10069               emitPtrByteGet (rname, p_type, FALSE);
10070               emitcode ("mov","acc.%d,c",bstr);
10071             }
10072           else
10073             {
10074               bool pushedB;
10075               /* Case with a bitfield length < 8 and arbitrary source
10076               */
10077               MOVA (aopGet (right, 0, FALSE, FALSE));
10078               /* shift and mask source value */
10079               AccLsh (bstr);
10080               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10081
10082               pushedB = pushB ();
10083               /* transfer A to B and get next byte */
10084               emitPtrByteGet (rname, p_type, TRUE);
10085
10086               emitcode ("anl", "a,#0x%02x", mask);
10087               emitcode ("orl", "a,b");
10088               if (p_type == GPOINTER)
10089                 emitcode ("pop", "b");
10090
10091               popB (pushedB);
10092            }
10093         }
10094
10095       emitPtrByteSet (rname, p_type, "a");
10096       return;
10097     }
10098
10099   /* Bit length is greater than 7 bits. In this case, copy  */
10100   /* all except the partial byte at the end                 */
10101   for (rlen=blen;rlen>=8;rlen-=8)
10102     {
10103       emitPtrByteSet (rname, p_type,
10104                       aopGet (right, offset++, FALSE, TRUE) );
10105       if (rlen>8)
10106         emitcode ("inc", "%s", rname);
10107     }
10108
10109   /* If there was a partial byte at the end */
10110   if (rlen)
10111     {
10112       mask = (((unsigned char) -1 << rlen) & 0xff);
10113
10114       if (AOP_TYPE (right) == AOP_LIT)
10115         {
10116           /* Case with partial byte and literal source
10117           */
10118           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10119           litval >>= (blen-rlen);
10120           litval &= (~mask) & 0xff;
10121           emitPtrByteGet (rname, p_type, FALSE);
10122           if ((mask|litval)!=0xff)
10123             emitcode ("anl","a,#0x%02x", mask);
10124           if (litval)
10125             emitcode ("orl","a,#0x%02x", litval);
10126         }
10127       else
10128         {
10129           bool pushedB;
10130           /* Case with partial byte and arbitrary source
10131           */
10132           MOVA (aopGet (right, offset++, FALSE, FALSE));
10133           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10134
10135           pushedB = pushB ();
10136           /* transfer A to B and get next byte */
10137           emitPtrByteGet (rname, p_type, TRUE);
10138
10139           emitcode ("anl", "a,#0x%02x", mask);
10140           emitcode ("orl", "a,b");
10141           if (p_type == GPOINTER)
10142             emitcode ("pop", "b");
10143
10144           popB (pushedB);
10145         }
10146       emitPtrByteSet (rname, p_type, "a");
10147     }
10148
10149 }
10150
10151
10152 /*-----------------------------------------------------------------*/
10153 /* genDataPointerSet - remat pointer to data space                 */
10154 /*-----------------------------------------------------------------*/
10155 static void
10156 genDataPointerSet (operand * right,
10157                    operand * result,
10158                    iCode * ic)
10159 {
10160   int size, offset = 0;
10161   char *l, buffer[256];
10162
10163   D(emitcode (";     genDataPointerSet",""));
10164
10165   aopOp (right, ic, FALSE);
10166
10167   l = aopGet (result, 0, FALSE, TRUE);
10168   size = AOP_SIZE (right);
10169   while (size--)
10170     {
10171       if (offset)
10172         sprintf (buffer, "(%s + %d)", l + 1, offset);
10173       else
10174         sprintf (buffer, "%s", l + 1);
10175       emitcode ("mov", "%s,%s", buffer,
10176                 aopGet (right, offset++, FALSE, FALSE));
10177     }
10178
10179   freeAsmop (result, NULL, ic, TRUE);
10180   freeAsmop (right, NULL, ic, TRUE);
10181 }
10182
10183 /*-----------------------------------------------------------------*/
10184 /* genNearPointerSet - emitcode for near pointer put                */
10185 /*-----------------------------------------------------------------*/
10186 static void
10187 genNearPointerSet (operand * right,
10188                    operand * result,
10189                    iCode * ic,
10190                    iCode * pi)
10191 {
10192   asmop *aop = NULL;
10193   regs *preg = NULL;
10194   char *rname, *l;
10195   sym_link *retype, *letype;
10196   sym_link *ptype = operandType (result);
10197
10198   D(emitcode (";     genNearPointerSet",""));
10199
10200   retype = getSpec (operandType (right));
10201   letype = getSpec (ptype);
10202   aopOp (result, ic, FALSE);
10203
10204   /* if the result is rematerializable &
10205      in data space & not a bit variable */
10206   if (AOP_TYPE (result) == AOP_IMMD &&
10207       DCL_TYPE (ptype) == POINTER &&
10208       !IS_BITVAR (retype) &&
10209       !IS_BITVAR (letype))
10210     {
10211       genDataPointerSet (right, result, ic);
10212       return;
10213     }
10214
10215   /* if the value is already in a pointer register
10216      then don't need anything more */
10217   if (!AOP_INPREG (AOP (result)))
10218     {
10219         if (
10220             //AOP_TYPE (result) == AOP_STK
10221             IS_AOP_PREG(result)
10222             )
10223         {
10224             // Aha, it is a pointer, just in disguise.
10225             rname = aopGet (result, 0, FALSE, FALSE);
10226             if (*rname != '@')
10227             {
10228                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10229                         __FILE__, __LINE__);
10230             }
10231             else
10232             {
10233                 // Expected case.
10234                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10235                 rname++;  // skip the '@'.
10236             }
10237         }
10238         else
10239         {
10240             /* otherwise get a free pointer register */
10241             aop = newAsmop (0);
10242             preg = getFreePtr (ic, &aop, FALSE);
10243             emitcode ("mov", "%s,%s",
10244                       preg->name,
10245                       aopGet (result, 0, FALSE, TRUE));
10246             rname = preg->name;
10247         }
10248     }
10249     else
10250     {
10251         rname = aopGet (result, 0, FALSE, FALSE);
10252     }
10253
10254   aopOp (right, ic, FALSE);
10255
10256   /* if bitfield then unpack the bits */
10257   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10258     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10259   else
10260     {
10261       /* we have can just get the values */
10262       int size = AOP_SIZE (right);
10263       int offset = 0;
10264
10265       while (size--)
10266         {
10267           l = aopGet (right, offset, FALSE, TRUE);
10268           if (*l == '@')
10269             {
10270               MOVA (l);
10271               emitcode ("mov", "@%s,a", rname);
10272             }
10273           else
10274             emitcode ("mov", "@%s,%s", rname, l);
10275           if (size || pi)
10276             emitcode ("inc", "%s", rname);
10277           offset++;
10278         }
10279     }
10280
10281   /* now some housekeeping stuff */
10282   if (aop) /* we had to allocate for this iCode */
10283     {
10284       if (pi)
10285         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10286       freeAsmop (NULL, aop, ic, TRUE);
10287     }
10288   else
10289     {
10290       /* we did not allocate which means left
10291          already in a pointer register, then
10292          if size > 0 && this could be used again
10293          we have to point it back to where it
10294          belongs */
10295       if ((AOP_SIZE (right) > 1 &&
10296            !OP_SYMBOL (result)->remat &&
10297            (OP_SYMBOL (result)->liveTo > ic->seq ||
10298             ic->depth)) &&
10299           !pi)
10300         {
10301           int size = AOP_SIZE (right) - 1;
10302           while (size--)
10303             emitcode ("dec", "%s", rname);
10304         }
10305     }
10306
10307   /* done */
10308   if (pi) pi->generated = 1;
10309   freeAsmop (result, NULL, ic, TRUE);
10310   freeAsmop (right, NULL, ic, TRUE);
10311 }
10312
10313 /*-----------------------------------------------------------------*/
10314 /* genPagedPointerSet - emitcode for Paged pointer put             */
10315 /*-----------------------------------------------------------------*/
10316 static void
10317 genPagedPointerSet (operand * right,
10318                     operand * result,
10319                     iCode * ic,
10320                     iCode * pi)
10321 {
10322   asmop *aop = NULL;
10323   regs *preg = NULL;
10324   char *rname, *l;
10325   sym_link *retype, *letype;
10326
10327   D(emitcode (";     genPagedPointerSet",""));
10328
10329   retype = getSpec (operandType (right));
10330   letype = getSpec (operandType (result));
10331
10332   aopOp (result, ic, FALSE);
10333
10334   /* if the value is already in a pointer register
10335      then don't need anything more */
10336   if (!AOP_INPREG (AOP (result)))
10337     {
10338       /* otherwise get a free pointer register */
10339       aop = newAsmop (0);
10340       preg = getFreePtr (ic, &aop, FALSE);
10341       emitcode ("mov", "%s,%s",
10342                 preg->name,
10343                 aopGet (result, 0, FALSE, TRUE));
10344       rname = preg->name;
10345     }
10346   else
10347     rname = aopGet (result, 0, FALSE, FALSE);
10348
10349   aopOp (right, ic, FALSE);
10350
10351   /* if bitfield then unpack the bits */
10352   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10353     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10354   else
10355     {
10356       /* we have can just get the values */
10357       int size = AOP_SIZE (right);
10358       int offset = 0;
10359
10360       while (size--)
10361         {
10362           l = aopGet (right, offset, FALSE, TRUE);
10363
10364           MOVA (l);
10365           emitcode ("movx", "@%s,a", rname);
10366
10367           if (size || pi)
10368             emitcode ("inc", "%s", rname);
10369
10370           offset++;
10371         }
10372     }
10373
10374   /* now some housekeeping stuff */
10375   if (aop) /* we had to allocate for this iCode */
10376     {
10377       if (pi)
10378         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10379       freeAsmop (NULL, aop, ic, TRUE);
10380     }
10381   else
10382     {
10383       /* we did not allocate which means left
10384          already in a pointer register, then
10385          if size > 0 && this could be used again
10386          we have to point it back to where it
10387          belongs */
10388       if (AOP_SIZE (right) > 1 &&
10389           !OP_SYMBOL (result)->remat &&
10390           (OP_SYMBOL (result)->liveTo > ic->seq ||
10391            ic->depth))
10392         {
10393           int size = AOP_SIZE (right) - 1;
10394           while (size--)
10395             emitcode ("dec", "%s", rname);
10396         }
10397     }
10398
10399   /* done */
10400   if (pi) pi->generated = 1;
10401   freeAsmop (result, NULL, ic, TRUE);
10402   freeAsmop (right, NULL, ic, TRUE);
10403 }
10404
10405 /*-----------------------------------------------------------------*/
10406 /* genFarPointerSet - set value from far space                     */
10407 /*-----------------------------------------------------------------*/
10408 static void
10409 genFarPointerSet (operand * right,
10410                   operand * result, iCode * ic, iCode * pi)
10411 {
10412   int size, offset;
10413   sym_link *retype = getSpec (operandType (right));
10414   sym_link *letype = getSpec (operandType (result));
10415
10416   D(emitcode (";     genFarPointerSet",""));
10417
10418   aopOp (result, ic, FALSE);
10419   loadDptrFromOperand (result, FALSE);
10420
10421   /* so dptr know contains the address */
10422   aopOp (right, ic, FALSE);
10423
10424   /* if bit then unpack */
10425   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10426     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10427   else
10428     {
10429       size = AOP_SIZE (right);
10430       offset = 0;
10431
10432       while (size--)
10433         {
10434           char *l = aopGet (right, offset++, FALSE, FALSE);
10435           MOVA (l);
10436           emitcode ("movx", "@dptr,a");
10437           if (size || pi)
10438             emitcode ("inc", "dptr");
10439         }
10440     }
10441   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10442     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10443     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10444     pi->generated=1;
10445   }
10446   freeAsmop (result, NULL, ic, TRUE);
10447   freeAsmop (right, NULL, ic, TRUE);
10448 }
10449
10450 /*-----------------------------------------------------------------*/
10451 /* genGenPointerSet - set value from generic pointer space         */
10452 /*-----------------------------------------------------------------*/
10453 static void
10454 genGenPointerSet (operand * right,
10455                   operand * result, iCode * ic, iCode * pi)
10456 {
10457   int size, offset;
10458   sym_link *retype = getSpec (operandType (right));
10459   sym_link *letype = getSpec (operandType (result));
10460
10461   D(emitcode (";     genGenPointerSet",""));
10462
10463   aopOp (result, ic, FALSE);
10464   loadDptrFromOperand (result, TRUE);
10465
10466   /* so dptr know contains the address */
10467   aopOp (right, ic, FALSE);
10468
10469   /* if bit then unpack */
10470   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10471     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10472   else
10473     {
10474       size = AOP_SIZE (right);
10475       offset = 0;
10476
10477       while (size--)
10478         {
10479           char *l = aopGet (right, offset++, FALSE, FALSE);
10480           MOVA (l);
10481           emitcode ("lcall", "__gptrput");
10482           if (size || pi)
10483             emitcode ("inc", "dptr");
10484         }
10485     }
10486
10487   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10488     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10489     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10490     pi->generated=1;
10491   }
10492   freeAsmop (result, NULL, ic, TRUE);
10493   freeAsmop (right, NULL, ic, TRUE);
10494 }
10495
10496 /*-----------------------------------------------------------------*/
10497 /* genPointerSet - stores the value into a pointer location        */
10498 /*-----------------------------------------------------------------*/
10499 static void
10500 genPointerSet (iCode * ic, iCode *pi)
10501 {
10502   operand *right, *result;
10503   sym_link *type, *etype;
10504   int p_type;
10505
10506   D(emitcode (";     genPointerSet",""));
10507
10508   right = IC_RIGHT (ic);
10509   result = IC_RESULT (ic);
10510
10511   /* depending on the type of pointer we need to
10512      move it to the correct pointer register */
10513   type = operandType (result);
10514   etype = getSpec (type);
10515   /* if left is of type of pointer then it is simple */
10516   if (IS_PTR (type) && !IS_FUNC (type->next))
10517     {
10518       p_type = DCL_TYPE (type);
10519     }
10520   else
10521     {
10522       /* we have to go by the storage class */
10523       p_type = PTR_TYPE (SPEC_OCLS (etype));
10524     }
10525
10526   /* special case when cast remat */
10527   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10528       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10529           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10530           type = operandType (result);
10531           p_type = DCL_TYPE (type);
10532   }
10533   /* now that we have the pointer type we assign
10534      the pointer values */
10535   switch (p_type)
10536     {
10537
10538     case POINTER:
10539     case IPOINTER:
10540       genNearPointerSet (right, result, ic, pi);
10541       break;
10542
10543     case PPOINTER:
10544       genPagedPointerSet (right, result, ic, pi);
10545       break;
10546
10547     case FPOINTER:
10548       genFarPointerSet (right, result, ic, pi);
10549       break;
10550
10551     case GPOINTER:
10552       genGenPointerSet (right, result, ic, pi);
10553       break;
10554
10555     default:
10556       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10557               "genPointerSet: illegal pointer type");
10558     }
10559
10560 }
10561
10562 /*-----------------------------------------------------------------*/
10563 /* genIfx - generate code for Ifx statement                        */
10564 /*-----------------------------------------------------------------*/
10565 static void
10566 genIfx (iCode * ic, iCode * popIc)
10567 {
10568   operand *cond = IC_COND (ic);
10569   int isbit = 0;
10570   char *dup = NULL;
10571
10572   D(emitcode (";     genIfx",""));
10573
10574   aopOp (cond, ic, FALSE);
10575
10576   /* get the value into acc */
10577   if (AOP_TYPE (cond) != AOP_CRY)
10578     toBoolean (cond);
10579   else
10580     {
10581       isbit = 1;
10582       if (AOP(cond)->aopu.aop_dir)
10583         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10584     }
10585   /* the result is now in the accumulator or a directly addressable bit */
10586   freeAsmop (cond, NULL, ic, TRUE);
10587
10588   /* if there was something to be popped then do it */
10589   if (popIc)
10590     genIpop (popIc);
10591
10592   /* if the condition is a bit variable */
10593   if (isbit && dup)
10594     genIfxJump(ic, dup, NULL, NULL, NULL);
10595   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10596     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10597   else if (isbit && !IS_ITEMP (cond))
10598     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10599   else
10600     genIfxJump (ic, "a", NULL, NULL, NULL);
10601
10602   ic->generated = 1;
10603 }
10604
10605 /*-----------------------------------------------------------------*/
10606 /* genAddrOf - generates code for address of                       */
10607 /*-----------------------------------------------------------------*/
10608 static void
10609 genAddrOf (iCode * ic)
10610 {
10611   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10612   int size, offset;
10613
10614   D(emitcode (";     genAddrOf",""));
10615
10616   aopOp (IC_RESULT (ic), ic, FALSE);
10617
10618   /* if the operand is on the stack then we
10619      need to get the stack offset of this
10620      variable */
10621   if (sym->onStack)
10622     {
10623       /* if it has an offset then we need to compute
10624          it */
10625       if (sym->stack)
10626         {
10627           emitcode ("mov", "a,%s", SYM_BP (sym));
10628           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
10629                                          ((char) (sym->stack - _G.nRegsSaved)) :
10630                                          ((char) sym->stack)) & 0xff);
10631           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10632         }
10633       else
10634         {
10635           /* we can just move _bp */
10636           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10637         }
10638       /* fill the result with zero */
10639       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10640
10641       offset = 1;
10642       while (size--)
10643         {
10644           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10645         }
10646
10647       goto release;
10648     }
10649
10650   /* object not on stack then we need the name */
10651   size = AOP_SIZE (IC_RESULT (ic));
10652   offset = 0;
10653
10654   while (size--)
10655     {
10656       char s[SDCC_NAME_MAX];
10657       if (offset)
10658         sprintf (s, "#(%s >> %d)",
10659                  sym->rname,
10660                  offset * 8);
10661       else
10662         sprintf (s, "#%s", sym->rname);
10663       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10664     }
10665
10666 release:
10667   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10668
10669 }
10670
10671 /*-----------------------------------------------------------------*/
10672 /* genFarFarAssign - assignment when both are in far space         */
10673 /*-----------------------------------------------------------------*/
10674 static void
10675 genFarFarAssign (operand * result, operand * right, iCode * ic)
10676 {
10677   int size = AOP_SIZE (right);
10678   int offset = 0;
10679   char *l;
10680
10681   D(emitcode (";     genFarFarAssign",""));
10682
10683   /* first push the right side on to the stack */
10684   while (size--)
10685     {
10686       l = aopGet (right, offset++, FALSE, FALSE);
10687       MOVA (l);
10688       emitcode ("push", "acc");
10689     }
10690
10691   freeAsmop (right, NULL, ic, FALSE);
10692   /* now assign DPTR to result */
10693   aopOp (result, ic, FALSE);
10694   size = AOP_SIZE (result);
10695   while (size--)
10696     {
10697       emitcode ("pop", "acc");
10698       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
10699     }
10700   freeAsmop (result, NULL, ic, FALSE);
10701 }
10702
10703 /*-----------------------------------------------------------------*/
10704 /* genAssign - generate code for assignment                        */
10705 /*-----------------------------------------------------------------*/
10706 static void
10707 genAssign (iCode * ic)
10708 {
10709   operand *result, *right;
10710   int size, offset;
10711   unsigned long lit = 0L;
10712
10713   D(emitcode(";     genAssign",""));
10714
10715   result = IC_RESULT (ic);
10716   right = IC_RIGHT (ic);
10717
10718   /* if they are the same */
10719   if (operandsEqu (result, right) &&
10720       !isOperandVolatile (result, FALSE) &&
10721       !isOperandVolatile (right, FALSE))
10722     return;
10723
10724   aopOp (right, ic, FALSE);
10725
10726   /* special case both in far space */
10727   if (AOP_TYPE (right) == AOP_DPTR &&
10728       IS_TRUE_SYMOP (result) &&
10729       isOperandInFarSpace (result))
10730     {
10731
10732       genFarFarAssign (result, right, ic);
10733       return;
10734     }
10735
10736   aopOp (result, ic, TRUE);
10737
10738   /* if they are the same registers */
10739   if (sameRegs (AOP (right), AOP (result)) &&
10740       !isOperandVolatile (result, FALSE) &&
10741       !isOperandVolatile (right, FALSE))
10742     goto release;
10743
10744   /* if the result is a bit */
10745   if (AOP_TYPE (result) == AOP_CRY)
10746     {
10747
10748       /* if the right size is a literal then
10749          we know what the value is */
10750       if (AOP_TYPE (right) == AOP_LIT)
10751         {
10752           if (((int) operandLitValue (right)))
10753             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10754           else
10755             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10756           goto release;
10757         }
10758
10759       /* the right is also a bit variable */
10760       if (AOP_TYPE (right) == AOP_CRY)
10761         {
10762           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10763           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10764           goto release;
10765         }
10766
10767       /* we need to or */
10768       toBoolean (right);
10769       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10770       goto release;
10771     }
10772
10773   /* bit variables done */
10774   /* general case */
10775   size = AOP_SIZE (result);
10776   offset = 0;
10777   if (AOP_TYPE (right) == AOP_LIT)
10778     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10779   if ((size > 1) &&
10780       (AOP_TYPE (result) != AOP_REG) &&
10781       (AOP_TYPE (right) == AOP_LIT) &&
10782       !IS_FLOAT (operandType (right)) &&
10783       (lit < 256L))
10784     {
10785       while ((size) && (lit))
10786         {
10787           aopPut (result,
10788                   aopGet (right, offset, FALSE, FALSE),
10789                   offset,
10790                   isOperandVolatile (result, FALSE));
10791           lit >>= 8;
10792           offset++;
10793           size--;
10794         }
10795       emitcode ("clr", "a");
10796       while (size--)
10797         {
10798           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10799           offset++;
10800         }
10801     }
10802   else
10803     {
10804       while (size--)
10805         {
10806           aopPut (result,
10807                   aopGet (right, offset, FALSE, FALSE),
10808                   offset,
10809                   isOperandVolatile (result, FALSE));
10810           offset++;
10811         }
10812     }
10813
10814 release:
10815   freeAsmop (result, NULL, ic, TRUE);
10816   freeAsmop (right, NULL, ic, TRUE);
10817 }
10818
10819 /*-----------------------------------------------------------------*/
10820 /* genJumpTab - generates code for jump table                      */
10821 /*-----------------------------------------------------------------*/
10822 static void
10823 genJumpTab (iCode * ic)
10824 {
10825   symbol *jtab,*jtablo,*jtabhi;
10826   char *l;
10827   unsigned int count;
10828
10829   D(emitcode (";     genJumpTab",""));
10830
10831   count = elementsInSet( IC_JTLABELS (ic) );
10832
10833   if( count <= 16 )
10834     {
10835       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10836          if the switch argument is in a register.
10837          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10838       /* Peephole may not convert ljmp to sjmp or ret
10839          labelIsReturnOnly & labelInRange must check
10840          currPl->ic->op != JUMPTABLE */
10841       aopOp (IC_JTCOND (ic), ic, FALSE);
10842       /* get the condition into accumulator */
10843       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10844       MOVA (l);
10845       /* multiply by three */
10846       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
10847         {
10848           emitcode ("mov", "b,#3");
10849           emitcode ("mul", "ab");
10850         }
10851       else
10852         {
10853           emitcode ("add", "a,acc");
10854           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10855         }
10856       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10857
10858       jtab = newiTempLabel (NULL);
10859       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10860       emitcode ("jmp", "@a+dptr");
10861       emitcode ("", "%05d$:", jtab->key + 100);
10862       /* now generate the jump labels */
10863       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10864            jtab = setNextItem (IC_JTLABELS (ic)))
10865         emitcode ("ljmp", "%05d$", jtab->key + 100);
10866     }
10867   else
10868     {
10869       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10870          if the switch argument is in a register.
10871          For n>6 this algorithm may be more compact */
10872       jtablo = newiTempLabel (NULL);
10873       jtabhi = newiTempLabel (NULL);
10874
10875       /* get the condition into accumulator.
10876          Using b as temporary storage, if register push/pop is needed */
10877       aopOp (IC_JTCOND (ic), ic, FALSE);
10878       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10879       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10880           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10881         {
10882           // (MB) what if B is in use???
10883           wassertl(!BINUSE, "B was in use");
10884           emitcode ("mov", "b,%s", l);
10885           l = "b";
10886         }
10887       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10888       MOVA (l);
10889       if( count <= 112 )
10890         {
10891           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10892           emitcode ("movc", "a,@a+pc");
10893           emitcode ("push", "acc");
10894
10895           MOVA (l);
10896           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10897           emitcode ("movc", "a,@a+pc");
10898           emitcode ("push", "acc");
10899         }
10900       else
10901         {
10902           /* this scales up to n<=255, but needs two more bytes
10903              and changes dptr */
10904           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10905           emitcode ("movc", "a,@a+dptr");
10906           emitcode ("push", "acc");
10907
10908           MOVA (l);
10909           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10910           emitcode ("movc", "a,@a+dptr");
10911           emitcode ("push", "acc");
10912         }
10913
10914       emitcode ("ret", "");
10915
10916       /* now generate jump table, LSB */
10917       emitcode ("", "%05d$:", jtablo->key + 100);
10918       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10919            jtab = setNextItem (IC_JTLABELS (ic)))
10920         emitcode (".db", "%05d$", jtab->key + 100);
10921
10922       /* now generate jump table, MSB */
10923       emitcode ("", "%05d$:", jtabhi->key + 100);
10924       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10925            jtab = setNextItem (IC_JTLABELS (ic)))
10926          emitcode (".db", "%05d$>>8", jtab->key + 100);
10927     }
10928 }
10929
10930 /*-----------------------------------------------------------------*/
10931 /* genCast - gen code for casting                                  */
10932 /*-----------------------------------------------------------------*/
10933 static void
10934 genCast (iCode * ic)
10935 {
10936   operand *result = IC_RESULT (ic);
10937   sym_link *ctype = operandType (IC_LEFT (ic));
10938   sym_link *rtype = operandType (IC_RIGHT (ic));
10939   operand *right = IC_RIGHT (ic);
10940   int size, offset;
10941
10942   D(emitcode(";     genCast",""));
10943
10944   /* if they are equivalent then do nothing */
10945   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10946     return;
10947
10948   aopOp (right, ic, FALSE);
10949   aopOp (result, ic, FALSE);
10950
10951   /* if the result is a bit (and not a bitfield) */
10952   // if (AOP_TYPE (result) == AOP_CRY)
10953   if (IS_BIT (OP_SYMBOL (result)->type))
10954     /* not for bitfields */
10955     {
10956       /* if the right size is a literal then
10957          we know what the value is */
10958       if (AOP_TYPE (right) == AOP_LIT)
10959         {
10960           if (((int) operandLitValue (right)))
10961             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10962           else
10963             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10964
10965           goto release;
10966         }
10967
10968       /* the right is also a bit variable */
10969       if (AOP_TYPE (right) == AOP_CRY)
10970         {
10971           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10972           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10973           goto release;
10974         }
10975
10976       /* we need to or */
10977       toBoolean (right);
10978       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10979       goto release;
10980     }
10981
10982
10983   /* if they are the same size : or less */
10984   if (AOP_SIZE (result) <= AOP_SIZE (right))
10985     {
10986
10987       /* if they are in the same place */
10988       if (sameRegs (AOP (right), AOP (result)))
10989         goto release;
10990
10991       /* if they in different places then copy */
10992       size = AOP_SIZE (result);
10993       offset = 0;
10994       while (size--)
10995         {
10996           aopPut (result,
10997                   aopGet (right, offset, FALSE, FALSE),
10998                   offset,
10999                   isOperandVolatile (result, FALSE));
11000           offset++;
11001         }
11002       goto release;
11003     }
11004
11005
11006   /* if the result is of type pointer */
11007   if (IS_PTR (ctype))
11008     {
11009
11010       int p_type;
11011       sym_link *type = operandType (right);
11012       sym_link *etype = getSpec (type);
11013
11014       /* pointer to generic pointer */
11015       if (IS_GENPTR (ctype))
11016         {
11017           if (IS_PTR (type))
11018             p_type = DCL_TYPE (type);
11019           else
11020             {
11021               if (SPEC_SCLS(etype)==S_REGISTER) {
11022                 // let's assume it is a generic pointer
11023                 p_type=GPOINTER;
11024               } else {
11025                 /* we have to go by the storage class */
11026                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11027               }
11028             }
11029
11030           /* the first two bytes are known */
11031           size = GPTRSIZE - 1;
11032           offset = 0;
11033           while (size--)
11034             {
11035               aopPut (result,
11036                       aopGet (right, offset, FALSE, FALSE),
11037                       offset,
11038                       isOperandVolatile (result, FALSE));
11039               offset++;
11040             }
11041           /* the last byte depending on type */
11042             {
11043                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11044                 char gpValStr[10];
11045
11046                 if (gpVal == -1)
11047                 {
11048                     // pointerTypeToGPByte will have bitched.
11049                     exit(1);
11050                 }
11051
11052                 sprintf(gpValStr, "#0x%x", gpVal);
11053                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
11054             }
11055           goto release;
11056         }
11057
11058       /* just copy the pointers */
11059       size = AOP_SIZE (result);
11060       offset = 0;
11061       while (size--)
11062         {
11063           aopPut (result,
11064                   aopGet (right, offset, FALSE, FALSE),
11065                   offset,
11066                   isOperandVolatile (result, FALSE));
11067           offset++;
11068         }
11069       goto release;
11070     }
11071
11072   /* so we now know that the size of destination is greater
11073      than the size of the source */
11074   /* we move to result for the size of source */
11075   size = AOP_SIZE (right);
11076   offset = 0;
11077   while (size--)
11078     {
11079       aopPut (result,
11080               aopGet (right, offset, FALSE, FALSE),
11081               offset,
11082               isOperandVolatile (result, FALSE));
11083       offset++;
11084     }
11085
11086   /* now depending on the sign of the source && destination */
11087   size = AOP_SIZE (result) - AOP_SIZE (right);
11088   /* if unsigned or not an integral type */
11089   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11090     {
11091       while (size--)
11092         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
11093     }
11094   else
11095     {
11096       /* we need to extend the sign :{ */
11097       char *l = aopGet (right, AOP_SIZE (right) - 1,
11098                         FALSE, FALSE);
11099       MOVA (l);
11100       emitcode ("rlc", "a");
11101       emitcode ("subb", "a,acc");
11102       while (size--)
11103         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
11104     }
11105
11106   /* we are done hurray !!!! */
11107
11108 release:
11109   freeAsmop (result, NULL, ic, TRUE);
11110   freeAsmop (right, NULL, ic, TRUE);
11111 }
11112
11113 /*-----------------------------------------------------------------*/
11114 /* genDjnz - generate decrement & jump if not zero instrucion      */
11115 /*-----------------------------------------------------------------*/
11116 static int
11117 genDjnz (iCode * ic, iCode * ifx)
11118 {
11119   symbol *lbl, *lbl1;
11120   if (!ifx)
11121     return 0;
11122
11123   D(emitcode (";     genDjnz",""));
11124
11125   /* if the if condition has a false label
11126      then we cannot save */
11127   if (IC_FALSE (ifx))
11128     return 0;
11129
11130   /* if the minus is not of the form
11131      a = a - 1 */
11132   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11133       !IS_OP_LITERAL (IC_RIGHT (ic)))
11134     return 0;
11135
11136   if (operandLitValue (IC_RIGHT (ic)) != 1)
11137     return 0;
11138
11139   /* if the size of this greater than one then no
11140      saving */
11141   if (getSize (operandType (IC_RESULT (ic))) > 1)
11142     return 0;
11143
11144   /* otherwise we can save BIG */
11145   lbl = newiTempLabel (NULL);
11146   lbl1 = newiTempLabel (NULL);
11147
11148   aopOp (IC_RESULT (ic), ic, FALSE);
11149
11150   if (AOP_NEEDSACC(IC_RESULT(ic)))
11151   {
11152       /* If the result is accessed indirectly via
11153        * the accumulator, we must explicitly write
11154        * it back after the decrement.
11155        */
11156       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11157
11158       if (strcmp(rByte, "a"))
11159       {
11160            /* Something is hopelessly wrong */
11161            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11162                    __FILE__, __LINE__);
11163            /* We can just give up; the generated code will be inefficient,
11164             * but what the hey.
11165             */
11166            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11167            return 0;
11168       }
11169       emitcode ("dec", "%s", rByte);
11170       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
11171       emitcode ("jnz", "%05d$", lbl->key + 100);
11172   }
11173   else if (IS_AOP_PREG (IC_RESULT (ic)))
11174     {
11175       emitcode ("dec", "%s",
11176                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11177       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11178       emitcode ("jnz", "%05d$", lbl->key + 100);
11179     }
11180   else
11181     {
11182       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11183                 lbl->key + 100);
11184     }
11185   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11186   emitcode ("", "%05d$:", lbl->key + 100);
11187   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11188   emitcode ("", "%05d$:", lbl1->key + 100);
11189
11190   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11191   ifx->generated = 1;
11192   return 1;
11193 }
11194
11195 /*-----------------------------------------------------------------*/
11196 /* genReceive - generate code for a receive iCode                  */
11197 /*-----------------------------------------------------------------*/
11198 static void
11199 genReceive (iCode * ic)
11200 {
11201   int size = getSize (operandType (IC_RESULT (ic)));
11202   int offset = 0;
11203
11204   D(emitcode (";     genReceive",""));
11205
11206   if (ic->argreg == 1)
11207     { /* first parameter */
11208       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11209            isOperandInPagedSpace (IC_RESULT (ic))) &&
11210           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11211            IS_TRUE_SYMOP (IC_RESULT (ic))))
11212         {
11213           regs *tempRegs[4];
11214           int receivingA = 0;
11215           int roffset = 0;
11216
11217           for (offset = 0; offset<size; offset++)
11218             if (!strcmp (fReturn[offset], "a"))
11219               receivingA = 1;
11220
11221           if (!receivingA)
11222             {
11223               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11224                 {
11225                   for (offset = size-1; offset>0; offset--)
11226                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11227                   emitcode("mov","a,%s", fReturn[0]);
11228                   _G.accInUse++;
11229                   aopOp (IC_RESULT (ic), ic, FALSE);
11230                   _G.accInUse--;
11231                   aopPut (IC_RESULT (ic), "a", offset,
11232                           isOperandVolatile (IC_RESULT (ic), FALSE));
11233                   for (offset = 1; offset<size; offset++)
11234                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
11235                             isOperandVolatile (IC_RESULT (ic), FALSE));
11236                   goto release;
11237                 }
11238             }
11239           else
11240             {
11241               if (getTempRegs(tempRegs, size, ic))
11242                 {
11243                   for (offset = 0; offset<size; offset++)
11244                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11245                   aopOp (IC_RESULT (ic), ic, FALSE);
11246                   for (offset = 0; offset<size; offset++)
11247                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
11248                             isOperandVolatile (IC_RESULT (ic), FALSE));
11249                   goto release;
11250                 }
11251             }
11252
11253           offset = fReturnSizeMCS51 - size;
11254           while (size--)
11255             {
11256               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11257                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11258               offset++;
11259             }
11260           aopOp (IC_RESULT (ic), ic, FALSE);
11261           size = AOP_SIZE (IC_RESULT (ic));
11262           offset = 0;
11263           while (size--)
11264             {
11265               emitcode ("pop", "acc");
11266               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11267             }
11268         }
11269       else
11270         {
11271           _G.accInUse++;
11272           aopOp (IC_RESULT (ic), ic, FALSE);
11273           _G.accInUse--;
11274           assignResultValue (IC_RESULT (ic), NULL);
11275         }
11276     }
11277   else if (ic->argreg > 12)
11278     { /* bit parameters */
11279       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11280         {
11281           aopOp (IC_RESULT (ic), ic, FALSE);
11282           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11283           outBitC(IC_RESULT (ic));
11284         }
11285     }
11286   else
11287     { /* other parameters */
11288       int rb1off ;
11289       aopOp (IC_RESULT (ic), ic, FALSE);
11290       rb1off = ic->argreg;
11291       while (size--)
11292         {
11293           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11294         }
11295     }
11296
11297 release:
11298   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11299 }
11300
11301 /*-----------------------------------------------------------------*/
11302 /* genDummyRead - generate code for dummy read of volatiles        */
11303 /*-----------------------------------------------------------------*/
11304 static void
11305 genDummyRead (iCode * ic)
11306 {
11307   operand *op;
11308   int size, offset;
11309
11310   D(emitcode(";     genDummyRead",""));
11311
11312   op = IC_RIGHT (ic);
11313   if (op && IS_SYMOP (op))
11314     {
11315       aopOp (op, ic, FALSE);
11316
11317       /* if the result is a bit */
11318       if (AOP_TYPE (op) == AOP_CRY)
11319         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11320       else
11321         {
11322           /* bit variables done */
11323           /* general case */
11324           size = AOP_SIZE (op);
11325           offset = 0;
11326           while (size--)
11327           {
11328             MOVA (aopGet (op, offset, FALSE, FALSE));
11329             offset++;
11330           }
11331         }
11332
11333       freeAsmop (op, NULL, ic, TRUE);
11334     }
11335
11336   op = IC_LEFT (ic);
11337   if (op && IS_SYMOP (op))
11338     {
11339       aopOp (op, ic, FALSE);
11340
11341       /* if the result is a bit */
11342       if (AOP_TYPE (op) == AOP_CRY)
11343         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11344       else
11345         {
11346           /* bit variables done */
11347           /* general case */
11348           size = AOP_SIZE (op);
11349           offset = 0;
11350           while (size--)
11351           {
11352             MOVA (aopGet (op, offset, FALSE, FALSE));
11353             offset++;
11354           }
11355         }
11356
11357       freeAsmop (op, NULL, ic, TRUE);
11358     }
11359 }
11360
11361 /*-----------------------------------------------------------------*/
11362 /* genCritical - generate code for start of a critical sequence    */
11363 /*-----------------------------------------------------------------*/
11364 static void
11365 genCritical (iCode *ic)
11366 {
11367   symbol *tlbl = newiTempLabel (NULL);
11368
11369   D(emitcode(";     genCritical",""));
11370
11371   if (IC_RESULT (ic))
11372     {
11373       aopOp (IC_RESULT (ic), ic, TRUE);
11374       aopPut (IC_RESULT (ic), one, 0, 0);
11375       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11376       aopPut (IC_RESULT (ic), zero, 0, 0);
11377       emitcode ("", "%05d$:", (tlbl->key + 100));
11378       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11379     }
11380   else
11381     {
11382       emitcode ("setb", "c");
11383       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11384       emitcode ("clr", "c");
11385       emitcode ("", "%05d$:", (tlbl->key + 100));
11386       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11387     }
11388 }
11389
11390 /*-----------------------------------------------------------------*/
11391 /* genEndCritical - generate code for end of a critical sequence   */
11392 /*-----------------------------------------------------------------*/
11393 static void
11394 genEndCritical (iCode *ic)
11395 {
11396   D(emitcode(";     genEndCritical",""));
11397
11398   if (IC_RIGHT (ic))
11399     {
11400       aopOp (IC_RIGHT (ic), ic, FALSE);
11401       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11402         {
11403           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11404           emitcode ("mov", "ea,c");
11405         }
11406       else
11407         {
11408           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11409             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11410           emitcode ("rrc", "a");
11411           emitcode ("mov", "ea,c");
11412         }
11413       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11414     }
11415   else
11416     {
11417       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11418       emitcode ("mov", "ea,c");
11419     }
11420 }
11421
11422 /*-----------------------------------------------------------------*/
11423 /* gen51Code - generate code for 8051 based controllers            */
11424 /*-----------------------------------------------------------------*/
11425 void
11426 gen51Code (iCode * lic)
11427 {
11428   iCode *ic;
11429   int cln = 0;
11430   /* int cseq = 0; */
11431
11432   _G.currentFunc = NULL;
11433   lineHead = lineCurr = NULL;
11434
11435   /* print the allocation information */
11436   if (allocInfo && currFunc)
11437     printAllocInfo (currFunc, codeOutFile);
11438   /* if debug information required */
11439   if (options.debug && currFunc)
11440     {
11441       debugFile->writeFunction (currFunc, lic);
11442     }
11443   /* stack pointer name */
11444   if (options.useXstack)
11445     spname = "_spx";
11446   else
11447     spname = "sp";
11448
11449
11450   for (ic = lic; ic; ic = ic->next)
11451     {
11452       _G.current_iCode = ic;
11453
11454       if (ic->lineno && cln != ic->lineno)
11455         {
11456           if (options.debug)
11457             {
11458               debugFile->writeCLine (ic);
11459             }
11460           if (!options.noCcodeInAsm) {
11461             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
11462                       printCLine(ic->filename, ic->lineno));
11463           }
11464           cln = ic->lineno;
11465         }
11466       #if 0
11467       if (ic->seqPoint && ic->seqPoint != cseq)
11468         {
11469           emitcode ("", "; sequence point %d", ic->seqPoint);
11470           cseq = ic->seqPoint;
11471         }
11472       #endif
11473       if (options.iCodeInAsm) {
11474         char regsInUse[80];
11475         int i;
11476
11477         #if 0
11478         for (i=0; i<8; i++) {
11479           sprintf (&regsInUse[i],
11480                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11481         regsInUse[i]=0;
11482         #else
11483         strcpy (regsInUse, "--------");
11484         for (i=0; i < 8; i++) {
11485           if (bitVectBitValue (ic->rMask, i))
11486             {
11487               int offset = regs8051[i].offset;
11488               regsInUse[offset] = offset + '0'; /* show rMask */
11489             }
11490         #endif
11491         }
11492         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11493       }
11494       /* if the result is marked as
11495          spilt and rematerializable or code for
11496          this has already been generated then
11497          do nothing */
11498       if (resultRemat (ic) || ic->generated)
11499         continue;
11500
11501       /* depending on the operation */
11502       switch (ic->op)
11503         {
11504         case '!':
11505           genNot (ic);
11506           break;
11507
11508         case '~':
11509           genCpl (ic);
11510           break;
11511
11512         case UNARYMINUS:
11513           genUminus (ic);
11514           break;
11515
11516         case IPUSH:
11517           genIpush (ic);
11518           break;
11519
11520         case IPOP:
11521           /* IPOP happens only when trying to restore a
11522              spilt live range, if there is an ifx statement
11523              following this pop then the if statement might
11524              be using some of the registers being popped which
11525              would destory the contents of the register so
11526              we need to check for this condition and handle it */
11527           if (ic->next &&
11528               ic->next->op == IFX &&
11529               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11530             genIfx (ic->next, ic);
11531           else
11532             genIpop (ic);
11533           break;
11534
11535         case CALL:
11536           genCall (ic);
11537           break;
11538
11539         case PCALL:
11540           genPcall (ic);
11541           break;
11542
11543         case FUNCTION:
11544           genFunction (ic);
11545           break;
11546
11547         case ENDFUNCTION:
11548           genEndFunction (ic);
11549           break;
11550
11551         case RETURN:
11552           genRet (ic);
11553           break;
11554
11555         case LABEL:
11556           genLabel (ic);
11557           break;
11558
11559         case GOTO:
11560           genGoto (ic);
11561           break;
11562
11563         case '+':
11564           genPlus (ic);
11565           break;
11566
11567         case '-':
11568           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11569             genMinus (ic);
11570           break;
11571
11572         case '*':
11573           genMult (ic);
11574           break;
11575
11576         case '/':
11577           genDiv (ic);
11578           break;
11579
11580         case '%':
11581           genMod (ic);
11582           break;
11583
11584         case '>':
11585           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11586           break;
11587
11588         case '<':
11589           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11590           break;
11591
11592         case LE_OP:
11593         case GE_OP:
11594         case NE_OP:
11595
11596           /* note these two are xlated by algebraic equivalence
11597              during parsing SDCC.y */
11598           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11599                   "got '>=' or '<=' shouldn't have come here");
11600           break;
11601
11602         case EQ_OP:
11603           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11604           break;
11605
11606         case AND_OP:
11607           genAndOp (ic);
11608           break;
11609
11610         case OR_OP:
11611           genOrOp (ic);
11612           break;
11613
11614         case '^':
11615           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11616           break;
11617
11618         case '|':
11619           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11620           break;
11621
11622         case BITWISEAND:
11623           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11624           break;
11625
11626         case INLINEASM:
11627           genInline (ic);
11628           break;
11629
11630         case RRC:
11631           genRRC (ic);
11632           break;
11633
11634         case RLC:
11635           genRLC (ic);
11636           break;
11637
11638         case GETHBIT:
11639           genGetHbit (ic);
11640           break;
11641
11642         case GETABIT:
11643           genGetAbit (ic);
11644           break;
11645
11646         case GETBYTE:
11647           genGetByte (ic);
11648           break;
11649
11650         case GETWORD:
11651           genGetWord (ic);
11652           break;
11653
11654         case LEFT_OP:
11655           genLeftShift (ic);
11656           break;
11657
11658         case RIGHT_OP:
11659           genRightShift (ic);
11660           break;
11661
11662         case GET_VALUE_AT_ADDRESS:
11663           genPointerGet (ic,
11664                          hasInc (IC_LEFT (ic), ic,
11665                                  getSize (operandType (IC_RESULT (ic)))),
11666                          ifxForOp (IC_RESULT (ic), ic) );
11667           break;
11668
11669         case '=':
11670           if (POINTER_SET (ic))
11671             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
11672           else
11673             genAssign (ic);
11674           break;
11675
11676         case IFX:
11677           genIfx (ic, NULL);
11678           break;
11679
11680         case ADDRESS_OF:
11681           genAddrOf (ic);
11682           break;
11683
11684         case JUMPTABLE:
11685           genJumpTab (ic);
11686           break;
11687
11688         case CAST:
11689           genCast (ic);
11690           break;
11691
11692         case RECEIVE:
11693           genReceive (ic);
11694           break;
11695
11696         case SEND:
11697           addSet (&_G.sendSet, ic);
11698           break;
11699
11700         case DUMMY_READ_VOLATILE:
11701           genDummyRead (ic);
11702           break;
11703
11704         case CRITICAL:
11705           genCritical (ic);
11706           break;
11707
11708         case ENDCRITICAL:
11709           genEndCritical (ic);
11710           break;
11711
11712         case SWAP:
11713           genSwap (ic);
11714           break;
11715
11716         default:
11717           ic = ic;
11718         }
11719     }
11720
11721   _G.current_iCode = NULL;
11722
11723   /* now we are ready to call the
11724      peep hole optimizer */
11725   if (!options.nopeep)
11726     peepHole (&lineHead);
11727
11728   /* now do the actual printing */
11729   printLine (lineHead, codeOutFile);
11730   return;
11731 }