* support/regression/tests/bug1348008.c: added
[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   return aop;
476 }
477
478 /*-----------------------------------------------------------------*/
479 /* pointerCode - returns the code for a pointer type               */
480 /*-----------------------------------------------------------------*/
481 static int
482 pointerCode (sym_link * etype)
483 {
484
485   return PTR_TYPE (SPEC_OCLS (etype));
486
487 }
488
489 /*-----------------------------------------------------------------*/
490 /* leftRightUseAcc - returns size of accumulator use by operands   */
491 /*-----------------------------------------------------------------*/
492 static int
493 leftRightUseAcc(iCode *ic)
494 {
495   operand *op;
496   int size;
497   int accuseSize = 0;
498   int accuse = 0;
499
500   if (!ic)
501     {
502       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
503               "null iCode pointer");
504       return 0;
505     }
506
507   if (ic->op == IFX)
508     {
509       op = IC_COND (ic);
510       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
511         {
512           accuse = 1;
513           size = getSize (OP_SYMBOL (op)->type);
514           if (size>accuseSize)
515             accuseSize = size;
516         }
517     }
518   else if (ic->op == JUMPTABLE)
519     {
520       op = IC_JTCOND (ic);
521       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
522         {
523           accuse = 1;
524           size = getSize (OP_SYMBOL (op)->type);
525           if (size>accuseSize)
526             accuseSize = size;
527         }
528     }
529   else
530     {
531       op = IC_LEFT (ic);
532       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
533         {
534           accuse = 1;
535           size = getSize (OP_SYMBOL (op)->type);
536           if (size>accuseSize)
537             accuseSize = size;
538         }
539       op = IC_RIGHT (ic);
540       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
541         {
542           accuse = 1;
543           size = getSize (OP_SYMBOL (op)->type);
544           if (size>accuseSize)
545             accuseSize = size;
546         }
547     }
548
549   if (accuseSize)
550     return accuseSize;
551   else
552     return accuse;
553 }
554
555 /*-----------------------------------------------------------------*/
556 /* aopForSym - for a true symbol                                   */
557 /*-----------------------------------------------------------------*/
558 static asmop *
559 aopForSym (iCode * ic, symbol * sym, bool result)
560 {
561   asmop *aop;
562   memmap *space;
563
564   wassertl (ic != NULL, "Got a null iCode");
565   wassertl (sym != NULL, "Got a null symbol");
566
567   space = SPEC_OCLS (sym->etype);
568
569   /* if already has one */
570   if (sym->aop)
571     return sym->aop;
572
573   /* assign depending on the storage class */
574   /* if it is on the stack or indirectly addressable */
575   /* space we need to assign either r0 or r1 to it   */
576   if (sym->onStack || sym->iaccess)
577     {
578       sym->aop = aop = newAsmop (0);
579       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
580       aop->size = getSize (sym->type);
581
582       /* now assign the address of the variable to
583          the pointer register */
584       if (aop->type != AOP_STK)
585         {
586
587           if (sym->onStack)
588             {
589               char offset = ((sym->stack < 0) ?
590                          ((char) (sym->stack - _G.nRegsSaved)) :
591                          ((char) sym->stack)) & 0xff;
592
593               if ((offset >= -3) && (offset <= 3))
594                 {
595                   emitcode ("mov", "%s,%s",
596                             aop->aopu.aop_ptr->name, SYM_BP (sym));
597                   while (offset < 0)
598                     {
599                       emitcode ("dec", aop->aopu.aop_ptr->name);
600                       offset++;
601                     }
602                   while (offset > 0)
603                     {
604                       emitcode ("inc", aop->aopu.aop_ptr->name);
605                       offset--;
606                     }
607                 }
608               else
609                 {
610                   if (_G.accInUse || leftRightUseAcc (ic))
611                     emitcode ("push", "acc");
612                   emitcode ("mov", "a,%s", SYM_BP (sym));
613                   emitcode ("add", "a,#0x%02x", offset);
614                   emitcode ("mov", "%s,a",
615                             aop->aopu.aop_ptr->name);
616                   if (_G.accInUse || leftRightUseAcc (ic))
617                     emitcode ("pop", "acc");
618                 }
619             }
620           else
621             emitcode ("mov", "%s,#%s",
622                       aop->aopu.aop_ptr->name,
623                       sym->rname);
624           aop->paged = space->paged;
625         }
626       else
627         aop->aopu.aop_stk = sym->stack;
628       return aop;
629     }
630
631   /* if in bit space */
632   if (IN_BITSPACE (space))
633     {
634       sym->aop = aop = newAsmop (AOP_CRY);
635       aop->aopu.aop_dir = sym->rname;
636       aop->size = getSize (sym->type);
637       return aop;
638     }
639   /* if it is in direct space */
640   if (IN_DIRSPACE (space))
641     {
642       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
643       //printTypeChainRaw(sym->type, NULL);
644       //printf("space = %s\n", space ? space->sname : "NULL");
645       sym->aop = aop = newAsmop (AOP_DIR);
646       aop->aopu.aop_dir = sym->rname;
647       aop->size = getSize (sym->type);
648       return aop;
649     }
650
651   /* special case for a function */
652   if (IS_FUNC (sym->type))
653     {
654       sym->aop = aop = newAsmop (AOP_IMMD);
655       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
656       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
657       aop->size = getSize (sym->type);
658       return aop;
659     }
660
661   /* only remaining is far space */
662   /* in which case DPTR gets the address */
663   sym->aop = aop = newAsmop (AOP_DPTR);
664   emitcode ("mov", "dptr,#%s", sym->rname);
665   aop->size = getSize (sym->type);
666
667   /* if it is in code space */
668   if (IN_CODESPACE (space))
669     aop->code = 1;
670
671   return aop;
672 }
673
674 /*-----------------------------------------------------------------*/
675 /* aopForRemat - rematerialzes an object                           */
676 /*-----------------------------------------------------------------*/
677 static asmop *
678 aopForRemat (symbol * sym)
679 {
680   iCode *ic = sym->rematiCode;
681   asmop *aop = newAsmop (AOP_IMMD);
682   int ptr_type = 0;
683   int val = 0;
684
685   for (;;)
686     {
687       if (ic->op == '+')
688         val += (int) operandLitValue (IC_RIGHT (ic));
689       else if (ic->op == '-')
690         val -= (int) operandLitValue (IC_RIGHT (ic));
691       else if (IS_CAST_ICODE(ic)) {
692               sym_link *from_type = operandType(IC_RIGHT(ic));
693               aop->aopu.aop_immd.from_cast_remat = 1;
694               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
695               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
696               continue;
697       } else break;
698
699       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
700     }
701
702   if (val)
703     sprintf (buffer, "(%s %c 0x%04x)",
704              OP_SYMBOL (IC_LEFT (ic))->rname,
705              val >= 0 ? '+' : '-',
706              abs (val) & 0xffff);
707   else
708     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
709
710   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
711   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
712   /* set immd2 field if required */
713   if (aop->aopu.aop_immd.from_cast_remat) {
714           sprintf(buffer,"#0x%02x",ptr_type);
715           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
716           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
717   }
718
719   return aop;
720 }
721
722 /*-----------------------------------------------------------------*/
723 /* regsInCommon - two operands have some registers in common       */
724 /*-----------------------------------------------------------------*/
725 static bool
726 regsInCommon (operand * op1, operand * op2)
727 {
728   symbol *sym1, *sym2;
729   int i;
730
731   /* if they have registers in common */
732   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
733     return FALSE;
734
735   sym1 = OP_SYMBOL (op1);
736   sym2 = OP_SYMBOL (op2);
737
738   if (sym1->nRegs == 0 || sym2->nRegs == 0)
739     return FALSE;
740
741   for (i = 0; i < sym1->nRegs; i++)
742     {
743       int j;
744       if (!sym1->regs[i])
745         continue;
746
747       for (j = 0; j < sym2->nRegs; j++)
748         {
749           if (!sym2->regs[j])
750             continue;
751
752           if (sym2->regs[j] == sym1->regs[i])
753             return TRUE;
754         }
755     }
756
757   return FALSE;
758 }
759
760 /*-----------------------------------------------------------------*/
761 /* operandsEqu - equivalent                                        */
762 /*-----------------------------------------------------------------*/
763 static bool
764 operandsEqu (operand * op1, operand * op2)
765 {
766   symbol *sym1, *sym2;
767
768   /* if they're not symbols */
769   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
770     return FALSE;
771
772   sym1 = OP_SYMBOL (op1);
773   sym2 = OP_SYMBOL (op2);
774
775   /* if both are itemps & one is spilt
776      and the other is not then false */
777   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
778       sym1->isspilt != sym2->isspilt)
779     return FALSE;
780
781   /* if they are the same */
782   if (sym1 == sym2)
783     return TRUE;
784
785   /* if they have the same rname */
786   if (sym1->rname[0] && sym2->rname[0] &&
787       strcmp (sym1->rname, sym2->rname) == 0 &&
788       !(IS_PARM (op2) && IS_ITEMP (op1)))
789     return TRUE;
790
791   /* if left is a tmp & right is not */
792   if (IS_ITEMP (op1) &&
793       !IS_ITEMP (op2) &&
794       sym1->isspilt &&
795       (sym1->usl.spillLoc == sym2))
796     return TRUE;
797
798   if (IS_ITEMP (op2) &&
799       !IS_ITEMP (op1) &&
800       sym2->isspilt &&
801       sym1->level > 0 &&
802       (sym2->usl.spillLoc == sym1))
803     return TRUE;
804
805   return FALSE;
806 }
807
808 /*-----------------------------------------------------------------*/
809 /* sameRegs - two asmops have the same registers                   */
810 /*-----------------------------------------------------------------*/
811 static bool
812 sameRegs (asmop * aop1, asmop * aop2)
813 {
814   int i;
815
816   if (aop1 == aop2)
817     return TRUE;
818
819   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
820     return FALSE;
821
822   if (aop1->type != aop2->type)
823     return FALSE;
824
825   if (aop1->size != aop2->size)
826     return FALSE;
827
828   for (i = 0; i < aop1->size; i++)
829     if (aop1->aopu.aop_reg[i] !=
830         aop2->aopu.aop_reg[i])
831       return FALSE;
832
833   return TRUE;
834 }
835
836 /*-----------------------------------------------------------------*/
837 /* aopOp - allocates an asmop for an operand  :                    */
838 /*-----------------------------------------------------------------*/
839 static void
840 aopOp (operand * op, iCode * ic, bool result)
841 {
842   asmop *aop;
843   symbol *sym;
844   int i;
845
846   if (!op)
847     return;
848
849   /* if this a literal */
850   if (IS_OP_LITERAL (op))
851     {
852       op->aop = aop = newAsmop (AOP_LIT);
853       aop->aopu.aop_lit = op->operand.valOperand;
854       aop->size = getSize (operandType (op));
855       return;
856     }
857
858   /* if already has a asmop then continue */
859   if (op->aop )
860     return;
861
862   /* if the underlying symbol has a aop */
863   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
864     {
865       op->aop = OP_SYMBOL (op)->aop;
866       return;
867     }
868
869   /* if this is a true symbol */
870   if (IS_TRUE_SYMOP (op))
871     {
872       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
873       return;
874     }
875
876   /* this is a temporary : this has
877      only five choices :
878      a) register
879      b) spillocation
880      c) rematerialize
881      d) conditional
882      e) can be a return use only */
883
884   sym = OP_SYMBOL (op);
885
886   /* if the type is a conditional */
887   if (sym->regType == REG_CND)
888     {
889       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
890       aop->size = 0;
891       return;
892     }
893
894   /* if it is spilt then two situations
895      a) is rematerialize
896      b) has a spill location */
897   if (sym->isspilt || sym->nRegs == 0)
898     {
899
900       /* rematerialize it NOW */
901       if (sym->remat)
902         {
903           sym->aop = op->aop = aop =
904             aopForRemat (sym);
905           aop->size = getSize (sym->type);
906           return;
907         }
908
909       if (sym->accuse)
910         {
911           int i;
912           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
913           aop->size = getSize (sym->type);
914           for (i = 0; i < 2; i++)
915             aop->aopu.aop_str[i] = accUse[i];
916           return;
917         }
918
919       if (sym->ruonly)
920         {
921           unsigned i;
922
923           aop = op->aop = sym->aop = newAsmop (AOP_STR);
924           aop->size = getSize (sym->type);
925           for (i = 0; i < fReturnSizeMCS51; i++)
926             aop->aopu.aop_str[i] = fReturn[i];
927           return;
928         }
929
930       if (sym->usl.spillLoc)
931         {
932           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
933             {
934               /* force a new aop if sizes differ */
935               sym->usl.spillLoc->aop = NULL;
936             }
937           sym->aop = op->aop = aop =
938                      aopForSym (ic, sym->usl.spillLoc, result);
939           aop->size = getSize (sym->type);
940           return;
941         }
942
943       /* else must be a dummy iTemp */
944       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
945       aop->size = getSize (sym->type);
946       return;
947     }
948
949   /* if the type is a bit register */
950   if (sym->regType == REG_BIT)
951     {
952       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
953       aop->size = sym->nRegs;//1???
954       aop->aopu.aop_reg[0] = sym->regs[0];
955       aop->aopu.aop_dir = sym->regs[0]->name;
956       return;
957     }
958
959   /* must be in a register */
960   sym->aop = op->aop = aop = newAsmop (AOP_REG);
961   aop->size = sym->nRegs;
962   for (i = 0; i < sym->nRegs; i++)
963     aop->aopu.aop_reg[i] = sym->regs[i];
964 }
965
966 /*-----------------------------------------------------------------*/
967 /* freeAsmop - free up the asmop given to an operand               */
968 /*----------------------------------------------------------------*/
969 static void
970 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
971 {
972   asmop *aop;
973
974   if (!op)
975     aop = aaop;
976   else
977     aop = op->aop;
978
979   if (!aop)
980     return;
981
982   if (aop->freed)
983     goto dealloc;
984
985   aop->freed = 1;
986
987   /* depending on the asmop type only three cases need work AOP_RO
988      , AOP_R1 && AOP_STK */
989   switch (aop->type)
990     {
991     case AOP_R0:
992       if (R0INB)
993         {
994           emitcode ("mov", "r0,b");
995           R0INB--;
996         }
997       else if (_G.r0Pushed)
998         {
999           if (pop)
1000             {
1001               emitcode ("pop", "ar0");
1002               _G.r0Pushed--;
1003             }
1004         }
1005       bitVectUnSetBit (ic->rUsed, R0_IDX);
1006       break;
1007
1008     case AOP_R1:
1009       if (R1INB)
1010         {
1011           emitcode ("mov", "r1,b");
1012           R1INB--;
1013         }
1014       if (_G.r1Pushed)
1015         {
1016           if (pop)
1017             {
1018               emitcode ("pop", "ar1");
1019               _G.r1Pushed--;
1020             }
1021         }
1022       bitVectUnSetBit (ic->rUsed, R1_IDX);
1023       break;
1024
1025     case AOP_STK:
1026       {
1027         int sz = aop->size;
1028         int stk = aop->aopu.aop_stk + aop->size - 1;
1029         bitVectUnSetBit (ic->rUsed, R0_IDX);
1030         bitVectUnSetBit (ic->rUsed, R1_IDX);
1031
1032         getFreePtr (ic, &aop, FALSE);
1033
1034         if (stk)
1035           {
1036             emitcode ("mov", "a,_bp");
1037             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1038             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1039           }
1040         else
1041           {
1042             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1043           }
1044
1045         while (sz--)
1046           {
1047             emitcode ("pop", "acc");
1048             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1049             if (!sz)
1050               break;
1051             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1052           }
1053         op->aop = aop;
1054         freeAsmop (op, NULL, ic, TRUE);
1055         if (_G.r1Pushed)
1056           {
1057             emitcode ("pop", "ar1");
1058             _G.r1Pushed--;
1059           }
1060
1061         if (_G.r0Pushed)
1062           {
1063             emitcode ("pop", "ar0");
1064             _G.r0Pushed--;
1065           }
1066       }
1067     }
1068
1069 dealloc:
1070   /* all other cases just dealloc */
1071   if (op)
1072     {
1073       op->aop = NULL;
1074       if (IS_SYMOP (op))
1075         {
1076           OP_SYMBOL (op)->aop = NULL;
1077           /* if the symbol has a spill */
1078           if (SPIL_LOC (op))
1079             SPIL_LOC (op)->aop = NULL;
1080         }
1081     }
1082 }
1083
1084 /*------------------------------------------------------------------*/
1085 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1086 /*                      pop r0 or r1 off stack if pushed            */
1087 /*------------------------------------------------------------------*/
1088 static void
1089 freeForBranchAsmop (operand * op)
1090 {
1091   asmop *aop;
1092
1093   if (!op)
1094     return;
1095
1096   aop = op->aop;
1097
1098   if (!aop)
1099     return;
1100
1101   if (aop->freed)
1102     return;
1103
1104   switch (aop->type)
1105     {
1106     case AOP_R0:
1107       if (R0INB)
1108         {
1109           emitcode ("mov", "r0,b");
1110         }
1111       else if (_G.r0Pushed)
1112         {
1113           emitcode ("pop", "ar0");
1114         }
1115       break;
1116
1117     case AOP_R1:
1118       if (R1INB)
1119         {
1120           emitcode ("mov", "r1,b");
1121         }
1122       else if (_G.r1Pushed)
1123         {
1124           emitcode ("pop", "ar1");
1125         }
1126       break;
1127
1128     case AOP_STK:
1129       {
1130         int sz = aop->size;
1131         int stk = aop->aopu.aop_stk + aop->size - 1;
1132
1133         emitcode ("mov", "b,r0");
1134         if (stk)
1135           {
1136             emitcode ("mov", "a,_bp");
1137             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1138             emitcode ("mov", "r0,a");
1139           }
1140         else
1141           {
1142             emitcode ("mov", "r0,_bp");
1143           }
1144
1145         while (sz--)
1146           {
1147             emitcode ("pop", "acc");
1148             emitcode ("mov", "@r0,a");
1149             if (!sz)
1150               break;
1151             emitcode ("dec", "r0");
1152           }
1153         emitcode ("mov", "r0,b");
1154       }
1155     }
1156
1157 }
1158
1159 /*-----------------------------------------------------------------*/
1160 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1161 /*                 clobber the accumulator                         */
1162 /*-----------------------------------------------------------------*/
1163 static bool
1164 aopGetUsesAcc (operand * oper, int offset)
1165 {
1166   asmop * aop = AOP (oper);
1167
1168   if (offset > (aop->size - 1))
1169     return FALSE;
1170
1171   switch (aop->type)
1172     {
1173
1174     case AOP_R0:
1175     case AOP_R1:
1176       if (aop->paged)
1177         return TRUE;
1178       return FALSE;
1179     case AOP_DPTR:
1180       return TRUE;
1181     case AOP_IMMD:
1182       return FALSE;
1183     case AOP_DIR:
1184       return FALSE;
1185     case AOP_REG:
1186       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1187       return FALSE;
1188     case AOP_CRY:
1189       return TRUE;
1190     case AOP_ACC:
1191       if (offset)
1192         return FALSE;
1193       return TRUE;
1194     case AOP_LIT:
1195       return FALSE;
1196     case AOP_STR:
1197       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1198         return TRUE;
1199       return FALSE;
1200     case AOP_DUMMY:
1201       return FALSE;
1202     default:
1203       /* Error case --- will have been caught already */
1204       wassert(0);
1205       return FALSE;
1206     }
1207 }
1208
1209 /*-----------------------------------------------------------------*/
1210 /* aopGet - for fetching value of the aop                          */
1211 /*-----------------------------------------------------------------*/
1212 static char *
1213 aopGet (operand * oper, int offset, bool bit16, bool dname)
1214 {
1215   char *s = buffer;
1216   char *rs;
1217   asmop * aop = AOP (oper);
1218
1219   /* offset is greater than
1220      size then zero */
1221   if (offset > (aop->size - 1) &&
1222       aop->type != AOP_LIT)
1223     return zero;
1224
1225   /* depending on type */
1226   switch (aop->type)
1227     {
1228     case AOP_DUMMY:
1229       return zero;
1230
1231     case AOP_R0:
1232     case AOP_R1:
1233       /* if we need to increment it */
1234       while (offset > aop->coff)
1235         {
1236           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1237           aop->coff++;
1238         }
1239
1240       while (offset < aop->coff)
1241         {
1242           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1243           aop->coff--;
1244         }
1245
1246       aop->coff = offset;
1247       if (aop->paged)
1248         {
1249           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1250           return (dname ? "acc" : "a");
1251         }
1252       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1253       rs = Safe_calloc (1, strlen (s) + 1);
1254       strcpy (rs, s);
1255       return rs;
1256
1257     case AOP_DPTR:
1258       if (aop->code && aop->coff==0 && offset>=1) {
1259         emitcode ("mov", "a,#0x%02x", offset);
1260         emitcode ("movc", "a,@a+dptr");
1261         return (dname ? "acc" : "a");
1262       }
1263
1264       while (offset > aop->coff)
1265         {
1266           emitcode ("inc", "dptr");
1267           aop->coff++;
1268         }
1269
1270       while (offset < aop->coff)
1271         {
1272           emitcode ("lcall", "__decdptr");
1273           aop->coff--;
1274         }
1275
1276       aop->coff = offset;
1277       if (aop->code)
1278         {
1279           emitcode ("clr", "a");
1280           emitcode ("movc", "a,@a+dptr");
1281         }
1282       else
1283         {
1284           emitcode ("movx", "a,@dptr");
1285         }
1286       return (dname ? "acc" : "a");
1287
1288
1289     case AOP_IMMD:
1290       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1291               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1292       } else if (bit16)
1293         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1294       else if (offset)
1295         sprintf (s, "#(%s >> %d)",
1296                  aop->aopu.aop_immd.aop_immd1,
1297                  offset * 8);
1298       else
1299         sprintf (s, "#%s",
1300                  aop->aopu.aop_immd.aop_immd1);
1301       rs = Safe_calloc (1, strlen (s) + 1);
1302       strcpy (rs, s);
1303       return rs;
1304
1305     case AOP_DIR:
1306       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1307         sprintf (s, "(%s >> %d)",
1308                  aop->aopu.aop_dir, offset * 8);
1309       else if (offset)
1310         sprintf (s, "(%s + %d)",
1311                  aop->aopu.aop_dir,
1312                  offset);
1313       else
1314         sprintf (s, "%s", aop->aopu.aop_dir);
1315       rs = Safe_calloc (1, strlen (s) + 1);
1316       strcpy (rs, s);
1317       return rs;
1318
1319     case AOP_REG:
1320       if (dname)
1321         return aop->aopu.aop_reg[offset]->dname;
1322       else
1323         return aop->aopu.aop_reg[offset]->name;
1324
1325     case AOP_CRY:
1326       emitcode ("clr", "a");
1327       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1328       emitcode ("rlc", "a");
1329       return (dname ? "acc" : "a");
1330
1331     case AOP_ACC:
1332       if (!offset && dname)
1333         return "acc";
1334       return aop->aopu.aop_str[offset];
1335
1336     case AOP_LIT:
1337       return aopLiteral (aop->aopu.aop_lit, offset);
1338
1339     case AOP_STR:
1340       aop->coff = offset;
1341       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1342           dname)
1343         return "acc";
1344
1345       return aop->aopu.aop_str[offset];
1346
1347     }
1348
1349   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1350           "aopget got unsupported aop->type");
1351   exit (1);
1352 }
1353
1354 /*-----------------------------------------------------------------*/
1355 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1356 /*                 clobber the accumulator                         */
1357 /*-----------------------------------------------------------------*/
1358 static bool
1359 aopPutUsesAcc (operand * oper, const char *s, int offset)
1360 {
1361   asmop * aop = AOP (oper);
1362
1363   if (offset > (aop->size - 1))
1364     return FALSE;
1365
1366   switch (aop->type)
1367     {
1368     case AOP_DUMMY:
1369       return TRUE;
1370     case AOP_DIR:
1371       return FALSE;
1372     case AOP_REG:
1373       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1374       return FALSE;
1375     case AOP_DPTR:
1376       return TRUE;
1377     case AOP_R0:
1378     case AOP_R1:
1379       return ((aop->paged) || (*s == '@'));
1380     case AOP_STK:
1381       return (*s == '@');
1382     case AOP_CRY:
1383       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1384     case AOP_STR:
1385       return FALSE;
1386     case AOP_IMMD:
1387       return FALSE;
1388     case AOP_ACC:
1389       return FALSE;
1390     default:
1391       /* Error case --- will have been caught already */
1392       wassert(0);
1393       return FALSE;
1394     }
1395 }
1396
1397 /*-----------------------------------------------------------------*/
1398 /* aopPut - puts a string for a aop and indicates if acc is in use */
1399 /*-----------------------------------------------------------------*/
1400 static bool
1401 aopPut (operand * result, const char *s, int offset, bool bvolatile)
1402 {
1403   char *d = buffer;
1404   bool accuse = FALSE;
1405   asmop * aop = AOP (result);
1406
1407   if (aop->size && offset > (aop->size - 1))
1408     {
1409       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1410               "aopPut got offset > aop->size");
1411       exit (1);
1412     }
1413
1414   /* will assign value to value */
1415   /* depending on where it is ofcourse */
1416   switch (aop->type)
1417     {
1418     case AOP_DUMMY:
1419       MOVA (s);         /* read s in case it was volatile */
1420       accuse = TRUE;
1421       break;
1422
1423     case AOP_DIR:
1424       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1425         sprintf (d, "(%s >> %d)", aop->aopu.aop_dir, offset * 8);
1426       else if (offset)
1427         sprintf (d, "(%s + %d)", aop->aopu.aop_dir, offset);
1428       else
1429         sprintf (d, "%s", aop->aopu.aop_dir);
1430
1431       if (strcmp (d, s) || bvolatile)
1432           emitcode ("mov", "%s,%s", d, s);
1433       if (!strcmp (d, "acc"))
1434           accuse = TRUE;
1435
1436       break;
1437
1438     case AOP_REG:
1439       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1440           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1441         {
1442           if (*s == '@' ||
1443               strcmp (s, "r0") == 0 ||
1444               strcmp (s, "r1") == 0 ||
1445               strcmp (s, "r2") == 0 ||
1446               strcmp (s, "r3") == 0 ||
1447               strcmp (s, "r4") == 0 ||
1448               strcmp (s, "r5") == 0 ||
1449               strcmp (s, "r6") == 0 ||
1450               strcmp (s, "r7") == 0)
1451             emitcode ("mov", "%s,%s",
1452                       aop->aopu.aop_reg[offset]->dname, s);
1453           else
1454             emitcode ("mov", "%s,%s",
1455                       aop->aopu.aop_reg[offset]->name, s);
1456         }
1457       break;
1458
1459     case AOP_DPTR:
1460       if (aop->code)
1461         {
1462           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1463                   "aopPut writing to code space");
1464           exit (1);
1465         }
1466
1467       while (offset > aop->coff)
1468         {
1469           aop->coff++;
1470           emitcode ("inc", "dptr");
1471         }
1472
1473       while (offset < aop->coff)
1474         {
1475           aop->coff--;
1476           emitcode ("lcall", "__decdptr");
1477         }
1478
1479       aop->coff = offset;
1480
1481       /* if not in accumulator */
1482       MOVA (s);
1483
1484       emitcode ("movx", "@dptr,a");
1485       break;
1486
1487     case AOP_R0:
1488     case AOP_R1:
1489       while (offset > aop->coff)
1490         {
1491           aop->coff++;
1492           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1493         }
1494       while (offset < aop->coff)
1495         {
1496           aop->coff--;
1497           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1498         }
1499       aop->coff = offset;
1500
1501       if (aop->paged)
1502         {
1503           MOVA (s);
1504           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1505         }
1506       else if (*s == '@')
1507         {
1508           MOVA (s);
1509           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1510         }
1511       else if (strcmp (s, "r0") == 0 ||
1512                strcmp (s, "r1") == 0 ||
1513                strcmp (s, "r2") == 0 ||
1514                strcmp (s, "r3") == 0 ||
1515                strcmp (s, "r4") == 0 ||
1516                strcmp (s, "r5") == 0 ||
1517                strcmp (s, "r6") == 0 ||
1518                strcmp (s, "r7") == 0)
1519         {
1520           char buffer[10];
1521           sprintf (buffer, "a%s", s);
1522           emitcode ("mov", "@%s,%s",
1523                     aop->aopu.aop_ptr->name, buffer);
1524         }
1525       else
1526         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1527
1528       break;
1529
1530     case AOP_STK:
1531       if (strcmp (s, "a") == 0)
1532         emitcode ("push", "acc");
1533       else
1534         if (*s=='@') {
1535           MOVA(s);
1536           emitcode ("push", "acc");
1537         } else {
1538           emitcode ("push", s);
1539         }
1540
1541       break;
1542
1543     case AOP_CRY:
1544       /* if not bit variable */
1545       if (!aop->aopu.aop_dir)
1546         {
1547           /* inefficient: move carry into A and use jz/jnz */
1548           emitcode ("clr", "a");
1549           emitcode ("rlc", "a");
1550           accuse = TRUE;
1551         }
1552       else
1553         {
1554           if (s == zero)
1555             emitcode ("clr", "%s", aop->aopu.aop_dir);
1556           else if (s == one)
1557             emitcode ("setb", "%s", aop->aopu.aop_dir);
1558           else if (!strcmp (s, "c"))
1559             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1560           else if (strcmp (s, aop->aopu.aop_dir))
1561             {
1562               MOVA (s);
1563               /* set C, if a >= 1 */
1564               emitcode ("add", "a,#0xff");
1565               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1566             }
1567         }
1568       break;
1569
1570     case AOP_STR:
1571       aop->coff = offset;
1572       if (strcmp (aop->aopu.aop_str[offset], s) ||
1573           bvolatile)
1574         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1575       break;
1576
1577     case AOP_ACC:
1578       accuse = TRUE;
1579       aop->coff = offset;
1580       if (!offset && (strcmp (s, "acc") == 0) &&
1581           !bvolatile)
1582         break;
1583
1584       if (strcmp (aop->aopu.aop_str[offset], s) &&
1585           !bvolatile)
1586         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1587       break;
1588
1589     default:
1590       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1591               "aopPut got unsupported aop->type");
1592       exit (1);
1593     }
1594
1595     return accuse;
1596 }
1597
1598
1599 #if 0
1600 /*-----------------------------------------------------------------*/
1601 /* pointToEnd :- points to the last byte of the operand            */
1602 /*-----------------------------------------------------------------*/
1603 static void
1604 pointToEnd (asmop * aop)
1605 {
1606   int count;
1607   if (!aop)
1608     return;
1609
1610   aop->coff = count = (aop->size - 1);
1611   switch (aop->type)
1612     {
1613     case AOP_R0:
1614     case AOP_R1:
1615       while (count--)
1616         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1617       break;
1618     case AOP_DPTR:
1619       while (count--)
1620         emitcode ("inc", "dptr");
1621       break;
1622     }
1623
1624 }
1625 #endif
1626
1627 /*-----------------------------------------------------------------*/
1628 /* reAdjustPreg - points a register back to where it should        */
1629 /*-----------------------------------------------------------------*/
1630 static void
1631 reAdjustPreg (asmop * aop)
1632 {
1633   if ((aop->coff==0) || aop->size <= 1)
1634     return;
1635
1636   switch (aop->type)
1637     {
1638     case AOP_R0:
1639     case AOP_R1:
1640       while (aop->coff--)
1641         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1642       break;
1643     case AOP_DPTR:
1644       while (aop->coff--)
1645         {
1646           emitcode ("lcall", "__decdptr");
1647         }
1648       break;
1649     }
1650   aop->coff = 0;
1651 }
1652
1653 /*-----------------------------------------------------------------*/
1654 /* opIsGptr: returns non-zero if the passed operand is       */
1655 /* a generic pointer type.             */
1656 /*-----------------------------------------------------------------*/
1657 static int
1658 opIsGptr (operand * op)
1659 {
1660   sym_link *type = operandType (op);
1661
1662   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1663     {
1664       return 1;
1665     }
1666   return 0;
1667 }
1668
1669 /*-----------------------------------------------------------------*/
1670 /* getDataSize - get the operand data size                         */
1671 /*-----------------------------------------------------------------*/
1672 static int
1673 getDataSize (operand * op)
1674 {
1675   int size;
1676   size = AOP_SIZE (op);
1677   if (size == GPTRSIZE)
1678     {
1679       sym_link *type = operandType (op);
1680       if (IS_GENPTR (type))
1681         {
1682           /* generic pointer; arithmetic operations
1683            * should ignore the high byte (pointer type).
1684            */
1685           size--;
1686         }
1687     }
1688   return size;
1689 }
1690
1691 /*-----------------------------------------------------------------*/
1692 /* outAcc - output Acc                                             */
1693 /*-----------------------------------------------------------------*/
1694 static void
1695 outAcc (operand * result)
1696 {
1697   int size, offset;
1698   size = getDataSize (result);
1699   if (size)
1700     {
1701       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
1702       size--;
1703       offset = 1;
1704       /* unsigned or positive */
1705       while (size--)
1706         {
1707           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
1708         }
1709     }
1710 }
1711
1712 /*-----------------------------------------------------------------*/
1713 /* outBitC - output a bit C                                        */
1714 /*-----------------------------------------------------------------*/
1715 static void
1716 outBitC (operand * result)
1717 {
1718   /* if the result is bit */
1719   if (AOP_TYPE (result) == AOP_CRY)
1720     aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
1721   else
1722     {
1723       emitcode ("clr", "a");
1724       emitcode ("rlc", "a");
1725       outAcc (result);
1726     }
1727 }
1728
1729 /*-----------------------------------------------------------------*/
1730 /* toBoolean - emit code for orl a,operator(sizeop)                */
1731 /*-----------------------------------------------------------------*/
1732 static void
1733 toBoolean (operand * oper)
1734 {
1735   int size = AOP_SIZE (oper) - 1;
1736   int offset = 1;
1737   bool AccUsed = FALSE;
1738   bool pushedB;
1739
1740   while (!AccUsed && size--)
1741     {
1742       AccUsed |= aopGetUsesAcc(oper, offset++);
1743     }
1744
1745   size = AOP_SIZE (oper) - 1;
1746   offset = 1;
1747   MOVA (aopGet (oper, 0, FALSE, FALSE));
1748   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1749     {
1750       pushedB = pushB ();
1751       emitcode("mov", "b,a");
1752       while (--size)
1753         {
1754           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1755           emitcode ("orl", "b,a");
1756         }
1757       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1758       emitcode ("orl", "a,b");
1759       popB (pushedB);
1760     }
1761   else
1762     {
1763       while (size--)
1764         {
1765           emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
1766         }
1767     }
1768 }
1769
1770
1771 /*-----------------------------------------------------------------*/
1772 /* genNot - generate code for ! operation                          */
1773 /*-----------------------------------------------------------------*/
1774 static void
1775 genNot (iCode * ic)
1776 {
1777   symbol *tlbl;
1778
1779   D(emitcode (";     genNot",""));
1780
1781   /* assign asmOps to operand & result */
1782   aopOp (IC_LEFT (ic), ic, FALSE);
1783   aopOp (IC_RESULT (ic), ic, TRUE);
1784
1785   /* if in bit space then a special case */
1786   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1787     {
1788       /* if left==result then cpl bit */
1789       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1790         {
1791           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1792         }
1793       else
1794         {
1795           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1796           emitcode ("cpl", "c");
1797           outBitC (IC_RESULT (ic));
1798         }
1799       goto release;
1800     }
1801
1802   toBoolean (IC_LEFT (ic));
1803
1804   /* set C, if a == 0 */
1805   tlbl = newiTempLabel (NULL);
1806   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1807   emitcode ("", "%05d$:", tlbl->key + 100);
1808   outBitC (IC_RESULT (ic));
1809
1810 release:
1811   /* release the aops */
1812   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1813   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1814 }
1815
1816
1817 /*-----------------------------------------------------------------*/
1818 /* genCpl - generate code for complement                           */
1819 /*-----------------------------------------------------------------*/
1820 static void
1821 genCpl (iCode * ic)
1822 {
1823   int offset = 0;
1824   int size;
1825   symbol *tlbl;
1826   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1827
1828   D(emitcode (";", "genCpl"));
1829
1830   /* assign asmOps to operand & result */
1831   aopOp (IC_LEFT (ic), ic, FALSE);
1832   aopOp (IC_RESULT (ic), ic, TRUE);
1833
1834   /* special case if in bit space */
1835   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1836     {
1837       char *l;
1838
1839       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1840           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1841         {
1842           /* promotion rules are responsible for this strange result:
1843              bit -> int -> ~int -> bit
1844              uchar -> int -> ~int -> bit
1845           */
1846           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1847           goto release;
1848         }
1849
1850       tlbl=newiTempLabel(NULL);
1851       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
1852       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1853           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1854           IS_AOP_PREG (IC_LEFT (ic)))
1855         {
1856           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1857         }
1858       else
1859         {
1860           MOVA (l);
1861           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1862         }
1863       emitcode ("", "%05d$:", tlbl->key + 100);
1864       outBitC (IC_RESULT(ic));
1865       goto release;
1866     }
1867
1868   size = AOP_SIZE (IC_RESULT (ic));
1869   while (size--)
1870     {
1871       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1872       MOVA (l);
1873       emitcode ("cpl", "a");
1874       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1875     }
1876
1877
1878 release:
1879   /* release the aops */
1880   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1881   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1882 }
1883
1884 /*-----------------------------------------------------------------*/
1885 /* genUminusFloat - unary minus for floating points                */
1886 /*-----------------------------------------------------------------*/
1887 static void
1888 genUminusFloat (operand * op, operand * result)
1889 {
1890   int size, offset = 0;
1891   char *l;
1892
1893   D(emitcode (";     genUminusFloat",""));
1894
1895   /* for this we just copy and then flip the bit */
1896
1897   size = AOP_SIZE (op) - 1;
1898
1899   while (size--)
1900     {
1901       aopPut (result,
1902               aopGet (op, offset, FALSE, FALSE),
1903               offset,
1904               isOperandVolatile (result, FALSE));
1905       offset++;
1906     }
1907
1908   l = aopGet (op, offset, FALSE, FALSE);
1909
1910   MOVA (l);
1911
1912   emitcode ("cpl", "acc.7");
1913   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
1914 }
1915
1916 /*-----------------------------------------------------------------*/
1917 /* genUminus - unary minus code generation                         */
1918 /*-----------------------------------------------------------------*/
1919 static void
1920 genUminus (iCode * ic)
1921 {
1922   int offset, size;
1923   sym_link *optype, *rtype;
1924
1925
1926   D(emitcode (";     genUminus",""));
1927
1928   /* assign asmops */
1929   aopOp (IC_LEFT (ic), ic, FALSE);
1930   aopOp (IC_RESULT (ic), ic, TRUE);
1931
1932   /* if both in bit space then special
1933      case */
1934   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1935       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1936     {
1937
1938       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1939       emitcode ("cpl", "c");
1940       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1941       goto release;
1942     }
1943
1944   optype = operandType (IC_LEFT (ic));
1945   rtype = operandType (IC_RESULT (ic));
1946
1947   /* if float then do float stuff */
1948   if (IS_FLOAT (optype))
1949     {
1950       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1951       goto release;
1952     }
1953
1954   /* otherwise subtract from zero */
1955   size = AOP_SIZE (IC_LEFT (ic));
1956   offset = 0;
1957   //CLRC ;
1958   while (size--)
1959     {
1960       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1961       if (!strcmp (l, "a"))
1962         {
1963           if (offset == 0)
1964             SETC;
1965           emitcode ("cpl", "a");
1966           emitcode ("addc", "a,#0");
1967         }
1968       else
1969         {
1970           if (offset == 0)
1971             CLRC;
1972           emitcode ("clr", "a");
1973           emitcode ("subb", "a,%s", l);
1974         }
1975       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1976     }
1977
1978   /* if any remaining bytes in the result */
1979   /* we just need to propagate the sign   */
1980   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1981     {
1982       emitcode ("rlc", "a");
1983       emitcode ("subb", "a,acc");
1984       while (size--)
1985         aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1986     }
1987
1988 release:
1989   /* release the aops */
1990   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1991   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1992 }
1993
1994 /*-----------------------------------------------------------------*/
1995 /* saveRegisters - will look for a call and save the registers     */
1996 /*-----------------------------------------------------------------*/
1997 static void
1998 saveRegisters (iCode * lic)
1999 {
2000   int i;
2001   iCode *ic;
2002   bitVect *rsave;
2003
2004   /* look for call */
2005   for (ic = lic; ic; ic = ic->next)
2006     if (ic->op == CALL || ic->op == PCALL)
2007       break;
2008
2009   if (!ic)
2010     {
2011       fprintf (stderr, "found parameter push with no function call\n");
2012       return;
2013     }
2014
2015   /* if the registers have been saved already or don't need to be then
2016      do nothing */
2017   if (ic->regsSaved)
2018     return;
2019   if (IS_SYMOP(IC_LEFT(ic)) &&
2020       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
2021        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
2022     return;
2023
2024   /* save the registers in use at this time but skip the
2025      ones for the result */
2026   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2027                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2028
2029   ic->regsSaved = 1;
2030   if (options.useXstack)
2031     {
2032       int count = bitVectnBitsOn (rsave);
2033
2034       if (count == 1)
2035         {
2036           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2037           if (reg->type == REG_BIT)
2038             {
2039               emitcode ("mov", "a,%s", reg->base);
2040             }
2041           else
2042             {
2043               emitcode ("mov", "a,%s", reg->name);
2044             }
2045           emitcode ("mov", "r0,%s", spname);
2046           emitcode ("inc", "%s", spname);// allocate before use
2047           emitcode ("movx", "@r0,a");
2048           if (bitVectBitValue (rsave, R0_IDX))
2049             emitcode ("mov", "r0,a");
2050         }
2051       else if (count != 0)
2052         {
2053           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2054           int nBits = bitVectnBitsOn (rsavebits);
2055
2056           if (nBits != 0)
2057             {
2058               count = count - nBits + 1;
2059               /* remove all but the first bits as they are pushed all at once */
2060               rsave = bitVectCplAnd (rsave, rsavebits);
2061               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2062             }
2063
2064           if (bitVectBitValue (rsave, R0_IDX))
2065             {
2066               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2067             }
2068           emitcode ("mov", "r0,%s", spname);
2069           MOVA ("r0");
2070           emitcode ("add", "a,#%d", count);
2071           emitcode ("mov", "%s,a", spname);
2072           for (i = 0; i < mcs51_nRegs; i++)
2073             {
2074               if (bitVectBitValue (rsave, i))
2075                 {
2076                   regs * reg = mcs51_regWithIdx (i);
2077                   if (i == R0_IDX)
2078                     {
2079                       emitcode ("pop", "acc");
2080                       emitcode ("push", "acc");
2081                     }
2082                   else if (reg->type == REG_BIT)
2083                     {
2084                       emitcode ("mov", "a,%s", reg->base);
2085                     }
2086                   else
2087                     {
2088                       emitcode ("mov", "a,%s", reg->name);
2089                     }
2090                   emitcode ("movx", "@r0,a");
2091                   if (--count)
2092                     {
2093                       emitcode ("inc", "r0");
2094                     }
2095                 }
2096             }
2097           if (bitVectBitValue (rsave, R0_IDX))
2098             {
2099               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2100             }
2101         }
2102     }
2103   else
2104     {
2105       bool bits_pushed = FALSE;
2106       for (i = 0; i < mcs51_nRegs; i++)
2107         {
2108           if (bitVectBitValue (rsave, i))
2109             {
2110               bits_pushed = pushReg (i, bits_pushed);
2111             }
2112         }
2113     }
2114 }
2115
2116 /*-----------------------------------------------------------------*/
2117 /* unsaveRegisters - pop the pushed registers                      */
2118 /*-----------------------------------------------------------------*/
2119 static void
2120 unsaveRegisters (iCode * ic)
2121 {
2122   int i;
2123   bitVect *rsave;
2124
2125   /* restore the registers in use at this time but skip the
2126      ones for the result */
2127   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2128                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2129
2130   if (options.useXstack)
2131     {
2132       int count = bitVectnBitsOn (rsave);
2133
2134       if (count == 1)
2135         {
2136           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2137           emitcode ("mov", "r0,%s", spname);
2138           emitcode ("dec", "r0");
2139           emitcode ("movx", "a,@r0");
2140           if (reg->type == REG_BIT)
2141             {
2142               emitcode ("mov", "%s,a", reg->base);
2143             }
2144           else
2145             {
2146               emitcode ("mov", "%s,a", reg->name);
2147             }
2148           emitcode ("dec", "%s", spname);
2149         }
2150       else if (count != 0)
2151         {
2152           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2153           int nBits = bitVectnBitsOn (rsavebits);
2154
2155           if (nBits != 0)
2156             {
2157               count = count - nBits + 1;
2158               /* remove all but the first bits as they are popped all at once */
2159               rsave = bitVectCplAnd (rsave, rsavebits);
2160               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2161             }
2162
2163           emitcode ("mov", "r0,%s", spname);
2164           for (i = mcs51_nRegs; i >= 0; i--)
2165             {
2166               if (bitVectBitValue (rsave, i))
2167                 {
2168                   regs * reg = mcs51_regWithIdx (i);
2169                   emitcode ("dec", "r0");
2170                   emitcode ("movx", "a,@r0");
2171                   if (i == R0_IDX)
2172                     {
2173                       emitcode ("push", "acc");
2174                     }
2175                   else if (reg->type == REG_BIT)
2176                     {
2177                       emitcode ("mov", "%s,a", reg->base);
2178                     }
2179                   else
2180                     {
2181                       emitcode ("mov", "%s,a", reg->name);
2182                     }
2183                 }
2184             }
2185           emitcode ("mov", "%s,r0", spname);
2186           if (bitVectBitValue (rsave, R0_IDX))
2187             {
2188               emitcode ("pop", "ar0");
2189             }
2190         }
2191     }
2192   else
2193     {
2194       bool bits_popped = FALSE;
2195       for (i = mcs51_nRegs; i >= 0; i--)
2196         {
2197           if (bitVectBitValue (rsave, i))
2198             {
2199               bits_popped = popReg (i, bits_popped);
2200             }
2201         }
2202     }
2203 }
2204
2205
2206 /*-----------------------------------------------------------------*/
2207 /* pushSide -                                                      */
2208 /*-----------------------------------------------------------------*/
2209 static void
2210 pushSide (operand * oper, int size)
2211 {
2212   int offset = 0;
2213   while (size--)
2214     {
2215       char *l = aopGet (oper, offset++, FALSE, TRUE);
2216       if (AOP_TYPE (oper) != AOP_REG &&
2217           AOP_TYPE (oper) != AOP_DIR &&
2218           strcmp (l, "a"))
2219         {
2220           MOVA (l);
2221           emitcode ("push", "acc");
2222         }
2223       else
2224         {
2225           emitcode ("push", "%s", l);
2226         }
2227     }
2228 }
2229
2230 /*-----------------------------------------------------------------*/
2231 /* assignResultValue - also indicates if acc is in use afterwards  */
2232 /*-----------------------------------------------------------------*/
2233 static bool
2234 assignResultValue (operand * oper, operand * func)
2235 {
2236   int offset = 0;
2237   int size = AOP_SIZE (oper);
2238   bool accuse = FALSE;
2239   bool pushedA = FALSE;
2240
2241   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2242     {
2243       outBitC (oper);
2244       return FALSE;
2245     }
2246
2247   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2248     {
2249       emitcode ("push", "acc");
2250       pushedA = TRUE;
2251     }
2252   while (size--)
2253     {
2254       if ((offset == 3) && pushedA)
2255         emitcode ("pop", "acc");
2256       accuse |= aopPut (oper, fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2257       offset++;
2258     }
2259   return accuse;
2260 }
2261
2262
2263 /*-----------------------------------------------------------------*/
2264 /* genXpush - pushes onto the external stack                       */
2265 /*-----------------------------------------------------------------*/
2266 static void
2267 genXpush (iCode * ic)
2268 {
2269   asmop *aop = newAsmop (0);
2270   regs *r;
2271   int size, offset = 0;
2272
2273   D(emitcode (";     genXpush",""));
2274
2275   aopOp (IC_LEFT (ic), ic, FALSE);
2276   r = getFreePtr (ic, &aop, FALSE);
2277
2278   size = AOP_SIZE (IC_LEFT (ic));
2279
2280   if (size == 1)
2281     {
2282       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2283       emitcode ("mov", "%s,%s", r->name, spname);
2284       emitcode ("inc", "%s", spname); // allocate space first
2285       emitcode ("movx", "@%s,a", r->name);
2286     }
2287   else
2288     {
2289       // allocate space first
2290       emitcode ("mov", "%s,%s", r->name, spname);
2291       MOVA (r->name);
2292       emitcode ("add", "a,#%d", size);
2293       emitcode ("mov", "%s,a", spname);
2294
2295       while (size--)
2296         {
2297           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2298           emitcode ("movx", "@%s,a", r->name);
2299           emitcode ("inc", "%s", r->name);
2300         }
2301     }
2302
2303   freeAsmop (NULL, aop, ic, TRUE);
2304   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2305 }
2306
2307 /*-----------------------------------------------------------------*/
2308 /* genIpush - generate code for pushing this gets a little complex */
2309 /*-----------------------------------------------------------------*/
2310 static void
2311 genIpush (iCode * ic)
2312 {
2313   int size, offset = 0;
2314   char *l;
2315   char *prev = "";
2316
2317   D(emitcode (";     genIpush",""));
2318
2319   /* if this is not a parm push : ie. it is spill push
2320      and spill push is always done on the local stack */
2321   if (!ic->parmPush)
2322     {
2323
2324       /* and the item is spilt then do nothing */
2325       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2326         return;
2327
2328       aopOp (IC_LEFT (ic), ic, FALSE);
2329       size = AOP_SIZE (IC_LEFT (ic));
2330       /* push it on the stack */
2331       while (size--)
2332         {
2333           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2334           if (*l == '#')
2335             {
2336               MOVA (l);
2337               l = "acc";
2338             }
2339           emitcode ("push", "%s", l);
2340         }
2341       return;
2342     }
2343
2344   /* this is a parameter push: in this case we call
2345      the routine to find the call and save those
2346      registers that need to be saved */
2347   saveRegisters (ic);
2348
2349   /* if use external stack then call the external
2350      stack pushing routine */
2351   if (options.useXstack)
2352     {
2353       genXpush (ic);
2354       return;
2355     }
2356
2357   /* then do the push */
2358   aopOp (IC_LEFT (ic), ic, FALSE);
2359
2360   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2361   size = AOP_SIZE (IC_LEFT (ic));
2362
2363   while (size--)
2364     {
2365       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2366       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2367           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2368           strcmp (l, "a"))
2369         {
2370           if (strcmp (l, prev) || *l == '@')
2371             MOVA (l);
2372           emitcode ("push", "acc");
2373         }
2374       else
2375         {
2376           emitcode ("push", "%s", l);
2377         }
2378       prev = l;
2379     }
2380
2381   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* genIpop - recover the registers: can happen only for spilling   */
2386 /*-----------------------------------------------------------------*/
2387 static void
2388 genIpop (iCode * ic)
2389 {
2390   int size, offset;
2391
2392   D(emitcode (";     genIpop",""));
2393
2394   /* if the temp was not pushed then */
2395   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2396     return;
2397
2398   aopOp (IC_LEFT (ic), ic, FALSE);
2399   size = AOP_SIZE (IC_LEFT (ic));
2400   offset = (size - 1);
2401   while (size--)
2402     emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2403                                    FALSE, TRUE));
2404
2405   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2406 }
2407
2408 /*-----------------------------------------------------------------*/
2409 /* saveRBank - saves an entire register bank on the stack          */
2410 /*-----------------------------------------------------------------*/
2411 static void
2412 saveRBank (int bank, iCode * ic, bool pushPsw)
2413 {
2414   int i;
2415   int count = 8 + ((mcs51_nRegs > 8) ? 1 : 0) + (pushPsw ? 1 : 0);
2416   asmop *aop = NULL;
2417   regs *r = NULL;
2418
2419   if (options.useXstack)
2420     {
2421       if (!ic)
2422       {
2423           /* Assume r0 is available for use. */
2424           r = mcs51_regWithIdx (R0_IDX);;
2425       }
2426       else
2427       {
2428           aop = newAsmop (0);
2429           r = getFreePtr (ic, &aop, FALSE);
2430       }
2431       // allocate space first
2432       emitcode ("mov", "%s,%s", r->name, spname);
2433       MOVA (r->name);
2434       emitcode ("add", "a,#%d", count);
2435       emitcode ("mov", "%s,a", spname);
2436     }
2437
2438   for (i = 0; i < 8; i++)
2439     {
2440       if (options.useXstack)
2441         {
2442           emitcode ("mov", "a,(%s+%d)",
2443                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2444           emitcode ("movx", "@%s,a", r->name);
2445           if (--count)
2446             emitcode ("inc", "%s", r->name);
2447         }
2448       else
2449         emitcode ("push", "(%s+%d)",
2450                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2451     }
2452
2453   if (mcs51_nRegs > 8)
2454     {
2455       if (options.useXstack)
2456         {
2457           emitcode ("mov", "a,bits");
2458           emitcode ("movx", "@%s,a", r->name);
2459           if (--count)
2460             emitcode ("inc", "%s", r->name);
2461         }
2462       else
2463         {
2464           emitcode ("push", "bits");
2465         }
2466       BitBankUsed = 1;
2467     }
2468
2469   if (pushPsw)
2470     {
2471       if (options.useXstack)
2472         {
2473           emitcode ("mov", "a,psw");
2474           emitcode ("movx", "@%s,a", r->name);
2475
2476         }
2477       else
2478         {
2479           emitcode ("push", "psw");
2480         }
2481
2482       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2483     }
2484
2485   if (aop)
2486     {
2487       freeAsmop (NULL, aop, ic, TRUE);
2488     }
2489
2490   if (ic)
2491   {
2492     ic->bankSaved = 1;
2493   }
2494 }
2495
2496 /*-----------------------------------------------------------------*/
2497 /* unsaveRBank - restores the register bank from stack             */
2498 /*-----------------------------------------------------------------*/
2499 static void
2500 unsaveRBank (int bank, iCode * ic, bool popPsw)
2501 {
2502   int i;
2503   asmop *aop = NULL;
2504   regs *r = NULL;
2505
2506   if (options.useXstack)
2507     {
2508       if (!ic)
2509         {
2510           /* Assume r0 is available for use. */
2511           r = mcs51_regWithIdx (R0_IDX);;
2512         }
2513       else
2514         {
2515           aop = newAsmop (0);
2516           r = getFreePtr (ic, &aop, FALSE);
2517         }
2518       emitcode ("mov", "%s,%s", r->name, spname);
2519     }
2520
2521   if (popPsw)
2522     {
2523       if (options.useXstack)
2524         {
2525           emitcode ("dec", "%s", r->name);
2526           emitcode ("movx", "a,@%s", r->name);
2527           emitcode ("mov", "psw,a");
2528         }
2529       else
2530         {
2531           emitcode ("pop", "psw");
2532         }
2533     }
2534
2535   if (mcs51_nRegs > 8)
2536     {
2537       if (options.useXstack)
2538         {
2539           emitcode ("dec", "%s", r->name);
2540           emitcode ("movx", "a,@%s", r->name);
2541           emitcode ("mov", "bits,a");
2542         }
2543       else
2544         {
2545           emitcode ("pop", "bits");
2546         }
2547     }
2548
2549   for (i = 7; i >= 0; i--)
2550     {
2551       if (options.useXstack)
2552         {
2553           emitcode ("dec", "%s", r->name);
2554           emitcode ("movx", "a,@%s", r->name);
2555           emitcode ("mov", "(%s+%d),a",
2556                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2557         }
2558       else
2559         {
2560           emitcode ("pop", "(%s+%d)",
2561                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2562         }
2563     }
2564
2565   if (options.useXstack)
2566     {
2567       emitcode ("mov", "%s,%s", spname, r->name);
2568     }
2569
2570   if (aop)
2571     {
2572       freeAsmop (NULL, aop, ic, TRUE);
2573     }
2574 }
2575
2576 /*-----------------------------------------------------------------*/
2577 /* genSend - gen code for SEND                                     */
2578 /*-----------------------------------------------------------------*/
2579 static void genSend(set *sendSet)
2580 {
2581   iCode *sic;
2582   int bit_count = 0;
2583
2584   /* first we do all bit parameters */
2585   for (sic = setFirstItem (sendSet); sic;
2586        sic = setNextItem (sendSet))
2587     {
2588       aopOp (IC_LEFT (sic), sic, FALSE);
2589
2590       if (sic->argreg > 12)
2591         {
2592           int bit = sic->argreg-13;
2593
2594           /* if left is a literal then
2595              we know what the value is */
2596           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2597             {
2598               if (((int) operandLitValue (IC_LEFT (sic))))
2599                   emitcode ("setb", "b[%d]", bit);
2600               else
2601                   emitcode ("clr", "b[%d]", bit);
2602             }
2603           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2604             {
2605               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2606                 if (strcmp (l, "c"))
2607                     emitcode ("mov", "c,%s", l);
2608                 emitcode ("mov", "b[%d],c", bit);
2609             }
2610           else
2611             {
2612               /* we need to or */
2613               toBoolean (IC_LEFT (sic));
2614               /* set C, if a >= 1 */
2615               emitcode ("add", "a,#0xff");
2616               emitcode ("mov", "b[%d],c", bit);
2617             }
2618           bit_count++;
2619           BitBankUsed = 1;
2620         }
2621       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2622     }
2623
2624   if (bit_count)
2625     {
2626       saveRegisters (setFirstItem (sendSet));
2627       emitcode ("mov", "bits,b");
2628     }
2629
2630   /* then we do all other parameters */
2631   for (sic = setFirstItem (sendSet); sic;
2632        sic = setNextItem (sendSet))
2633     {
2634       int size, offset = 0;
2635       aopOp (IC_LEFT (sic), sic, FALSE);
2636       size = AOP_SIZE (IC_LEFT (sic));
2637
2638       if (sic->argreg == 1)
2639         {
2640           while (size--)
2641             {
2642               char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2643               if (strcmp (l, fReturn[offset]))
2644                   emitcode ("mov", "%s,%s", fReturn[offset], l);
2645               offset++;
2646             }
2647         }
2648       else if (sic->argreg <= 12)
2649         {
2650           while (size--)
2651             {
2652               emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2653                         aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2654               offset++;
2655             }
2656         }
2657       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2658     }
2659 }
2660
2661 /*-----------------------------------------------------------------*/
2662 /* selectRegBank - emit code to select the register bank           */
2663 /*-----------------------------------------------------------------*/
2664 static void
2665 selectRegBank (short bank, bool keepFlags)
2666 {
2667   /* if f.e. result is in carry */
2668   if (keepFlags)
2669     {
2670       emitcode ("anl", "psw,#0xE7");
2671       if (bank)
2672         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2673     }
2674   else
2675     {
2676       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2677     }
2678 }
2679
2680 /*-----------------------------------------------------------------*/
2681 /* genCall - generates a call statement                            */
2682 /*-----------------------------------------------------------------*/
2683 static void
2684 genCall (iCode * ic)
2685 {
2686   sym_link *dtype;
2687   sym_link *etype;
2688 //  bool restoreBank = FALSE;
2689   bool swapBanks = FALSE;
2690   bool accuse = FALSE;
2691   bool accPushed = FALSE;
2692   bool resultInF0 = FALSE;
2693
2694   D(emitcode(";     genCall",""));
2695
2696   dtype = operandType (IC_LEFT (ic));
2697   etype = getSpec(dtype);
2698   /* if send set is not empty then assign */
2699   if (_G.sendSet)
2700     {
2701         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2702             genSend(reverseSet(_G.sendSet));
2703         } else {
2704             genSend(_G.sendSet);
2705         }
2706
2707       _G.sendSet = NULL;
2708     }
2709
2710   /* if we are calling a not _naked function that is not using
2711      the same register bank then we need to save the
2712      destination registers on the stack */
2713   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2714       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2715        !IFFUNC_ISISR (dtype))
2716     {
2717       swapBanks = TRUE;
2718     }
2719
2720   /* if caller saves & we have not saved then */
2721   if (!ic->regsSaved)
2722       saveRegisters (ic);
2723
2724   if (swapBanks)
2725     {
2726         emitcode ("mov", "psw,#0x%02x",
2727            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2728     }
2729
2730   /* make the call */
2731   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2732     {
2733       if (IFFUNC_CALLEESAVES(dtype))
2734         {
2735           werror (E_BANKED_WITH_CALLEESAVES);
2736         }
2737       else
2738         {
2739           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2740                      OP_SYMBOL (IC_LEFT (ic))->rname :
2741                      OP_SYMBOL (IC_LEFT (ic))->name);
2742
2743           emitcode ("mov", "r0,#%s", l);
2744           emitcode ("mov", "r1,#(%s >> 8)", l);
2745           emitcode ("mov", "r2,#(%s >> 16)", l);
2746           emitcode ("lcall", "__sdcc_banked_call");
2747         }
2748     }
2749   else
2750     {
2751       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2752                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2753                                 OP_SYMBOL (IC_LEFT (ic))->name));
2754     }
2755
2756   if (swapBanks)
2757     {
2758       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2759     }
2760
2761   /* if we need assign a result value */
2762   if ((IS_ITEMP (IC_RESULT (ic)) &&
2763        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2764        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2765         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2766         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2767       IS_TRUE_SYMOP (IC_RESULT (ic)))
2768     {
2769
2770       _G.accInUse++;
2771       aopOp (IC_RESULT (ic), ic, FALSE);
2772       _G.accInUse--;
2773
2774       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2775
2776       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2777     }
2778
2779   /* adjust the stack for parameters if required */
2780   if (ic->parmBytes)
2781     {
2782       int i;
2783       if (ic->parmBytes > 3)
2784         {
2785           if (accuse)
2786             {
2787               emitcode ("push", "acc");
2788               accPushed = TRUE;
2789             }
2790           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2791               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2792             {
2793               emitcode ("mov", "F0,c");
2794               resultInF0 = TRUE;
2795             }
2796
2797           emitcode ("mov", "a,%s", spname);
2798           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2799           emitcode ("mov", "%s,a", spname);
2800
2801           /* unsaveRegisters from xstack needs acc, but */
2802           /* unsaveRegisters from stack needs this popped */
2803           if (accPushed && !options.useXstack)
2804             {
2805               emitcode ("pop", "acc");
2806               accPushed = FALSE;
2807             }
2808         }
2809       else
2810         for (i = 0; i < ic->parmBytes; i++)
2811           emitcode ("dec", "%s", spname);
2812     }
2813
2814   /* if we had saved some registers then unsave them */
2815   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2816     {
2817       if (accuse && !accPushed && options.useXstack)
2818         {
2819           /* xstack needs acc, but doesn't touch normal stack */
2820           emitcode ("push", "acc");
2821           accPushed = TRUE;
2822         }
2823       unsaveRegisters (ic);
2824     }
2825
2826 //  /* if register bank was saved then pop them */
2827 //  if (restoreBank)
2828 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2829
2830   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2831     {
2832       if (resultInF0)
2833           emitcode ("mov", "c,F0");
2834
2835       aopOp (IC_RESULT (ic), ic, FALSE);
2836       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2837       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2838     }
2839
2840   if (accPushed)
2841     emitcode ("pop", "acc");
2842 }
2843
2844 /*-----------------------------------------------------------------*/
2845 /* -10l - generates a call by pointer statement                */
2846 /*-----------------------------------------------------------------*/
2847 static void
2848 genPcall (iCode * ic)
2849 {
2850   sym_link *dtype;
2851   sym_link *etype;
2852   symbol *rlbl = newiTempLabel (NULL);
2853 //  bool restoreBank=FALSE;
2854   bool swapBanks = FALSE;
2855   bool resultInF0 = FALSE;
2856
2857   D(emitcode(";     genPCall",""));
2858
2859   dtype = operandType (IC_LEFT (ic))->next;
2860   etype = getSpec(dtype);
2861   /* if caller saves & we have not saved then */
2862   if (!ic->regsSaved)
2863     saveRegisters (ic);
2864
2865   /* if we are calling a not _naked function that is not using
2866      the same register bank then we need to save the
2867      destination registers on the stack */
2868   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2869       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2870       !IFFUNC_ISISR (dtype))
2871     {
2872 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2873 //    restoreBank=TRUE;
2874       swapBanks = TRUE;
2875       // need caution message to user here
2876     }
2877
2878   if (IS_LITERAL(etype))
2879     {
2880       /* if send set is not empty then assign */
2881       if (_G.sendSet)
2882         {
2883           genSend(reverseSet(_G.sendSet));
2884           _G.sendSet = NULL;
2885         }
2886
2887       if (swapBanks)
2888         {
2889           emitcode ("mov", "psw,#0x%02x",
2890            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2891         }
2892
2893       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2894         {
2895           if (IFFUNC_CALLEESAVES(dtype))
2896             {
2897               werror (E_BANKED_WITH_CALLEESAVES);
2898             }
2899           else
2900             {
2901               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
2902
2903               emitcode ("mov", "r0,#%s", l);
2904               emitcode ("mov", "r1,#(%s >> 8)", l);
2905               emitcode ("mov", "r2,#(%s >> 16)", l);
2906               emitcode ("lcall", "__sdcc_banked_call");
2907             }
2908         }
2909       else
2910         {
2911           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
2912         }
2913     }
2914   else
2915     {
2916       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2917         {
2918           if (IFFUNC_CALLEESAVES(dtype))
2919             {
2920               werror (E_BANKED_WITH_CALLEESAVES);
2921             }
2922           else
2923             {
2924               aopOp (IC_LEFT (ic), ic, FALSE);
2925
2926               if (!swapBanks)
2927                 {
2928                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2929                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2930                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2931                 }
2932               else
2933                 {
2934                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
2935                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2936                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2937                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2938                 }
2939
2940               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2941
2942               /* if send set is not empty then assign */
2943               if (_G.sendSet)
2944                 {
2945                   genSend(reverseSet(_G.sendSet));
2946                   _G.sendSet = NULL;
2947                 }
2948
2949               if (swapBanks)
2950                 {
2951                   emitcode ("mov", "psw,#0x%02x",
2952                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2953                 }
2954
2955               /* make the call */
2956               emitcode ("lcall", "__sdcc_banked_call");
2957             }
2958         }
2959       else
2960         {
2961           /* push the return address on to the stack */
2962           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2963           emitcode ("push", "acc");
2964           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2965           emitcode ("push", "acc");
2966
2967           /* now push the calling address */
2968           aopOp (IC_LEFT (ic), ic, FALSE);
2969
2970           pushSide (IC_LEFT (ic), FPTRSIZE);
2971
2972           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2973
2974           /* if send set is not empty the assign */
2975           if (_G.sendSet)
2976             {
2977               genSend(reverseSet(_G.sendSet));
2978               _G.sendSet = NULL;
2979             }
2980
2981           if (swapBanks)
2982             {
2983               emitcode ("mov", "psw,#0x%02x",
2984                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2985             }
2986
2987           /* make the call */
2988           emitcode ("ret", "");
2989           emitcode ("", "%05d$:", (rlbl->key + 100));
2990         }
2991     }
2992   if (swapBanks)
2993     {
2994       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2995     }
2996
2997   /* if we need assign a result value */
2998   if ((IS_ITEMP (IC_RESULT (ic)) &&
2999        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3000        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3001         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3002       IS_TRUE_SYMOP (IC_RESULT (ic)))
3003     {
3004
3005       _G.accInUse++;
3006       aopOp (IC_RESULT (ic), ic, FALSE);
3007       _G.accInUse--;
3008
3009       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3010
3011       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3012     }
3013
3014   /* adjust the stack for parameters if required */
3015   if (ic->parmBytes)
3016     {
3017       int i;
3018       if (ic->parmBytes > 3)
3019         {
3020           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3021               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3022             {
3023               emitcode ("mov", "F0,c");
3024               resultInF0 = TRUE;
3025             }
3026
3027           emitcode ("mov", "a,%s", spname);
3028           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3029           emitcode ("mov", "%s,a", spname);
3030         }
3031       else
3032         for (i = 0; i < ic->parmBytes; i++)
3033           emitcode ("dec", "%s", spname);
3034
3035     }
3036
3037 //  /* if register bank was saved then unsave them */
3038 //  if (restoreBank)
3039 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3040
3041   /* if we had saved some registers then unsave them */
3042   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3043     unsaveRegisters (ic);
3044
3045   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3046     {
3047       if (resultInF0)
3048           emitcode ("mov", "c,F0");
3049
3050       aopOp (IC_RESULT (ic), ic, FALSE);
3051       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3052       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3053     }
3054 }
3055
3056 /*-----------------------------------------------------------------*/
3057 /* resultRemat - result  is rematerializable                       */
3058 /*-----------------------------------------------------------------*/
3059 static int
3060 resultRemat (iCode * ic)
3061 {
3062   if (SKIP_IC (ic) || ic->op == IFX)
3063     return 0;
3064
3065   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3066     {
3067       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3068       if (sym->remat && !POINTER_SET (ic))
3069         return 1;
3070     }
3071
3072   return 0;
3073 }
3074
3075 #if defined(__BORLANDC__) || defined(_MSC_VER)
3076 #define STRCASECMP stricmp
3077 #else
3078 #define STRCASECMP strcasecmp
3079 #endif
3080
3081 /*-----------------------------------------------------------------*/
3082 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3083 /*-----------------------------------------------------------------*/
3084 static int
3085 regsCmp(void *p1, void *p2)
3086 {
3087   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3088 }
3089
3090 static bool
3091 inExcludeList (char *s)
3092 {
3093   const char *p = setFirstItem(options.excludeRegsSet);
3094
3095   if (p == NULL || STRCASECMP(p, "none") == 0)
3096     return FALSE;
3097
3098
3099   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3100 }
3101
3102 /*-----------------------------------------------------------------*/
3103 /* genFunction - generated code for function entry                 */
3104 /*-----------------------------------------------------------------*/
3105 static void
3106 genFunction (iCode * ic)
3107 {
3108   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3109   sym_link *ftype;
3110   bool     switchedPSW = FALSE;
3111   int      calleesaves_saved_register = -1;
3112   int      stackAdjust = sym->stack;
3113   int      accIsFree = sym->recvSize < 4;
3114   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3115   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3116
3117   _G.nRegsSaved = 0;
3118   /* create the function header */
3119   emitcode (";", "-----------------------------------------");
3120   emitcode (";", " function %s", sym->name);
3121   emitcode (";", "-----------------------------------------");
3122
3123   emitcode ("", "%s:", sym->rname);
3124   ftype = operandType (IC_LEFT (ic));
3125   _G.currentFunc = sym;
3126
3127   if (IFFUNC_ISNAKED(ftype))
3128   {
3129       emitcode(";", "naked function: no prologue.");
3130       return;
3131   }
3132
3133   /* here we need to generate the equates for the
3134      register bank if required */
3135   if (FUNC_REGBANK (ftype) != rbank)
3136     {
3137       int i;
3138
3139       rbank = FUNC_REGBANK (ftype);
3140       for (i = 0; i < mcs51_nRegs; i++)
3141         {
3142           if (regs8051[i].type != REG_BIT)
3143             {
3144               if (strcmp (regs8051[i].base, "0") == 0)
3145                 emitcode ("", "%s = 0x%02x",
3146                           regs8051[i].dname,
3147                           8 * rbank + regs8051[i].offset);
3148               else
3149                 emitcode ("", "%s = %s + 0x%02x",
3150                           regs8051[i].dname,
3151                           regs8051[i].base,
3152                           8 * rbank + regs8051[i].offset);
3153             }
3154         }
3155     }
3156
3157   /* if this is an interrupt service routine then
3158      save acc, b, dpl, dph  */
3159   if (IFFUNC_ISISR (sym->type))
3160     {
3161
3162       if (!inExcludeList ("acc"))
3163         emitcode ("push", "acc");
3164       if (!inExcludeList ("b"))
3165         emitcode ("push", "b");
3166       if (!inExcludeList ("dpl"))
3167         emitcode ("push", "dpl");
3168       if (!inExcludeList ("dph"))
3169         emitcode ("push", "dph");
3170       /* if this isr has no bank i.e. is going to
3171          run with bank 0 , then we need to save more
3172          registers :-) */
3173       if (!FUNC_REGBANK (sym->type))
3174         {
3175
3176           /* if this function does not call any other
3177              function then we can be economical and
3178              save only those registers that are used */
3179           if (!IFFUNC_HASFCALL(sym->type))
3180             {
3181               int i;
3182
3183               /* if any registers used */
3184               if (sym->regsUsed)
3185                 {
3186                   bool bits_pushed = FALSE;
3187                   /* save the registers used */
3188                   for (i = 0; i < sym->regsUsed->size; i++)
3189                     {
3190                       if (bitVectBitValue (sym->regsUsed, i))
3191                         bits_pushed = pushReg (i, bits_pushed);
3192                     }
3193                 }
3194             }
3195           else
3196             {
3197
3198               /* this function has a function call. We cannot
3199                  determines register usage so we will have to push the
3200                  entire bank */
3201                 saveRBank (0, ic, FALSE);
3202                 if (options.parms_in_bank1) {
3203                     int i;
3204                     for (i=0; i < 8 ; i++ ) {
3205                         emitcode ("push","%s",rb1regs[i]);
3206                     }
3207                 }
3208             }
3209         }
3210         else
3211         {
3212             /* This ISR uses a non-zero bank.
3213              *
3214              * We assume that the bank is available for our
3215              * exclusive use.
3216              *
3217              * However, if this ISR calls a function which uses some
3218              * other bank, we must save that bank entirely.
3219              */
3220             unsigned long banksToSave = 0;
3221
3222             if (IFFUNC_HASFCALL(sym->type))
3223             {
3224
3225 #define MAX_REGISTER_BANKS 4
3226
3227                 iCode *i;
3228                 int ix;
3229
3230                 for (i = ic; i; i = i->next)
3231                 {
3232                     if (i->op == ENDFUNCTION)
3233                     {
3234                         /* we got to the end OK. */
3235                         break;
3236                     }
3237
3238                     if (i->op == CALL)
3239                     {
3240                         sym_link *dtype;
3241
3242                         dtype = operandType (IC_LEFT(i));
3243                         if (dtype
3244                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3245                         {
3246                              /* Mark this bank for saving. */
3247                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3248                              {
3249                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3250                              }
3251                              else
3252                              {
3253                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3254                              }
3255
3256                              /* And note that we don't need to do it in
3257                               * genCall.
3258                               */
3259                              i->bankSaved = 1;
3260                         }
3261                     }
3262                     if (i->op == PCALL)
3263                     {
3264                         /* This is a mess; we have no idea what
3265                          * register bank the called function might
3266                          * use.
3267                          *
3268                          * The only thing I can think of to do is
3269                          * throw a warning and hope.
3270                          */
3271                         werror(W_FUNCPTR_IN_USING_ISR);
3272                     }
3273                 }
3274
3275                 if (banksToSave && options.useXstack)
3276                 {
3277                     /* Since we aren't passing it an ic,
3278                      * saveRBank will assume r0 is available to abuse.
3279                      *
3280                      * So switch to our (trashable) bank now, so
3281                      * the caller's R0 isn't trashed.
3282                      */
3283                     emitcode ("push", "psw");
3284                     emitcode ("mov", "psw,#0x%02x",
3285                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3286                     switchedPSW = TRUE;
3287                 }
3288
3289                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3290                 {
3291                      if (banksToSave & (1 << ix))
3292                      {
3293                          saveRBank(ix, NULL, FALSE);
3294                      }
3295                 }
3296             }
3297             // TODO: this needs a closer look
3298             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3299         }
3300
3301       /* Set the register bank to the desired value if nothing else */
3302       /* has done so yet. */
3303       if (!switchedPSW)
3304         {
3305           emitcode ("push", "psw");
3306           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3307         }
3308     }
3309   else
3310     {
3311       /* This is a non-ISR function. The caller has already switched register */
3312       /* banks, if necessary, so just handle the callee-saves option. */
3313
3314       /* if callee-save to be used for this function
3315          then save the registers being used in this function */
3316       if (IFFUNC_CALLEESAVES(sym->type))
3317         {
3318           int i;
3319
3320           /* if any registers used */
3321           if (sym->regsUsed)
3322             {
3323               bool bits_pushed = FALSE;
3324               /* save the registers used */
3325               for (i = 0; i < sym->regsUsed->size; i++)
3326                 {
3327                   if (bitVectBitValue (sym->regsUsed, i))
3328                     {
3329                       /* remember one saved register for later usage */
3330                       if (calleesaves_saved_register < 0)
3331                         calleesaves_saved_register = i;
3332                       bits_pushed = pushReg (i, bits_pushed);
3333                       _G.nRegsSaved++;
3334                     }
3335                 }
3336             }
3337         }
3338     }
3339
3340
3341   if (fReentrant)
3342     {
3343       if (options.useXstack)
3344         {
3345           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3346             {
3347               emitcode ("mov", "r0,%s", spname);
3348               emitcode ("inc", "%s", spname);
3349               emitcode ("xch", "a,_bpx");
3350               emitcode ("movx", "@r0,a");
3351               emitcode ("inc", "r0");
3352               emitcode ("mov", "a,r0");
3353               emitcode ("xch", "a,_bpx");
3354             }
3355           if (sym->stack)
3356             {
3357               emitcode ("push", "_bp");     /* save the callers stack  */
3358               emitcode ("mov", "_bp,sp");
3359             }
3360         }
3361       else
3362         {
3363           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3364             {
3365               /* set up the stack */
3366               emitcode ("push", "_bp");     /* save the callers stack  */
3367               emitcode ("mov", "_bp,sp");
3368             }
3369         }
3370     }
3371
3372   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3373   /* before setting up the stack frame completely. */
3374   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3375     {
3376       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3377
3378       if (rsym->isitmp)
3379         {
3380           if (rsym && rsym->regType == REG_CND)
3381             rsym = NULL;
3382           if (rsym && (rsym->accuse || rsym->ruonly))
3383             rsym = NULL;
3384           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3385             rsym = rsym->usl.spillLoc;
3386         }
3387
3388       /* If the RECEIVE operand immediately spills to the first entry on the */
3389       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3390       /* rather than the usual @r0/r1 machinations. */
3391       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3392         {
3393           int ofs;
3394
3395           _G.current_iCode = ric;
3396           D(emitcode (";     genReceive",""));
3397           for (ofs=0; ofs < sym->recvSize; ofs++)
3398             {
3399               if (!strcmp (fReturn[ofs], "a"))
3400                 emitcode ("push", "acc");
3401               else
3402                 emitcode ("push", fReturn[ofs]);
3403             }
3404           stackAdjust -= sym->recvSize;
3405           if (stackAdjust<0)
3406             {
3407               assert (stackAdjust>=0);
3408               stackAdjust = 0;
3409             }
3410           _G.current_iCode = ic;
3411           ric->generated = 1;
3412           accIsFree = 1;
3413         }
3414       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3415       /* to free up the accumulator. */
3416       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3417         {
3418           int ofs;
3419
3420           _G.current_iCode = ric;
3421           D(emitcode (";     genReceive",""));
3422           for (ofs=0; ofs < sym->recvSize; ofs++)
3423             {
3424               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3425             }
3426           _G.current_iCode = ic;
3427           ric->generated = 1;
3428           accIsFree = 1;
3429         }
3430     }
3431
3432   /* adjust the stack for the function */
3433   if (stackAdjust)
3434     {
3435       int i = stackAdjust;
3436       if (i > 256)
3437         werror (W_STACK_OVERFLOW, sym->name);
3438
3439       if (i > 3 && accIsFree)
3440         {
3441           emitcode ("mov", "a,sp");
3442           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3443           emitcode ("mov", "sp,a");
3444         }
3445       else if (i > 5)
3446         {
3447           /* The accumulator is not free, so we will need another register */
3448           /* to clobber. No need to worry about a possible conflict with */
3449           /* the above early RECEIVE optimizations since they would have */
3450           /* freed the accumulator if they were generated. */
3451
3452           if (IFFUNC_CALLEESAVES(sym->type))
3453             {
3454               /* if it's a callee-saves function we need a saved register */
3455               if (calleesaves_saved_register >= 0)
3456                 {
3457                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3458                   emitcode ("mov", "a,sp");
3459                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3460                   emitcode ("mov", "sp,a");
3461                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3462                 }
3463               else
3464                 /* do it the hard way */
3465                 while (i--)
3466                   emitcode ("inc", "sp");
3467             }
3468           else
3469             {
3470               /* not callee-saves, we can clobber r0 */
3471               emitcode ("mov", "r0,a");
3472               emitcode ("mov", "a,sp");
3473               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3474               emitcode ("mov", "sp,a");
3475               emitcode ("mov", "a,r0");
3476             }
3477         }
3478       else
3479         while (i--)
3480           emitcode ("inc", "sp");
3481     }
3482
3483   if (sym->xstack)
3484     {
3485       char i = ((char) sym->xstack & 0xff);
3486
3487       if (i > 3 && accIsFree)
3488         {
3489           emitcode ("mov", "a,_spx");
3490           emitcode ("add", "a,#0x%02x", i);
3491           emitcode ("mov", "_spx,a");
3492         }
3493       else if (i > 5)
3494         {
3495           emitcode ("push", "acc");
3496           emitcode ("mov", "a,_spx");
3497           emitcode ("add", "a,#0x%02x", i);
3498           emitcode ("mov", "_spx,a");
3499           emitcode ("pop", "acc");
3500         }
3501       else
3502         {
3503           while (i--)
3504             emitcode ("inc", "_spx");
3505         }
3506     }
3507
3508   /* if critical function then turn interrupts off */
3509   if (IFFUNC_ISCRITICAL (ftype))
3510     {
3511       symbol *tlbl = newiTempLabel (NULL);
3512       emitcode ("setb", "c");
3513       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3514       emitcode ("clr", "c");
3515       emitcode ("", "%05d$:", (tlbl->key + 100));
3516       emitcode ("push", "psw"); /* save old ea via c in psw */
3517     }
3518 }
3519
3520 /*-----------------------------------------------------------------*/
3521 /* genEndFunction - generates epilogue for functions               */
3522 /*-----------------------------------------------------------------*/
3523 static void
3524 genEndFunction (iCode * ic)
3525 {
3526   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3527   lineNode *lnp = lineCurr;
3528   bitVect  *regsUsed;
3529   bitVect  *regsUsedPrologue;
3530   bitVect  *regsUnneeded;
3531   int      idx;
3532
3533   _G.currentFunc = NULL;
3534   if (IFFUNC_ISNAKED(sym->type))
3535   {
3536       emitcode(";", "naked function: no epilogue.");
3537       if (options.debug && currFunc)
3538         debugFile->writeEndFunction (currFunc, ic, 0);
3539       return;
3540   }
3541
3542   if (IFFUNC_ISCRITICAL (sym->type))
3543     {
3544       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3545         {
3546           emitcode ("rlc", "a");   /* save c in a */
3547           emitcode ("pop", "psw"); /* restore ea via c in psw */
3548           emitcode ("mov", "ea,c");
3549           emitcode ("rrc", "a");   /* restore c from a */
3550         }
3551       else
3552         {
3553           emitcode ("pop", "psw"); /* restore ea via c in psw */
3554           emitcode ("mov", "ea,c");
3555         }
3556     }
3557
3558   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3559     {
3560       if (options.useXstack)
3561         {
3562           if (sym->stack)
3563             {
3564               emitcode ("mov", "sp,_bp");
3565               emitcode ("pop", "_bp");
3566             }
3567           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3568             {
3569               emitcode ("xch", "a,_bpx");
3570               emitcode ("mov", "r0,a");
3571               emitcode ("dec", "r0");
3572               emitcode ("movx", "a,@r0");
3573               emitcode ("xch", "a,_bpx");
3574               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3575             }
3576         }
3577       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3578         {
3579           emitcode ("mov", "sp,_bp");
3580           emitcode ("pop", "_bp");
3581         }
3582     }
3583
3584   /* restore the register bank  */
3585   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3586   {
3587     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3588      || !options.useXstack)
3589     {
3590         /* Special case of ISR using non-zero bank with useXstack
3591          * is handled below.
3592          */
3593         emitcode ("pop", "psw");
3594     }
3595   }
3596
3597   if (IFFUNC_ISISR (sym->type))
3598     {
3599
3600       /* now we need to restore the registers */
3601       /* if this isr has no bank i.e. is going to
3602          run with bank 0 , then we need to save more
3603          registers :-) */
3604       if (!FUNC_REGBANK (sym->type))
3605         {
3606           /* if this function does not call any other
3607              function then we can be economical and
3608              save only those registers that are used */
3609           if (!IFFUNC_HASFCALL(sym->type))
3610             {
3611               int i;
3612
3613               /* if any registers used */
3614               if (sym->regsUsed)
3615                 {
3616                   bool bits_popped = FALSE;
3617                   /* save the registers used */
3618                   for (i = sym->regsUsed->size; i >= 0; i--)
3619                     {
3620                       if (bitVectBitValue (sym->regsUsed, i))
3621                         bits_popped = popReg (i, bits_popped);
3622                     }
3623                 }
3624             }
3625           else
3626             {
3627               if (options.parms_in_bank1) {
3628                   int i;
3629                   for (i = 7 ; i >= 0 ; i-- ) {
3630                       emitcode ("pop","%s",rb1regs[i]);
3631                   }
3632               }
3633               /* this function has  a function call cannot
3634                  determines register usage so we will have to pop the
3635                  entire bank */
3636               unsaveRBank (0, ic, FALSE);
3637             }
3638         }
3639         else
3640         {
3641             /* This ISR uses a non-zero bank.
3642              *
3643              * Restore any register banks saved by genFunction
3644              * in reverse order.
3645              */
3646             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3647             int ix;
3648
3649             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3650             {
3651                 if (savedBanks & (1 << ix))
3652                 {
3653                     unsaveRBank(ix, NULL, FALSE);
3654                 }
3655             }
3656
3657             if (options.useXstack)
3658             {
3659                 /* Restore bank AFTER calling unsaveRBank,
3660                  * since it can trash r0.
3661                  */
3662                 emitcode ("pop", "psw");
3663             }
3664         }
3665
3666       if (!inExcludeList ("dph"))
3667         emitcode ("pop", "dph");
3668       if (!inExcludeList ("dpl"))
3669         emitcode ("pop", "dpl");
3670       if (!inExcludeList ("b"))
3671         emitcode ("pop", "b");
3672       if (!inExcludeList ("acc"))
3673         emitcode ("pop", "acc");
3674
3675       /* if debug then send end of function */
3676       if (options.debug && currFunc)
3677         {
3678           debugFile->writeEndFunction (currFunc, ic, 1);
3679         }
3680
3681       emitcode ("reti", "");
3682     }
3683   else
3684     {
3685       if (IFFUNC_CALLEESAVES(sym->type))
3686         {
3687           int i;
3688
3689           /* if any registers used */
3690           if (sym->regsUsed)
3691             {
3692               /* save the registers used */
3693               for (i = sym->regsUsed->size; i >= 0; i--)
3694                 {
3695                   if (bitVectBitValue (sym->regsUsed, i) ||
3696                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3697                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3698                 }
3699             }
3700           else if (mcs51_ptrRegReq)
3701             {
3702               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3703               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3704             }
3705
3706         }
3707
3708       /* if debug then send end of function */
3709       if (options.debug && currFunc)
3710         {
3711           debugFile->writeEndFunction (currFunc, ic, 1);
3712         }
3713
3714       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3715         {
3716           emitcode ("ljmp", "__sdcc_banked_ret");
3717         }
3718       else
3719         {
3720           emitcode ("ret", "");
3721         }
3722     }
3723
3724   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3725     return;
3726
3727   /* If this was an interrupt handler using bank 0 that called another */
3728   /* function, then all registers must be saved; nothing to optimized. */
3729   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3730       && !FUNC_REGBANK(sym->type))
3731     return;
3732
3733   /* There are no push/pops to optimize if not callee-saves or ISR */
3734   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3735     return;
3736
3737   /* If there were stack parameters, we cannot optimize without also    */
3738   /* fixing all of the stack offsets; this is too dificult to consider. */
3739   if (FUNC_HASSTACKPARM(sym->type))
3740     return;
3741
3742   /* Compute the registers actually used */
3743   regsUsed = newBitVect (mcs51_nRegs);
3744   regsUsedPrologue = newBitVect (mcs51_nRegs);
3745   while (lnp)
3746     {
3747       if (lnp->ic && lnp->ic->op == FUNCTION)
3748         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3749       else
3750         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3751
3752       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3753           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3754         break;
3755       if (!lnp->prev)
3756         break;
3757       lnp = lnp->prev;
3758     }
3759
3760   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3761       && !bitVectBitValue (regsUsed, CND_IDX))
3762     {
3763       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3764       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3765           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3766         bitVectUnSetBit (regsUsed, CND_IDX);
3767     }
3768   else
3769     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3770
3771   /* If this was an interrupt handler that called another function */
3772   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3773   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3774     {
3775       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3776       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3777       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3778       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3779       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3780     }
3781
3782   /* Remove the unneeded push/pops */
3783   regsUnneeded = newBitVect (mcs51_nRegs);
3784   while (lnp)
3785     {
3786       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3787         {
3788           if (!strncmp(lnp->line, "push", 4))
3789             {
3790               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3791               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3792                 {
3793                   connectLine (lnp->prev, lnp->next);
3794                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3795                 }
3796             }
3797           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3798             {
3799               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3800               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3801                 {
3802                   connectLine (lnp->prev, lnp->next);
3803                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3804                 }
3805             }
3806         }
3807       lnp = lnp->next;
3808     }
3809
3810   for (idx = 0; idx < regsUnneeded->size; idx++)
3811     if (bitVectBitValue (regsUnneeded, idx))
3812       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3813
3814   freeBitVect (regsUnneeded);
3815   freeBitVect (regsUsed);
3816   freeBitVect (regsUsedPrologue);
3817 }
3818
3819 /*-----------------------------------------------------------------*/
3820 /* genRet - generate code for return statement                     */
3821 /*-----------------------------------------------------------------*/
3822 static void
3823 genRet (iCode * ic)
3824 {
3825   int size, offset = 0, pushed = 0;
3826
3827   D(emitcode (";     genRet",""));
3828
3829   /* if we have no return value then
3830      just generate the "ret" */
3831   if (!IC_LEFT (ic))
3832     goto jumpret;
3833
3834   /* we have something to return then
3835      move the return value into place */
3836   aopOp (IC_LEFT (ic), ic, FALSE);
3837   size = AOP_SIZE (IC_LEFT (ic));
3838
3839
3840   if (IS_BIT(_G.currentFunc->etype))
3841     {
3842       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3843       size = 0;
3844     }
3845
3846   while (size--)
3847     {
3848       char *l;
3849       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3850         {
3851           /* #NOCHANGE */
3852           l = aopGet (IC_LEFT (ic), offset++,
3853                       FALSE, TRUE);
3854           emitcode ("push", "%s", l);
3855           pushed++;
3856         }
3857       else
3858         {
3859           l = aopGet (IC_LEFT (ic), offset,
3860                       FALSE, FALSE);
3861           if (strcmp (fReturn[offset], l))
3862             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3863         }
3864     }
3865
3866   while (pushed)
3867     {
3868       pushed--;
3869       if (strcmp (fReturn[pushed], "a"))
3870         emitcode ("pop", fReturn[pushed]);
3871       else
3872         emitcode ("pop", "acc");
3873     }
3874   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3875
3876 jumpret:
3877   /* generate a jump to the return label
3878      if the next is not the return statement */
3879   if (!(ic->next && ic->next->op == LABEL &&
3880         IC_LABEL (ic->next) == returnLabel))
3881
3882     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3883
3884 }
3885
3886 /*-----------------------------------------------------------------*/
3887 /* genLabel - generates a label                                    */
3888 /*-----------------------------------------------------------------*/
3889 static void
3890 genLabel (iCode * ic)
3891 {
3892   /* special case never generate */
3893   if (IC_LABEL (ic) == entryLabel)
3894     return;
3895
3896   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3897 }
3898
3899 /*-----------------------------------------------------------------*/
3900 /* genGoto - generates a ljmp                                      */
3901 /*-----------------------------------------------------------------*/
3902 static void
3903 genGoto (iCode * ic)
3904 {
3905   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3906 }
3907
3908 /*-----------------------------------------------------------------*/
3909 /* findLabelBackwards: walks back through the iCode chain looking  */
3910 /* for the given label. Returns number of iCode instructions     */
3911 /* between that label and given ic.          */
3912 /* Returns zero if label not found.          */
3913 /*-----------------------------------------------------------------*/
3914 static int
3915 findLabelBackwards (iCode * ic, int key)
3916 {
3917   int count = 0;
3918
3919   while (ic->prev)
3920     {
3921       ic = ic->prev;
3922       count++;
3923
3924       /* If we have any pushes or pops, we cannot predict the distance.
3925          I don't like this at all, this should be dealt with in the
3926          back-end */
3927       if (ic->op == IPUSH || ic->op == IPOP) {
3928         return 0;
3929       }
3930
3931       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3932         {
3933           return count;
3934         }
3935     }
3936
3937   return 0;
3938 }
3939
3940 /*-----------------------------------------------------------------*/
3941 /* genPlusIncr :- does addition with increment if possible         */
3942 /*-----------------------------------------------------------------*/
3943 static bool
3944 genPlusIncr (iCode * ic)
3945 {
3946   unsigned int icount;
3947   unsigned int size = getDataSize (IC_RESULT (ic));
3948
3949   /* will try to generate an increment */
3950   /* if the right side is not a literal
3951      we cannot */
3952   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3953     return FALSE;
3954
3955   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3956
3957   D(emitcode (";     genPlusIncr",""));
3958
3959   /* if increment >=16 bits in register or direct space */
3960   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3961       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3962       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
3963       (size > 1) &&
3964       (icount == 1))
3965     {
3966       symbol *tlbl;
3967       int emitTlbl;
3968       int labelRange;
3969
3970       /* If the next instruction is a goto and the goto target
3971        * is < 10 instructions previous to this, we can generate
3972        * jumps straight to that target.
3973        */
3974       if (ic->next && ic->next->op == GOTO
3975           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3976           && labelRange <= 10)
3977         {
3978           emitcode (";", "tail increment optimized");
3979           tlbl = IC_LABEL (ic->next);
3980           emitTlbl = 0;
3981         }
3982       else
3983         {
3984           tlbl = newiTempLabel (NULL);
3985           emitTlbl = 1;
3986         }
3987       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3988       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3989           IS_AOP_PREG (IC_RESULT (ic)))
3990         emitcode ("cjne", "%s,#0x00,%05d$",
3991                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3992                   tlbl->key + 100);
3993       else
3994         {
3995           emitcode ("clr", "a");
3996           emitcode ("cjne", "a,%s,%05d$",
3997                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3998                     tlbl->key + 100);
3999         }
4000
4001       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4002       if (size > 2)
4003         {
4004           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4005               IS_AOP_PREG (IC_RESULT (ic)))
4006             emitcode ("cjne", "%s,#0x00,%05d$",
4007                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4008                       tlbl->key + 100);
4009           else
4010             emitcode ("cjne", "a,%s,%05d$",
4011                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4012                       tlbl->key + 100);
4013
4014           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4015         }
4016       if (size > 3)
4017         {
4018           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4019               IS_AOP_PREG (IC_RESULT (ic)))
4020             emitcode ("cjne", "%s,#0x00,%05d$",
4021                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4022                       tlbl->key + 100);
4023           else
4024             {
4025               emitcode ("cjne", "a,%s,%05d$",
4026                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4027                         tlbl->key + 100);
4028             }
4029           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4030         }
4031
4032       if (emitTlbl)
4033         {
4034           emitcode ("", "%05d$:", tlbl->key + 100);
4035         }
4036       return TRUE;
4037     }
4038
4039   /* if result is dptr */
4040   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4041       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4042       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4043       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4044     {
4045       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4046         return FALSE;
4047
4048       if (icount > 9)
4049         return FALSE;
4050
4051       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4052         return FALSE;
4053
4054       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
4055       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
4056       while (icount--)
4057         emitcode ("inc", "dptr");
4058
4059       return TRUE;
4060     }
4061
4062   /* if the literal value of the right hand side
4063      is greater than 4 then it is not worth it */
4064   if (icount > 4)
4065     return FALSE;
4066
4067   /* if the sizes are greater than 1 then we cannot */
4068   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4069       AOP_SIZE (IC_LEFT (ic)) > 1)
4070     return FALSE;
4071
4072   /* we can if the aops of the left & result match or
4073      if they are in registers and the registers are the
4074      same */
4075   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4076     {
4077
4078       if (icount > 3)
4079         {
4080           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4081           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4082           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4083         }
4084       else
4085         {
4086
4087           while (icount--)
4088             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4089         }
4090
4091       return TRUE;
4092     }
4093
4094   return FALSE;
4095 }
4096
4097 /*-----------------------------------------------------------------*/
4098 /* outBitAcc - output a bit in acc                                 */
4099 /*-----------------------------------------------------------------*/
4100 static void
4101 outBitAcc (operand * result)
4102 {
4103   symbol *tlbl = newiTempLabel (NULL);
4104   /* if the result is a bit */
4105   if (AOP_TYPE (result) == AOP_CRY)
4106     {
4107       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4108     }
4109   else
4110     {
4111       emitcode ("jz", "%05d$", tlbl->key + 100);
4112       emitcode ("mov", "a,%s", one);
4113       emitcode ("", "%05d$:", tlbl->key + 100);
4114       outAcc (result);
4115     }
4116 }
4117
4118 /*-----------------------------------------------------------------*/
4119 /* genPlusBits - generates code for addition of two bits           */
4120 /*-----------------------------------------------------------------*/
4121 static void
4122 genPlusBits (iCode * ic)
4123 {
4124   D(emitcode (";     genPlusBits",""));
4125
4126   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4127     {
4128       symbol *lbl = newiTempLabel (NULL);
4129       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4130       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4131       emitcode ("cpl", "c");
4132       emitcode ("", "%05d$:", (lbl->key + 100));
4133       outBitC (IC_RESULT (ic));
4134     }
4135   else
4136     {
4137       emitcode ("clr", "a");
4138       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4139       emitcode ("rlc", "a");
4140       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4141       emitcode ("addc", "a,#0x00");
4142       outAcc (IC_RESULT (ic));
4143     }
4144 }
4145
4146 #if 0
4147 /* This is the original version of this code.
4148
4149  * This is being kept around for reference,
4150  * because I am not entirely sure I got it right...
4151  */
4152 static void
4153 adjustArithmeticResult (iCode * ic)
4154 {
4155   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4156       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4157       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4158     aopPut (IC_RESULT (ic),
4159             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4160             2,
4161             isOperandVolatile (IC_RESULT (ic), FALSE));
4162
4163   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4164       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4165       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4166     aopPut (IC_RESULT (ic),
4167             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4168             2,
4169             isOperandVolatile (IC_RESULT (ic), FALSE));
4170
4171   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4172       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4173       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4174       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4175       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4176     {
4177       char buffer[5];
4178       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4179       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
4180     }
4181 }
4182 #else
4183 /* This is the pure and virtuous version of this code.
4184  * I'm pretty certain it's right, but not enough to toss the old
4185  * code just yet...
4186  */
4187 static void
4188 adjustArithmeticResult (iCode * ic)
4189 {
4190   if (opIsGptr (IC_RESULT (ic)) &&
4191       opIsGptr (IC_LEFT (ic)) &&
4192       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4193     {
4194       aopPut (IC_RESULT (ic),
4195               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4196               GPTRSIZE - 1,
4197               isOperandVolatile (IC_RESULT (ic), FALSE));
4198     }
4199
4200   if (opIsGptr (IC_RESULT (ic)) &&
4201       opIsGptr (IC_RIGHT (ic)) &&
4202       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4203     {
4204       aopPut (IC_RESULT (ic),
4205               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4206               GPTRSIZE - 1,
4207               isOperandVolatile (IC_RESULT (ic), FALSE));
4208     }
4209
4210   if (opIsGptr (IC_RESULT (ic)) &&
4211       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4212       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4213       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4214       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4215     {
4216       char buffer[5];
4217       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4218       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4219     }
4220 }
4221 #endif
4222
4223 /*-----------------------------------------------------------------*/
4224 /* genPlus - generates code for addition                           */
4225 /*-----------------------------------------------------------------*/
4226 static void
4227 genPlus (iCode * ic)
4228 {
4229   int size, offset = 0;
4230   int skip_bytes = 0;
4231   char *add = "add";
4232   operand *leftOp, *rightOp;
4233   operand * op;
4234
4235   /* special cases :- */
4236
4237   D(emitcode (";     genPlus",""));
4238
4239   aopOp (IC_LEFT (ic), ic, FALSE);
4240   aopOp (IC_RIGHT (ic), ic, FALSE);
4241   aopOp (IC_RESULT (ic), ic, TRUE);
4242
4243   /* if literal, literal on the right or
4244      if left requires ACC or right is already
4245      in ACC */
4246   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4247       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4248       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4249     {
4250       operand *t = IC_RIGHT (ic);
4251       IC_RIGHT (ic) = IC_LEFT (ic);
4252       IC_LEFT (ic) = t;
4253     }
4254
4255   /* if both left & right are in bit
4256      space */
4257   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4258       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4259     {
4260       genPlusBits (ic);
4261       goto release;
4262     }
4263
4264   /* if left in bit space & right literal */
4265   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4266       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4267     {
4268       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4269       /* if result in bit space */
4270       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4271         {
4272           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4273             emitcode ("cpl", "c");
4274           outBitC (IC_RESULT (ic));
4275         }
4276       else
4277         {
4278           size = getDataSize (IC_RESULT (ic));
4279           while (size--)
4280             {
4281               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4282               emitcode ("addc", "a,#00");
4283               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4284             }
4285         }
4286       goto release;
4287     }
4288
4289   /* if I can do an increment instead
4290      of add then GOOD for ME */
4291   if (genPlusIncr (ic) == TRUE)
4292     goto release;
4293
4294   size = getDataSize (IC_RESULT (ic));
4295   leftOp = IC_LEFT(ic);
4296   rightOp = IC_RIGHT(ic);
4297   op=IC_LEFT(ic);
4298
4299   /* if this is an add for an array access
4300      at a 256 byte boundary */
4301   if ( 2 == size
4302        && AOP_TYPE (op) == AOP_IMMD
4303        && IS_SYMOP (op)
4304        && IS_SPEC (OP_SYM_ETYPE (op))
4305        && SPEC_ABSA (OP_SYM_ETYPE (op))
4306        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4307      )
4308     {
4309       D(emitcode (";     genPlus aligned array",""));
4310       aopPut (IC_RESULT (ic),
4311               aopGet (rightOp, 0, FALSE, FALSE),
4312               0,
4313               isOperandVolatile (IC_RESULT (ic), FALSE));
4314
4315       if( 1 == getDataSize (IC_RIGHT (ic)) )
4316         {
4317           aopPut (IC_RESULT (ic),
4318                   aopGet (leftOp, 1, FALSE, FALSE),
4319                   1,
4320                   isOperandVolatile (IC_RESULT (ic), FALSE));
4321         }
4322       else
4323         {
4324           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4325           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4326           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4327         }
4328       goto release;
4329     }
4330
4331   /* if the lower bytes of a literal are zero skip the addition */
4332   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4333     {
4334        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4335               (skip_bytes+1 < size))
4336          {
4337            skip_bytes++;
4338          }
4339        if (skip_bytes)
4340          D(emitcode (";     genPlus shortcut",""));
4341     }
4342
4343   while (size--)
4344     {
4345       if( offset >= skip_bytes )
4346         {
4347           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4348             {
4349               bool pushedB;
4350               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4351               pushedB = pushB ();
4352               emitcode("xch", "a,b");
4353               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4354               emitcode (add, "a,b");
4355               popB (pushedB);
4356             }
4357           else if (aopGetUsesAcc (leftOp, offset))
4358             {
4359               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4360               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4361             }
4362           else
4363             {
4364               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4365               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4366             }
4367           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4368           add = "addc";  /* further adds must propagate carry */
4369         }
4370       else
4371         {
4372           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4373               isOperandVolatile (IC_RESULT (ic), FALSE))
4374             {
4375               /* just move */
4376               aopPut (IC_RESULT (ic),
4377                       aopGet (leftOp, offset, FALSE, FALSE),
4378                       offset,
4379                       isOperandVolatile (IC_RESULT (ic), FALSE));
4380             }
4381         }
4382       offset++;
4383     }
4384
4385   adjustArithmeticResult (ic);
4386
4387 release:
4388   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4389   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4390   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4391 }
4392
4393 /*-----------------------------------------------------------------*/
4394 /* genMinusDec :- does subtraction with decrement if possible      */
4395 /*-----------------------------------------------------------------*/
4396 static bool
4397 genMinusDec (iCode * ic)
4398 {
4399   unsigned int icount;
4400   unsigned int size = getDataSize (IC_RESULT (ic));
4401
4402   /* will try to generate an increment */
4403   /* if the right side is not a literal
4404      we cannot */
4405   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4406     return FALSE;
4407
4408   /* if the literal value of the right hand side
4409      is greater than 4 then it is not worth it */
4410   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4411     return FALSE;
4412
4413   D(emitcode (";     genMinusDec",""));
4414
4415   /* if decrement >=16 bits in register or direct space */
4416   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
4417       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4418       (size > 1) &&
4419       (icount == 1))
4420     {
4421       symbol *tlbl;
4422       int emitTlbl;
4423       int labelRange;
4424
4425       /* If the next instruction is a goto and the goto target
4426        * is <= 10 instructions previous to this, we can generate
4427        * jumps straight to that target.
4428        */
4429       if (ic->next && ic->next->op == GOTO
4430           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4431           && labelRange <= 10)
4432         {
4433           emitcode (";", "tail decrement optimized");
4434           tlbl = IC_LABEL (ic->next);
4435           emitTlbl = 0;
4436         }
4437       else
4438         {
4439           tlbl = newiTempLabel (NULL);
4440           emitTlbl = 1;
4441         }
4442
4443       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4444       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4445           IS_AOP_PREG (IC_RESULT (ic)))
4446         emitcode ("cjne", "%s,#0xff,%05d$"
4447                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4448                   ,tlbl->key + 100);
4449       else
4450         {
4451           emitcode ("mov", "a,#0xff");
4452           emitcode ("cjne", "a,%s,%05d$"
4453                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4454                     ,tlbl->key + 100);
4455         }
4456       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4457       if (size > 2)
4458         {
4459           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4460               IS_AOP_PREG (IC_RESULT (ic)))
4461             emitcode ("cjne", "%s,#0xff,%05d$"
4462                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4463                       ,tlbl->key + 100);
4464           else
4465             {
4466               emitcode ("cjne", "a,%s,%05d$"
4467                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4468                         ,tlbl->key + 100);
4469             }
4470           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4471         }
4472       if (size > 3)
4473         {
4474           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4475               IS_AOP_PREG (IC_RESULT (ic)))
4476             emitcode ("cjne", "%s,#0xff,%05d$"
4477                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4478                       ,tlbl->key + 100);
4479           else
4480             {
4481               emitcode ("cjne", "a,%s,%05d$"
4482                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4483                         ,tlbl->key + 100);
4484             }
4485           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4486         }
4487       if (emitTlbl)
4488         {
4489           emitcode ("", "%05d$:", tlbl->key + 100);
4490         }
4491       return TRUE;
4492     }
4493
4494   /* if the sizes are greater than 1 then we cannot */
4495   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4496       AOP_SIZE (IC_LEFT (ic)) > 1)
4497     return FALSE;
4498
4499   /* we can if the aops of the left & result match or
4500      if they are in registers and the registers are the
4501      same */
4502   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4503     {
4504       char *l;
4505
4506       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4507         {
4508           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4509           l = "a";
4510         }
4511       else
4512         {
4513           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4514         }
4515
4516       while (icount--)
4517         emitcode ("dec", "%s", l);
4518
4519       if (AOP_NEEDSACC (IC_RESULT (ic)))
4520         aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4521
4522       return TRUE;
4523     }
4524
4525   return FALSE;
4526 }
4527
4528 /*-----------------------------------------------------------------*/
4529 /* addSign - complete with sign                                    */
4530 /*-----------------------------------------------------------------*/
4531 static void
4532 addSign (operand * result, int offset, int sign)
4533 {
4534   int size = (getDataSize (result) - offset);
4535   if (size > 0)
4536     {
4537       if (sign)
4538         {
4539           emitcode ("rlc", "a");
4540           emitcode ("subb", "a,acc");
4541           while (size--)
4542             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4543         }
4544       else
4545         while (size--)
4546           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4547     }
4548 }
4549
4550 /*-----------------------------------------------------------------*/
4551 /* genMinusBits - generates code for subtraction  of two bits      */
4552 /*-----------------------------------------------------------------*/
4553 static void
4554 genMinusBits (iCode * ic)
4555 {
4556   symbol *lbl = newiTempLabel (NULL);
4557
4558   D(emitcode (";     genMinusBits",""));
4559
4560   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4561     {
4562       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4563       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4564       emitcode ("cpl", "c");
4565       emitcode ("", "%05d$:", (lbl->key + 100));
4566       outBitC (IC_RESULT (ic));
4567     }
4568   else
4569     {
4570       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4571       emitcode ("subb", "a,acc");
4572       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4573       emitcode ("inc", "a");
4574       emitcode ("", "%05d$:", (lbl->key + 100));
4575       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4576       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4577     }
4578 }
4579
4580 /*-----------------------------------------------------------------*/
4581 /* genMinus - generates code for subtraction                       */
4582 /*-----------------------------------------------------------------*/
4583 static void
4584 genMinus (iCode * ic)
4585 {
4586   int size, offset = 0;
4587
4588   D(emitcode (";     genMinus",""));
4589
4590   aopOp (IC_LEFT (ic), ic, FALSE);
4591   aopOp (IC_RIGHT (ic), ic, FALSE);
4592   aopOp (IC_RESULT (ic), ic, TRUE);
4593
4594   /* special cases :- */
4595   /* if both left & right are in bit space */
4596   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4597       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4598     {
4599       genMinusBits (ic);
4600       goto release;
4601     }
4602
4603   /* if I can do an decrement instead
4604      of subtract then GOOD for ME */
4605   if (genMinusDec (ic) == TRUE)
4606     goto release;
4607
4608   size = getDataSize (IC_RESULT (ic));
4609
4610   /* if literal, add a,#-lit, else normal subb */
4611   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4612     {
4613       unsigned long lit = 0L;
4614       bool useCarry = FALSE;
4615
4616       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4617       lit = -(long) lit;
4618
4619       while (size--)
4620         {
4621           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4622             {
4623             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4624               if (!offset && !size && lit== (unsigned long) -1)
4625                 {
4626                   emitcode ("dec", "a");
4627                 }
4628               else if (!useCarry)
4629                 {
4630                   /* first add without previous c */
4631                   emitcode ("add", "a,#0x%02x",
4632                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4633                   useCarry = TRUE;
4634                 }
4635               else
4636                 {
4637                   emitcode ("addc", "a,#0x%02x",
4638                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4639                 }
4640               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4641             }
4642           else
4643             {
4644               /* no need to add zeroes */
4645               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4646                 {
4647                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4648                           offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4649                 }
4650               offset++;
4651             }
4652         }
4653     }
4654   else
4655     {
4656       operand *leftOp, *rightOp;
4657
4658       leftOp = IC_LEFT(ic);
4659       rightOp = IC_RIGHT(ic);
4660
4661       while (size--)
4662         {
4663           if (aopGetUsesAcc(rightOp, offset)) {
4664             if (aopGetUsesAcc(leftOp, offset)) {
4665               bool pushedB;
4666
4667               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4668               pushedB = pushB ();
4669               emitcode ("mov", "b,a");
4670               if (offset == 0)
4671                 CLRC;
4672               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4673               emitcode ("subb", "a,b");
4674               popB (pushedB);
4675             } else {
4676               /* reverse subtraction with 2's complement */
4677               if (offset == 0)
4678                 emitcode( "setb", "c");
4679                else
4680                 emitcode( "cpl", "c");
4681               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4682               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4683               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4684               emitcode("cpl", "a");
4685               if (size) /* skip if last byte */
4686                 emitcode( "cpl", "c");
4687             }
4688           } else {
4689             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4690             if (offset == 0)
4691               CLRC;
4692             emitcode ("subb", "a,%s",
4693                       aopGet(rightOp, offset, FALSE, TRUE));
4694           }
4695
4696           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4697         }
4698     }
4699
4700
4701   adjustArithmeticResult (ic);
4702
4703 release:
4704   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4705   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4706   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4707 }
4708
4709
4710 /*-----------------------------------------------------------------*/
4711 /* genMultbits :- multiplication of bits                           */
4712 /*-----------------------------------------------------------------*/
4713 static void
4714 genMultbits (operand * left,
4715              operand * right,
4716              operand * result)
4717 {
4718   D(emitcode (";     genMultbits",""));
4719
4720   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4721   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4722   outBitC (result);
4723 }
4724
4725 /*-----------------------------------------------------------------*/
4726 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4727 /*-----------------------------------------------------------------*/
4728 static void
4729 genMultOneByte (operand * left,
4730                 operand * right,
4731                 operand * result)
4732 {
4733   symbol *lbl;
4734   int size = AOP_SIZE (result);
4735   bool runtimeSign, compiletimeSign;
4736   bool lUnsigned, rUnsigned, pushedB;
4737
4738   D(emitcode (";     genMultOneByte",""));
4739
4740   if (size < 1 || size > 2)
4741     {
4742       /* this should never happen */
4743       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4744                AOP_SIZE(result), __FILE__, lineno);
4745       exit (1);
4746     }
4747
4748   /* (if two literals: the value is computed before) */
4749   /* if one literal, literal on the right */
4750   if (AOP_TYPE (left) == AOP_LIT)
4751     {
4752       operand *t = right;
4753       right = left;
4754       left = t;
4755       /* emitcode (";", "swapped left and right"); */
4756     }
4757   /* if no literal, unsigned on the right: shorter code */
4758   if (   AOP_TYPE (right) != AOP_LIT
4759       && SPEC_USIGN (getSpec (operandType (left))))
4760     {
4761       operand *t = right;
4762       right = left;
4763       left = t;
4764     }
4765
4766   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4767   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4768
4769   pushedB = pushB ();
4770
4771   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4772                    no need to take care about the signedness! */
4773       || (lUnsigned && rUnsigned))
4774     {
4775       /* just an unsigned 8 * 8 = 8 multiply
4776          or 8u * 8u = 16u */
4777       /* emitcode (";","unsigned"); */
4778       /* TODO: check for accumulator clash between left & right aops? */
4779
4780       if (AOP_TYPE (right) == AOP_LIT)
4781         {
4782           /* moving to accumulator first helps peepholes */
4783           MOVA (aopGet (left, 0, FALSE, FALSE));
4784           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4785         }
4786       else
4787         {
4788           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4789           MOVA (aopGet (left, 0, FALSE, FALSE));
4790         }
4791
4792       emitcode ("mul", "ab");
4793       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4794       if (size == 2)
4795         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4796
4797       popB (pushedB);
4798       return;
4799     }
4800
4801   /* we have to do a signed multiply */
4802   /* emitcode (";", "signed"); */
4803
4804   /* now sign adjust for both left & right */
4805
4806   /* let's see what's needed: */
4807   /* apply negative sign during runtime */
4808   runtimeSign = FALSE;
4809   /* negative sign from literals */
4810   compiletimeSign = FALSE;
4811
4812   if (!lUnsigned)
4813     {
4814       if (AOP_TYPE(left) == AOP_LIT)
4815         {
4816           /* signed literal */
4817           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4818           if (val < 0)
4819             compiletimeSign = TRUE;
4820         }
4821       else
4822         /* signed but not literal */
4823         runtimeSign = TRUE;
4824     }
4825
4826   if (!rUnsigned)
4827     {
4828       if (AOP_TYPE(right) == AOP_LIT)
4829         {
4830           /* signed literal */
4831           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4832           if (val < 0)
4833             compiletimeSign ^= TRUE;
4834         }
4835       else
4836         /* signed but not literal */
4837         runtimeSign = TRUE;
4838     }
4839
4840   /* initialize F0, which stores the runtime sign */
4841   if (runtimeSign)
4842     {
4843       if (compiletimeSign)
4844         emitcode ("setb", "F0"); /* set sign flag */
4845       else
4846         emitcode ("clr", "F0"); /* reset sign flag */
4847     }
4848
4849   /* save the signs of the operands */
4850   if (AOP_TYPE(right) == AOP_LIT)
4851     {
4852       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4853
4854       if (!rUnsigned && val < 0)
4855         emitcode ("mov", "b,#0x%02x", -val);
4856       else
4857         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4858     }
4859   else /* ! literal */
4860     {
4861       if (rUnsigned)  /* emitcode (";", "signed"); */
4862
4863         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4864       else
4865         {
4866           MOVA (aopGet (right, 0, FALSE, FALSE));
4867           lbl = newiTempLabel (NULL);
4868           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4869           emitcode ("cpl", "F0"); /* complement sign flag */
4870           emitcode ("cpl", "a");  /* 2's complement */
4871           emitcode ("inc", "a");
4872           emitcode ("", "%05d$:", (lbl->key + 100));
4873           emitcode ("mov", "b,a");
4874         }
4875     }
4876
4877   if (AOP_TYPE(left) == AOP_LIT)
4878     {
4879       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4880
4881       if (!lUnsigned && val < 0)
4882         emitcode ("mov", "a,#0x%02x", -val);
4883       else
4884         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4885     }
4886   else /* ! literal */
4887     {
4888       MOVA (aopGet (left, 0, FALSE, FALSE));
4889
4890       if (!lUnsigned)
4891         {
4892           lbl = newiTempLabel (NULL);
4893           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4894           emitcode ("cpl", "F0"); /* complement sign flag */
4895           emitcode ("cpl", "a"); /* 2's complement */
4896           emitcode ("inc", "a");
4897           emitcode ("", "%05d$:", (lbl->key + 100));
4898         }
4899     }
4900
4901   /* now the multiplication */
4902   emitcode ("mul", "ab");
4903   if (runtimeSign || compiletimeSign)
4904     {
4905       lbl = newiTempLabel (NULL);
4906       if (runtimeSign)
4907         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4908       emitcode ("cpl", "a"); /* lsb 2's complement */
4909       if (size != 2)
4910         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4911       else
4912         {
4913           emitcode ("add", "a,#1"); /* this sets carry flag */
4914           emitcode ("xch", "a,b");
4915           emitcode ("cpl", "a"); /* msb 2's complement */
4916           emitcode ("addc", "a,#0");
4917           emitcode ("xch", "a,b");
4918         }
4919       emitcode ("", "%05d$:", (lbl->key + 100));
4920     }
4921   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4922   if (size == 2)
4923     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4924
4925   popB (pushedB);
4926 }
4927
4928 /*-----------------------------------------------------------------*/
4929 /* genMult - generates code for multiplication                     */
4930 /*-----------------------------------------------------------------*/
4931 static void
4932 genMult (iCode * ic)
4933 {
4934   operand *left = IC_LEFT (ic);
4935   operand *right = IC_RIGHT (ic);
4936   operand *result = IC_RESULT (ic);
4937
4938   D(emitcode (";     genMult",""));
4939
4940   /* assign the asmops */
4941   aopOp (left, ic, FALSE);
4942   aopOp (right, ic, FALSE);
4943   aopOp (result, ic, TRUE);
4944
4945   /* special cases first */
4946   /* both are bits */
4947   if (AOP_TYPE (left) == AOP_CRY &&
4948       AOP_TYPE (right) == AOP_CRY)
4949     {
4950       genMultbits (left, right, result);
4951       goto release;
4952     }
4953
4954   /* if both are of size == 1 */
4955 #if 0 // one of them can be a sloc shared with the result
4956     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4957 #else
4958   if (getSize(operandType(left)) == 1 &&
4959       getSize(operandType(right)) == 1)
4960 #endif
4961     {
4962       genMultOneByte (left, right, result);
4963       goto release;
4964     }
4965
4966   /* should have been converted to function call */
4967     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4968              getSize(OP_SYMBOL(right)->type));
4969   assert (0);
4970
4971 release:
4972   freeAsmop (result, NULL, ic, TRUE);
4973   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4974   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4975 }
4976
4977 /*-----------------------------------------------------------------*/
4978 /* genDivbits :- division of bits                                  */
4979 /*-----------------------------------------------------------------*/
4980 static void
4981 genDivbits (operand * left,
4982             operand * right,
4983             operand * result)
4984 {
4985   char *l;
4986   bool pushedB;
4987
4988   D(emitcode (";     genDivbits",""));
4989
4990   pushedB = pushB ();
4991
4992   /* the result must be bit */
4993   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4994   l = aopGet (left, 0, FALSE, FALSE);
4995
4996   MOVA (l);
4997
4998   emitcode ("div", "ab");
4999   emitcode ("rrc", "a");
5000
5001   popB (pushedB);
5002
5003   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5004 }
5005
5006 /*-----------------------------------------------------------------*/
5007 /* genDivOneByte : 8 bit division                                  */
5008 /*-----------------------------------------------------------------*/
5009 static void
5010 genDivOneByte (operand * left,
5011                operand * right,
5012                operand * result)
5013 {
5014   bool lUnsigned, rUnsigned, pushedB;
5015   bool runtimeSign, compiletimeSign;
5016   bool accuse = FALSE;
5017   bool pushedA = FALSE;
5018   symbol *lbl;
5019   int size, offset;
5020
5021   D(emitcode (";     genDivOneByte",""));
5022
5023   /* Why is it necessary that genDivOneByte() can return an int result?
5024      Have a look at:
5025
5026         volatile unsigned char uc;
5027         volatile signed char sc1, sc2;
5028         volatile int i;
5029
5030         uc  = 255;
5031         sc1 = -1;
5032         i = uc / sc1;
5033
5034      Or:
5035
5036         sc1 = -128;
5037         sc2 = -1;
5038         i = sc1 / sc2;
5039
5040      In all cases a one byte result would overflow, the following cast to int
5041      would return the wrong result.
5042
5043      Two possible solution:
5044         a) cast operands to int, if ((unsigned) / (signed)) or
5045            ((signed) / (signed))
5046         b) return an 16 bit signed int; this is what we're doing here!
5047   */
5048
5049   size = AOP_SIZE (result) - 1;
5050   offset = 1;
5051   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5052   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5053
5054   pushedB = pushB ();
5055
5056   /* signed or unsigned */
5057   if (lUnsigned && rUnsigned)
5058     {
5059       /* unsigned is easy */
5060       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5061       MOVA (aopGet (left, 0, FALSE, FALSE));
5062       emitcode ("div", "ab");
5063       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5064       while (size--)
5065         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5066
5067       popB (pushedB);
5068       return;
5069     }
5070
5071   /* signed is a little bit more difficult */
5072
5073   /* now sign adjust for both left & right */
5074
5075   /* let's see what's needed: */
5076   /* apply negative sign during runtime */
5077   runtimeSign = FALSE;
5078   /* negative sign from literals */
5079   compiletimeSign = FALSE;
5080
5081   if (!lUnsigned)
5082     {
5083       if (AOP_TYPE(left) == AOP_LIT)
5084         {
5085           /* signed literal */
5086           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5087           if (val < 0)
5088             compiletimeSign = TRUE;
5089         }
5090       else
5091         /* signed but not literal */
5092         runtimeSign = TRUE;
5093     }
5094
5095   if (!rUnsigned)
5096     {
5097       if (AOP_TYPE(right) == AOP_LIT)
5098         {
5099           /* signed literal */
5100           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5101           if (val < 0)
5102             compiletimeSign ^= TRUE;
5103         }
5104       else
5105         /* signed but not literal */
5106         runtimeSign = TRUE;
5107     }
5108
5109   /* initialize F0, which stores the runtime sign */
5110   if (runtimeSign)
5111     {
5112       if (compiletimeSign)
5113         emitcode ("setb", "F0"); /* set sign flag */
5114       else
5115         emitcode ("clr", "F0"); /* reset sign flag */
5116     }
5117
5118   /* save the signs of the operands */
5119   if (AOP_TYPE(right) == AOP_LIT)
5120     {
5121       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5122
5123       if (!rUnsigned && val < 0)
5124         emitcode ("mov", "b,#0x%02x", -val);
5125       else
5126         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5127     }
5128   else /* ! literal */
5129     {
5130       if (rUnsigned)
5131         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5132       else
5133         {
5134           MOVA (aopGet (right, 0, FALSE, FALSE));
5135           lbl = newiTempLabel (NULL);
5136           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5137           emitcode ("cpl", "F0"); /* complement sign flag */
5138           emitcode ("cpl", "a");  /* 2's complement */
5139           emitcode ("inc", "a");
5140           emitcode ("", "%05d$:", (lbl->key + 100));
5141           emitcode ("mov", "b,a");
5142         }
5143     }
5144
5145   if (AOP_TYPE(left) == AOP_LIT)
5146     {
5147       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5148
5149       if (!lUnsigned && val < 0)
5150         emitcode ("mov", "a,#0x%02x", -val);
5151       else
5152         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5153     }
5154   else /* ! literal */
5155     {
5156       MOVA (aopGet (left, 0, FALSE, FALSE));
5157
5158       if (!lUnsigned)
5159         {
5160           lbl = newiTempLabel (NULL);
5161           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5162           emitcode ("cpl", "F0"); /* complement sign flag */
5163           emitcode ("cpl", "a");  /* 2's complement */
5164           emitcode ("inc", "a");
5165           emitcode ("", "%05d$:", (lbl->key + 100));
5166         }
5167     }
5168
5169   /* now the division */
5170   emitcode ("div", "ab");
5171
5172   if (runtimeSign || compiletimeSign)
5173     {
5174       lbl = newiTempLabel (NULL);
5175       if (runtimeSign)
5176         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5177       emitcode ("cpl", "a"); /* lsb 2's complement */
5178       emitcode ("inc", "a");
5179       emitcode ("", "%05d$:", (lbl->key + 100));
5180
5181       accuse = aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5182       if (size > 0)
5183         {
5184           /* msb is 0x00 or 0xff depending on the sign */
5185           if (runtimeSign)
5186             {
5187               if (accuse)
5188                 {
5189                   emitcode ("push", "acc");
5190                   pushedA = TRUE;
5191                 }
5192               emitcode ("mov", "c,F0");
5193               emitcode ("subb", "a,acc");
5194               while (size--)
5195                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5196             }
5197           else /* compiletimeSign */
5198             {
5199               if (aopPutUsesAcc (result, "#0xFF", offset))
5200                 {
5201                   emitcode ("push", "acc");
5202                   pushedA = TRUE;
5203                 }
5204               while (size--)
5205                 aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5206             }
5207         }
5208     }
5209   else
5210     {
5211       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5212       while (size--)
5213         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5214     }
5215
5216   if (pushedA)
5217     emitcode ("pop", "acc");
5218   popB (pushedB);
5219 }
5220
5221 /*-----------------------------------------------------------------*/
5222 /* genDiv - generates code for division                            */
5223 /*-----------------------------------------------------------------*/
5224 static void
5225 genDiv (iCode * ic)
5226 {
5227   operand *left = IC_LEFT (ic);
5228   operand *right = IC_RIGHT (ic);
5229   operand *result = IC_RESULT (ic);
5230
5231   D(emitcode (";     genDiv",""));
5232
5233   /* assign the amsops */
5234   aopOp (left, ic, FALSE);
5235   aopOp (right, ic, FALSE);
5236   aopOp (result, ic, TRUE);
5237
5238   /* special cases first */
5239   /* both are bits */
5240   if (AOP_TYPE (left) == AOP_CRY &&
5241       AOP_TYPE (right) == AOP_CRY)
5242     {
5243       genDivbits (left, right, result);
5244       goto release;
5245     }
5246
5247   /* if both are of size == 1 */
5248   if (AOP_SIZE (left) == 1 &&
5249       AOP_SIZE (right) == 1)
5250     {
5251       genDivOneByte (left, right, result);
5252       goto release;
5253     }
5254
5255   /* should have been converted to function call */
5256   assert (0);
5257 release:
5258   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5259   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5260   freeAsmop (result, NULL, ic, TRUE);
5261 }
5262
5263 /*-----------------------------------------------------------------*/
5264 /* genModbits :- modulus of bits                                   */
5265 /*-----------------------------------------------------------------*/
5266 static void
5267 genModbits (operand * left,
5268             operand * right,
5269             operand * result)
5270 {
5271   char *l;
5272   bool pushedB;
5273
5274   D(emitcode (";     genModbits",""));
5275
5276   pushedB = pushB ();
5277
5278   /* the result must be bit */
5279   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5280   l = aopGet (left, 0, FALSE, FALSE);
5281
5282   MOVA (l);
5283
5284   emitcode ("div", "ab");
5285   emitcode ("mov", "a,b");
5286   emitcode ("rrc", "a");
5287
5288   popB (pushedB);
5289
5290   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5291 }
5292
5293 /*-----------------------------------------------------------------*/
5294 /* genModOneByte : 8 bit modulus                                   */
5295 /*-----------------------------------------------------------------*/
5296 static void
5297 genModOneByte (operand * left,
5298                operand * right,
5299                operand * result)
5300 {
5301   bool lUnsigned, rUnsigned, pushedB;
5302   bool runtimeSign, compiletimeSign;
5303   symbol *lbl;
5304   int size, offset;
5305
5306   D(emitcode (";     genModOneByte",""));
5307
5308   size = AOP_SIZE (result) - 1;
5309   offset = 1;
5310   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5311   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5312
5313   /* if right is a literal, check it for 2^n */
5314   if (AOP_TYPE(right) == AOP_LIT)
5315     {
5316       unsigned char val = abs((int) operandLitValue(right));
5317       symbol *lbl2 = NULL;
5318
5319       switch (val)
5320         {
5321           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5322           case 2:
5323           case 4:
5324           case 8:
5325           case 16:
5326           case 32:
5327           case 64:
5328           case 128:
5329             if (lUnsigned)
5330               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5331                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5332               /* because iCode should have been changed to genAnd  */
5333               /* see file "SDCCopt.c", function "convertToFcall()" */
5334
5335             MOVA (aopGet (left, 0, FALSE, FALSE));
5336             emitcode ("mov", "c,acc.7");
5337             emitcode ("anl", "a,#0x%02x", val - 1);
5338             lbl = newiTempLabel (NULL);
5339             emitcode ("jz", "%05d$", (lbl->key + 100));
5340             emitcode ("jnc", "%05d$", (lbl->key + 100));
5341             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5342             if (size)
5343               {
5344                 int size2 = size;
5345                 int offs2 = offset;
5346
5347                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5348                 while (size2--)
5349                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
5350                 lbl2 = newiTempLabel (NULL);
5351                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5352               }
5353             emitcode ("", "%05d$:", (lbl->key + 100));
5354             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5355             while (size--)
5356               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5357             if (lbl2)
5358               {
5359                 emitcode ("", "%05d$:", (lbl2->key + 100));
5360               }
5361             return;
5362
5363           default:
5364             break;
5365         }
5366     }
5367
5368   pushedB = pushB ();
5369
5370   /* signed or unsigned */
5371   if (lUnsigned && rUnsigned)
5372     {
5373       /* unsigned is easy */
5374       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5375       MOVA (aopGet (left, 0, FALSE, FALSE));
5376       emitcode ("div", "ab");
5377       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5378       while (size--)
5379         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5380
5381       popB (pushedB);
5382       return;
5383     }
5384
5385   /* signed is a little bit more difficult */
5386
5387   /* now sign adjust for both left & right */
5388
5389   /* modulus: sign of the right operand has no influence on the result! */
5390   if (AOP_TYPE(right) == AOP_LIT)
5391     {
5392       signed char val = (char) operandLitValue(right);
5393
5394       if (!rUnsigned && val < 0)
5395         emitcode ("mov", "b,#0x%02x", -val);
5396       else
5397         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5398     }
5399   else /* not literal */
5400     {
5401       if (rUnsigned)
5402         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5403       else
5404         {
5405           MOVA (aopGet (right, 0, FALSE, FALSE));
5406           lbl = newiTempLabel (NULL);
5407           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5408           emitcode ("cpl", "a"); /* 2's complement */
5409           emitcode ("inc", "a");
5410           emitcode ("", "%05d$:", (lbl->key + 100));
5411           emitcode ("mov", "b,a");
5412         }
5413     }
5414
5415   /* let's see what's needed: */
5416   /* apply negative sign during runtime */
5417   runtimeSign = FALSE;
5418   /* negative sign from literals */
5419   compiletimeSign = FALSE;
5420
5421   /* sign adjust left side */
5422   if (AOP_TYPE(left) == AOP_LIT)
5423     {
5424       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5425
5426       if (!lUnsigned && val < 0)
5427         {
5428           compiletimeSign = TRUE; /* set sign flag */
5429           emitcode ("mov", "a,#0x%02x", -val);
5430         }
5431       else
5432         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5433     }
5434   else /* ! literal */
5435     {
5436       MOVA (aopGet (left, 0, FALSE, FALSE));
5437
5438       if (!lUnsigned)
5439         {
5440           runtimeSign = TRUE;
5441           emitcode ("clr", "F0"); /* clear sign flag */
5442
5443           lbl = newiTempLabel (NULL);
5444           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5445           emitcode ("setb", "F0"); /* set sign flag */
5446           emitcode ("cpl", "a");   /* 2's complement */
5447           emitcode ("inc", "a");
5448           emitcode ("", "%05d$:", (lbl->key + 100));
5449         }
5450     }
5451
5452   /* now the modulus */
5453   emitcode ("div", "ab");
5454
5455   if (runtimeSign || compiletimeSign)
5456     {
5457       emitcode ("mov", "a,b");
5458       lbl = newiTempLabel (NULL);
5459       if (runtimeSign)
5460         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5461       emitcode ("cpl", "a"); /* 2's complement */
5462       emitcode ("inc", "a");
5463       emitcode ("", "%05d$:", (lbl->key + 100));
5464
5465       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5466       if (size > 0)
5467         {
5468           /* msb is 0x00 or 0xff depending on the sign */
5469           if (runtimeSign)
5470             {
5471               emitcode ("mov", "c,F0");
5472               emitcode ("subb", "a,acc");
5473               while (size--)
5474                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5475             }
5476           else /* compiletimeSign */
5477             while (size--)
5478               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5479         }
5480     }
5481   else
5482     {
5483       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5484       while (size--)
5485         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5486     }
5487
5488   popB (pushedB);
5489 }
5490
5491 /*-----------------------------------------------------------------*/
5492 /* genMod - generates code for division                            */
5493 /*-----------------------------------------------------------------*/
5494 static void
5495 genMod (iCode * ic)
5496 {
5497   operand *left = IC_LEFT (ic);
5498   operand *right = IC_RIGHT (ic);
5499   operand *result = IC_RESULT (ic);
5500
5501   D(emitcode (";     genMod",""));
5502
5503   /* assign the asmops */
5504   aopOp (left, ic, FALSE);
5505   aopOp (right, ic, FALSE);
5506   aopOp (result, ic, TRUE);
5507
5508   /* special cases first */
5509   /* both are bits */
5510   if (AOP_TYPE (left) == AOP_CRY &&
5511       AOP_TYPE (right) == AOP_CRY)
5512     {
5513       genModbits (left, right, result);
5514       goto release;
5515     }
5516
5517   /* if both are of size == 1 */
5518   if (AOP_SIZE (left) == 1 &&
5519       AOP_SIZE (right) == 1)
5520     {
5521       genModOneByte (left, right, result);
5522       goto release;
5523     }
5524
5525   /* should have been converted to function call */
5526   assert (0);
5527
5528 release:
5529   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5530   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5531   freeAsmop (result, NULL, ic, TRUE);
5532 }
5533
5534 /*-----------------------------------------------------------------*/
5535 /* genIfxJump :- will create a jump depending on the ifx           */
5536 /*-----------------------------------------------------------------*/
5537 static void
5538 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5539 {
5540   symbol *jlbl;
5541   symbol *tlbl = newiTempLabel (NULL);
5542   char *inst;
5543
5544   D(emitcode (";     genIfxJump",""));
5545
5546   /* if true label then we jump if condition
5547      supplied is true */
5548   if (IC_TRUE (ic))
5549     {
5550       jlbl = IC_TRUE (ic);
5551       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5552                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5553     }
5554   else
5555     {
5556       /* false label is present */
5557       jlbl = IC_FALSE (ic);
5558       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5559                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5560     }
5561   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5562     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5563   else
5564     emitcode (inst, "%05d$", tlbl->key + 100);
5565   freeForBranchAsmop (result);
5566   freeForBranchAsmop (right);
5567   freeForBranchAsmop (left);
5568   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5569   emitcode ("", "%05d$:", tlbl->key + 100);
5570
5571   /* mark the icode as generated */
5572   ic->generated = 1;
5573 }
5574
5575 /*-----------------------------------------------------------------*/
5576 /* genCmp :- greater or less than comparison                       */
5577 /*-----------------------------------------------------------------*/
5578 static void
5579 genCmp (operand * left, operand * right,
5580         operand * result, iCode * ifx, int sign, iCode *ic)
5581 {
5582   int size, offset = 0;
5583   unsigned long lit = 0L;
5584   bool rightInB;
5585
5586   D(emitcode (";     genCmp",""));
5587
5588   /* if left & right are bit variables */
5589   if (AOP_TYPE (left) == AOP_CRY &&
5590       AOP_TYPE (right) == AOP_CRY)
5591     {
5592       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5593       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5594     }
5595   else
5596     {
5597       /* subtract right from left if at the
5598          end the carry flag is set then we know that
5599          left is greater than right */
5600       size = max (AOP_SIZE (left), AOP_SIZE (right));
5601
5602       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5603       if ((size == 1) && !sign &&
5604           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5605         {
5606           symbol *lbl = newiTempLabel (NULL);
5607           emitcode ("cjne", "%s,%s,%05d$",
5608                     aopGet (left, offset, FALSE, FALSE),
5609                     aopGet (right, offset, FALSE, FALSE),
5610                     lbl->key + 100);
5611           emitcode ("", "%05d$:", lbl->key + 100);
5612         }
5613       else
5614         {
5615           if (AOP_TYPE (right) == AOP_LIT)
5616             {
5617               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5618               /* optimize if(x < 0) or if(x >= 0) */
5619               if (lit == 0L)
5620                 {
5621                   if (!sign)
5622                     {
5623                       CLRC;
5624                     }
5625                   else
5626                     {
5627                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5628                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5629                         {
5630                           genIfxJump (ifx, "acc.7", left, right, result);
5631                           freeAsmop (right, NULL, ic, TRUE);
5632                           freeAsmop (left, NULL, ic, TRUE);
5633
5634                           return;
5635                         }
5636                       else
5637                         emitcode ("rlc", "a");
5638                     }
5639                   goto release;
5640                 }
5641             }
5642           CLRC;
5643           while (size--)
5644             {
5645               bool pushedB = FALSE;
5646               rightInB = aopGetUsesAcc(right, offset);
5647               if (rightInB)
5648                 {
5649                   pushedB = pushB ();
5650                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5651                 }
5652               MOVA (aopGet (left, offset, FALSE, FALSE));
5653               if (sign && size == 0)
5654                 {
5655                   emitcode ("xrl", "a,#0x80");
5656                   if (AOP_TYPE (right) == AOP_LIT)
5657                     {
5658                       unsigned long lit = (unsigned long)
5659                       floatFromVal (AOP (right)->aopu.aop_lit);
5660                       emitcode ("subb", "a,#0x%02x",
5661                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5662                     }
5663                   else
5664                     {
5665                       if (!rightInB)
5666                         {
5667                           pushedB = pushB ();
5668                           rightInB++;
5669                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5670                         }
5671                       emitcode ("xrl", "b,#0x80");
5672                       emitcode ("subb", "a,b");
5673                     }
5674                 }
5675               else
5676                 {
5677                   if (rightInB)
5678                     emitcode ("subb", "a,b");
5679                   else
5680                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5681                 }
5682               if (rightInB)
5683                 popB (pushedB);
5684               offset++;
5685             }
5686         }
5687     }
5688
5689 release:
5690   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5691   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5692   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5693     {
5694       outBitC (result);
5695     }
5696   else
5697     {
5698       /* if the result is used in the next
5699          ifx conditional branch then generate
5700          code a little differently */
5701       if (ifx)
5702         genIfxJump (ifx, "c", NULL, NULL, result);
5703       else
5704         outBitC (result);
5705       /* leave the result in acc */
5706     }
5707 }
5708
5709 /*-----------------------------------------------------------------*/
5710 /* genCmpGt :- greater than comparison                             */
5711 /*-----------------------------------------------------------------*/
5712 static void
5713 genCmpGt (iCode * ic, iCode * ifx)
5714 {
5715   operand *left, *right, *result;
5716   sym_link *letype, *retype;
5717   int sign;
5718
5719   D(emitcode (";     genCmpGt",""));
5720
5721   left = IC_LEFT (ic);
5722   right = IC_RIGHT (ic);
5723   result = IC_RESULT (ic);
5724
5725   letype = getSpec (operandType (left));
5726   retype = getSpec (operandType (right));
5727   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5728            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5729   /* assign the amsops */
5730   aopOp (left, ic, FALSE);
5731   aopOp (right, ic, FALSE);
5732   aopOp (result, ic, TRUE);
5733
5734   genCmp (right, left, result, ifx, sign, ic);
5735
5736   freeAsmop (result, NULL, ic, TRUE);
5737 }
5738
5739 /*-----------------------------------------------------------------*/
5740 /* genCmpLt - less than comparisons                                */
5741 /*-----------------------------------------------------------------*/
5742 static void
5743 genCmpLt (iCode * ic, iCode * ifx)
5744 {
5745   operand *left, *right, *result;
5746   sym_link *letype, *retype;
5747   int sign;
5748
5749   D(emitcode (";     genCmpLt",""));
5750
5751   left = IC_LEFT (ic);
5752   right = IC_RIGHT (ic);
5753   result = IC_RESULT (ic);
5754
5755   letype = getSpec (operandType (left));
5756   retype = getSpec (operandType (right));
5757   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5758            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5759   /* assign the amsops */
5760   aopOp (left, ic, FALSE);
5761   aopOp (right, ic, FALSE);
5762   aopOp (result, ic, TRUE);
5763
5764   genCmp (left, right, result, ifx, sign, ic);
5765
5766   freeAsmop (result, NULL, ic, TRUE);
5767 }
5768
5769 /*-----------------------------------------------------------------*/
5770 /* gencjneshort - compare and jump if not equal                    */
5771 /*-----------------------------------------------------------------*/
5772 static void
5773 gencjneshort (operand * left, operand * right, symbol * lbl)
5774 {
5775   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5776   int offset = 0;
5777   unsigned long lit = 0L;
5778
5779   /* if the left side is a literal or
5780      if the right is in a pointer register and left
5781      is not */
5782   if ((AOP_TYPE (left) == AOP_LIT) ||
5783       (AOP_TYPE (left) == AOP_IMMD) ||
5784       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5785     {
5786       operand *t = right;
5787       right = left;
5788       left = t;
5789     }
5790
5791   if (AOP_TYPE (right) == AOP_LIT)
5792     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5793
5794   /* if the right side is a literal then anything goes */
5795   if (AOP_TYPE (right) == AOP_LIT &&
5796       AOP_TYPE (left) != AOP_DIR  &&
5797       AOP_TYPE (left) != AOP_IMMD)
5798     {
5799       while (size--)
5800         {
5801           emitcode ("cjne", "%s,%s,%05d$",
5802                     aopGet (left, offset, FALSE, FALSE),
5803                     aopGet (right, offset, FALSE, FALSE),
5804                     lbl->key + 100);
5805           offset++;
5806         }
5807     }
5808
5809   /* if the right side is in a register or in direct space or
5810      if the left is a pointer register & right is not */
5811   else if (AOP_TYPE (right) == AOP_REG ||
5812            AOP_TYPE (right) == AOP_DIR ||
5813            AOP_TYPE (right) == AOP_LIT ||
5814            AOP_TYPE (right) == AOP_IMMD ||
5815            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5816            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5817     {
5818       while (size--)
5819         {
5820           MOVA (aopGet (left, offset, FALSE, FALSE));
5821           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5822               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5823             emitcode ("jnz", "%05d$", lbl->key + 100);
5824           else
5825             emitcode ("cjne", "a,%s,%05d$",
5826                       aopGet (right, offset, FALSE, TRUE),
5827                       lbl->key + 100);
5828           offset++;
5829         }
5830     }
5831   else
5832     {
5833       /* right is a pointer reg need both a & b */
5834       while (size--)
5835         {
5836           char *l;
5837           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5838           wassertl(!BINUSE, "B was in use");
5839           l = aopGet (left, offset, FALSE, FALSE);
5840           if (strcmp (l, "b"))
5841             emitcode ("mov", "b,%s", l);
5842           MOVA (aopGet (right, offset, FALSE, FALSE));
5843           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5844           offset++;
5845         }
5846     }
5847 }
5848
5849 /*-----------------------------------------------------------------*/
5850 /* gencjne - compare and jump if not equal                         */
5851 /*-----------------------------------------------------------------*/
5852 static void
5853 gencjne (operand * left, operand * right, symbol * lbl)
5854 {
5855   symbol *tlbl = newiTempLabel (NULL);
5856
5857   gencjneshort (left, right, lbl);
5858
5859   emitcode ("mov", "a,%s", one);
5860   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5861   emitcode ("", "%05d$:", lbl->key + 100);
5862   emitcode ("clr", "a");
5863   emitcode ("", "%05d$:", tlbl->key + 100);
5864 }
5865
5866 /*-----------------------------------------------------------------*/
5867 /* genCmpEq - generates code for equal to                          */
5868 /*-----------------------------------------------------------------*/
5869 static void
5870 genCmpEq (iCode * ic, iCode * ifx)
5871 {
5872   operand *left, *right, *result;
5873
5874   D(emitcode (";     genCmpEq",""));
5875
5876   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5877   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5878   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5879
5880   /* if literal, literal on the right or
5881      if the right is in a pointer register and left
5882      is not */
5883   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5884       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5885     {
5886       operand *t = IC_RIGHT (ic);
5887       IC_RIGHT (ic) = IC_LEFT (ic);
5888       IC_LEFT (ic) = t;
5889     }
5890
5891   if (ifx && !AOP_SIZE (result))
5892     {
5893       symbol *tlbl;
5894       /* if they are both bit variables */
5895       if (AOP_TYPE (left) == AOP_CRY &&
5896           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5897         {
5898           if (AOP_TYPE (right) == AOP_LIT)
5899             {
5900               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5901               if (lit == 0L)
5902                 {
5903                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5904                   emitcode ("cpl", "c");
5905                 }
5906               else if (lit == 1L)
5907                 {
5908                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5909                 }
5910               else
5911                 {
5912                   emitcode ("clr", "c");
5913                 }
5914               /* AOP_TYPE(right) == AOP_CRY */
5915             }
5916           else
5917             {
5918               symbol *lbl = newiTempLabel (NULL);
5919               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5920               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5921               emitcode ("cpl", "c");
5922               emitcode ("", "%05d$:", (lbl->key + 100));
5923             }
5924           /* if true label then we jump if condition
5925              supplied is true */
5926           tlbl = newiTempLabel (NULL);
5927           if (IC_TRUE (ifx))
5928             {
5929               emitcode ("jnc", "%05d$", tlbl->key + 100);
5930               freeForBranchAsmop (result);
5931               freeForBranchAsmop (right);
5932               freeForBranchAsmop (left);
5933               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5934             }
5935           else
5936             {
5937               emitcode ("jc", "%05d$", tlbl->key + 100);
5938               freeForBranchAsmop (result);
5939               freeForBranchAsmop (right);
5940               freeForBranchAsmop (left);
5941               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5942             }
5943           emitcode ("", "%05d$:", tlbl->key + 100);
5944         }
5945       else
5946         {
5947           tlbl = newiTempLabel (NULL);
5948           gencjneshort (left, right, tlbl);
5949           if (IC_TRUE (ifx))
5950             {
5951               freeForBranchAsmop (result);
5952               freeForBranchAsmop (right);
5953               freeForBranchAsmop (left);
5954               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5955               emitcode ("", "%05d$:", tlbl->key + 100);
5956             }
5957           else
5958             {
5959               symbol *lbl = newiTempLabel (NULL);
5960               emitcode ("sjmp", "%05d$", lbl->key + 100);
5961               emitcode ("", "%05d$:", tlbl->key + 100);
5962               freeForBranchAsmop (result);
5963               freeForBranchAsmop (right);
5964               freeForBranchAsmop (left);
5965               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5966               emitcode ("", "%05d$:", lbl->key + 100);
5967             }
5968         }
5969       /* mark the icode as generated */
5970       ifx->generated = 1;
5971       goto release;
5972     }
5973
5974   /* if they are both bit variables */
5975   if (AOP_TYPE (left) == AOP_CRY &&
5976       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5977     {
5978       if (AOP_TYPE (right) == AOP_LIT)
5979         {
5980           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5981           if (lit == 0L)
5982             {
5983               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5984               emitcode ("cpl", "c");
5985             }
5986           else if (lit == 1L)
5987             {
5988               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5989             }
5990           else
5991             {
5992               emitcode ("clr", "c");
5993             }
5994           /* AOP_TYPE(right) == AOP_CRY */
5995         }
5996       else
5997         {
5998           symbol *lbl = newiTempLabel (NULL);
5999           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6000           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6001           emitcode ("cpl", "c");
6002           emitcode ("", "%05d$:", (lbl->key + 100));
6003         }
6004       /* c = 1 if egal */
6005       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6006         {
6007           outBitC (result);
6008           goto release;
6009         }
6010       if (ifx)
6011         {
6012           genIfxJump (ifx, "c", left, right, result);
6013           goto release;
6014         }
6015       /* if the result is used in an arithmetic operation
6016          then put the result in place */
6017       outBitC (result);
6018     }
6019   else
6020     {
6021       gencjne (left, right, newiTempLabel (NULL));
6022       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6023         {
6024           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6025           goto release;
6026         }
6027       if (ifx)
6028         {
6029           genIfxJump (ifx, "a", left, right, result);
6030           goto release;
6031         }
6032       /* if the result is used in an arithmetic operation
6033          then put the result in place */
6034       if (AOP_TYPE (result) != AOP_CRY)
6035         outAcc (result);
6036       /* leave the result in acc */
6037     }
6038
6039 release:
6040   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6041   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6042   freeAsmop (result, NULL, ic, TRUE);
6043 }
6044
6045 /*-----------------------------------------------------------------*/
6046 /* ifxForOp - returns the icode containing the ifx for operand     */
6047 /*-----------------------------------------------------------------*/
6048 static iCode *
6049 ifxForOp (operand * op, iCode * ic)
6050 {
6051   /* if true symbol then needs to be assigned */
6052   if (IS_TRUE_SYMOP (op))
6053     return NULL;
6054
6055   /* if this has register type condition and
6056      the next instruction is ifx with the same operand
6057      and live to of the operand is upto the ifx only then */
6058   if (ic->next &&
6059       ic->next->op == IFX &&
6060       IC_COND (ic->next)->key == op->key &&
6061       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6062     return ic->next;
6063
6064   return NULL;
6065 }
6066
6067 /*-----------------------------------------------------------------*/
6068 /* hasInc - operand is incremented before any other use            */
6069 /*-----------------------------------------------------------------*/
6070 static iCode *
6071 hasInc (operand *op, iCode *ic,int osize)
6072 {
6073   sym_link *type = operandType(op);
6074   sym_link *retype = getSpec (type);
6075   iCode *lic = ic->next;
6076   int isize ;
6077
6078   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6079   if (!IS_SYMOP(op)) return NULL;
6080
6081   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6082   if (IS_AGGREGATE(type->next)) return NULL;
6083   if (osize != (isize = getSize(type->next))) return NULL;
6084
6085   while (lic) {
6086     /* if operand of the form op = op + <sizeof *op> */
6087     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6088         isOperandEqual(IC_RESULT(lic),op) &&
6089         isOperandLiteral(IC_RIGHT(lic)) &&
6090         operandLitValue(IC_RIGHT(lic)) == isize) {
6091       return lic;
6092     }
6093     /* if the operand used or deffed */
6094     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6095       return NULL;
6096     }
6097     /* if GOTO or IFX */
6098     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6099     lic = lic->next;
6100   }
6101   return NULL;
6102 }
6103
6104 /*-----------------------------------------------------------------*/
6105 /* genAndOp - for && operation                                     */
6106 /*-----------------------------------------------------------------*/
6107 static void
6108 genAndOp (iCode * ic)
6109 {
6110   operand *left, *right, *result;
6111   symbol *tlbl;
6112
6113   D(emitcode (";     genAndOp",""));
6114
6115   /* note here that && operations that are in an
6116      if statement are taken away by backPatchLabels
6117      only those used in arthmetic operations remain */
6118   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6119   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6120   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6121
6122   /* if both are bit variables */
6123   if (AOP_TYPE (left) == AOP_CRY &&
6124       AOP_TYPE (right) == AOP_CRY)
6125     {
6126       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6127       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6128       outBitC (result);
6129     }
6130   else
6131     {
6132       tlbl = newiTempLabel (NULL);
6133       toBoolean (left);
6134       emitcode ("jz", "%05d$", tlbl->key + 100);
6135       toBoolean (right);
6136       emitcode ("", "%05d$:", tlbl->key + 100);
6137       outBitAcc (result);
6138     }
6139
6140   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6141   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6142   freeAsmop (result, NULL, ic, TRUE);
6143 }
6144
6145
6146 /*-----------------------------------------------------------------*/
6147 /* genOrOp - for || operation                                      */
6148 /*-----------------------------------------------------------------*/
6149 static void
6150 genOrOp (iCode * ic)
6151 {
6152   operand *left, *right, *result;
6153   symbol *tlbl;
6154
6155   D(emitcode (";     genOrOp",""));
6156
6157   /* note here that || operations that are in an
6158      if statement are taken away by backPatchLabels
6159      only those used in arthmetic operations remain */
6160   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6161   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6162   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6163
6164   /* if both are bit variables */
6165   if (AOP_TYPE (left) == AOP_CRY &&
6166       AOP_TYPE (right) == AOP_CRY)
6167     {
6168       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6169       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6170       outBitC (result);
6171     }
6172   else
6173     {
6174       tlbl = newiTempLabel (NULL);
6175       toBoolean (left);
6176       emitcode ("jnz", "%05d$", tlbl->key + 100);
6177       toBoolean (right);
6178       emitcode ("", "%05d$:", tlbl->key + 100);
6179       outBitAcc (result);
6180     }
6181
6182   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6183   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6184   freeAsmop (result, NULL, ic, TRUE);
6185 }
6186
6187 /*-----------------------------------------------------------------*/
6188 /* isLiteralBit - test if lit == 2^n                               */
6189 /*-----------------------------------------------------------------*/
6190 static int
6191 isLiteralBit (unsigned long lit)
6192 {
6193   unsigned long pw[32] =
6194   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6195    0x100L, 0x200L, 0x400L, 0x800L,
6196    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6197    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6198    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6199    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6200    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6201   int idx;
6202
6203   for (idx = 0; idx < 32; idx++)
6204     if (lit == pw[idx])
6205       return idx + 1;
6206   return 0;
6207 }
6208
6209 /*-----------------------------------------------------------------*/
6210 /* continueIfTrue -                                                */
6211 /*-----------------------------------------------------------------*/
6212 static void
6213 continueIfTrue (iCode * ic)
6214 {
6215   if (IC_TRUE (ic))
6216     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6217   ic->generated = 1;
6218 }
6219
6220 /*-----------------------------------------------------------------*/
6221 /* jmpIfTrue -                                                     */
6222 /*-----------------------------------------------------------------*/
6223 static void
6224 jumpIfTrue (iCode * ic)
6225 {
6226   if (!IC_TRUE (ic))
6227     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6228   ic->generated = 1;
6229 }
6230
6231 /*-----------------------------------------------------------------*/
6232 /* jmpTrueOrFalse -                                                */
6233 /*-----------------------------------------------------------------*/
6234 static void
6235 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6236 {
6237   // ugly but optimized by peephole
6238   if (IC_TRUE (ic))
6239     {
6240       symbol *nlbl = newiTempLabel (NULL);
6241       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6242       emitcode ("", "%05d$:", tlbl->key + 100);
6243       freeForBranchAsmop (result);
6244       freeForBranchAsmop (right);
6245       freeForBranchAsmop (left);
6246       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6247       emitcode ("", "%05d$:", nlbl->key + 100);
6248     }
6249   else
6250     {
6251       freeForBranchAsmop (result);
6252       freeForBranchAsmop (right);
6253       freeForBranchAsmop (left);
6254       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6255       emitcode ("", "%05d$:", tlbl->key + 100);
6256     }
6257   ic->generated = 1;
6258 }
6259
6260 /*-----------------------------------------------------------------*/
6261 /* genAnd  - code for and                                          */
6262 /*-----------------------------------------------------------------*/
6263 static void
6264 genAnd (iCode * ic, iCode * ifx)
6265 {
6266   operand *left, *right, *result;
6267   int size, offset = 0;
6268   unsigned long lit = 0L;
6269   int bytelit = 0;
6270   char buffer[10];
6271
6272   D(emitcode (";     genAnd",""));
6273
6274   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6275   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6276   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6277
6278 #ifdef DEBUG_TYPE
6279   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6280             AOP_TYPE (result),
6281             AOP_TYPE (left), AOP_TYPE (right));
6282   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6283             AOP_SIZE (result),
6284             AOP_SIZE (left), AOP_SIZE (right));
6285 #endif
6286
6287   /* if left is a literal & right is not then exchange them */
6288   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6289       AOP_NEEDSACC (left))
6290     {
6291       operand *tmp = right;
6292       right = left;
6293       left = tmp;
6294     }
6295
6296   /* if result = right then exchange left and right */
6297   if (sameRegs (AOP (result), AOP (right)))
6298     {
6299       operand *tmp = right;
6300       right = left;
6301       left = tmp;
6302     }
6303
6304   /* if right is bit then exchange them */
6305   if (AOP_TYPE (right) == AOP_CRY &&
6306       AOP_TYPE (left) != AOP_CRY)
6307     {
6308       operand *tmp = right;
6309       right = left;
6310       left = tmp;
6311     }
6312   if (AOP_TYPE (right) == AOP_LIT)
6313     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6314
6315   size = AOP_SIZE (result);
6316
6317   // if(bit & yy)
6318   // result = bit & yy;
6319   if (AOP_TYPE (left) == AOP_CRY)
6320     {
6321       // c = bit & literal;
6322       if (AOP_TYPE (right) == AOP_LIT)
6323         {
6324           if (lit & 1)
6325             {
6326               if (size && sameRegs (AOP (result), AOP (left)))
6327                 // no change
6328                 goto release;
6329               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6330             }
6331           else
6332             {
6333               // bit(result) = 0;
6334               if (size && (AOP_TYPE (result) == AOP_CRY))
6335                 {
6336                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6337                   goto release;
6338                 }
6339               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6340                 {
6341                   jumpIfTrue (ifx);
6342                   goto release;
6343                 }
6344               emitcode ("clr", "c");
6345             }
6346         }
6347       else
6348         {
6349           if (AOP_TYPE (right) == AOP_CRY)
6350             {
6351               // c = bit & bit;
6352               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6353               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6354             }
6355           else
6356             {
6357               // c = bit & val;
6358               MOVA (aopGet (right, 0, FALSE, FALSE));
6359               // c = lsb
6360               emitcode ("rrc", "a");
6361               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6362             }
6363         }
6364       // bit = c
6365       // val = c
6366       if (size)
6367         outBitC (result);
6368       // if(bit & ...)
6369       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6370         genIfxJump (ifx, "c", left, right, result);
6371       goto release;
6372     }
6373
6374   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6375   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6376   if ((AOP_TYPE (right) == AOP_LIT) &&
6377       (AOP_TYPE (result) == AOP_CRY) &&
6378       (AOP_TYPE (left) != AOP_CRY))
6379     {
6380       int posbit = isLiteralBit (lit);
6381       /* left &  2^n */
6382       if (posbit)
6383         {
6384           posbit--;
6385           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6386           // bit = left & 2^n
6387           if (size)
6388             {
6389               switch (posbit & 0x07)
6390                 {
6391                   case 0: emitcode ("rrc", "a");
6392                           break;
6393                   case 7: emitcode ("rlc", "a");
6394                           break;
6395                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6396                           break;
6397                 }
6398             }
6399           // if(left &  2^n)
6400           else
6401             {
6402               if (ifx)
6403                 {
6404                   SNPRINTF (buffer, sizeof(buffer),
6405                             "acc.%d", posbit & 0x07);
6406                   genIfxJump (ifx, buffer, left, right, result);
6407                 }
6408               else
6409                 {// what is this case? just found it in ds390/gen.c
6410                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6411                 }
6412               goto release;
6413             }
6414         }
6415       else
6416         {
6417           symbol *tlbl = newiTempLabel (NULL);
6418           int sizel = AOP_SIZE (left);
6419           if (size)
6420             emitcode ("setb", "c");
6421           while (sizel--)
6422             {
6423               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6424                 {
6425                   MOVA (aopGet (left, offset, FALSE, FALSE));
6426                   // byte ==  2^n ?
6427                   if ((posbit = isLiteralBit (bytelit)) != 0)
6428                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6429                   else
6430                     {
6431                       if (bytelit != 0x0FFL)
6432                         emitcode ("anl", "a,%s",
6433                                   aopGet (right, offset, FALSE, TRUE));
6434                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6435                     }
6436                 }
6437               offset++;
6438             }
6439           // bit = left & literal
6440           if (size)
6441             {
6442               emitcode ("clr", "c");
6443               emitcode ("", "%05d$:", tlbl->key + 100);
6444             }
6445           // if(left & literal)
6446           else
6447             {
6448               if (ifx)
6449                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6450               else
6451                 emitcode ("", "%05d$:", tlbl->key + 100);
6452               goto release;
6453             }
6454         }
6455       outBitC (result);
6456       goto release;
6457     }
6458
6459   /* if left is same as result */
6460   if (sameRegs (AOP (result), AOP (left)))
6461     {
6462       for (; size--; offset++)
6463         {
6464           if (AOP_TYPE (right) == AOP_LIT)
6465             {
6466               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6467               if (bytelit == 0x0FF)
6468                 {
6469                   /* dummy read of volatile operand */
6470                   if (isOperandVolatile (left, FALSE))
6471                     MOVA (aopGet (left, offset, FALSE, FALSE));
6472                   else
6473                     continue;
6474                 }
6475               else if (bytelit == 0)
6476                 {
6477                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6478                 }
6479               else if (IS_AOP_PREG (result))
6480                 {
6481                   MOVA (aopGet (left, offset, FALSE, TRUE));
6482                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6483                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6484                 }
6485               else
6486                 emitcode ("anl", "%s,%s",
6487                           aopGet (left, offset, FALSE, TRUE),
6488                           aopGet (right, offset, FALSE, FALSE));
6489             }
6490           else
6491             {
6492               if (AOP_TYPE (left) == AOP_ACC)
6493                 {
6494                   if (offset)
6495                     emitcode("mov", "a,b");
6496                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6497                 }
6498               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6499                 {
6500                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6501                   MOVA (aopGet (right, offset, FALSE, FALSE));
6502                   emitcode ("anl", "a,b");
6503                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6504                 }
6505               else if (aopGetUsesAcc (left, offset))
6506                 {
6507                   MOVA (aopGet (left, offset, FALSE, FALSE));
6508                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6509                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6510                 }
6511               else
6512                 {
6513                   MOVA (aopGet (right, offset, FALSE, FALSE));
6514                   if (IS_AOP_PREG (result))
6515                     {
6516                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6517                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6518                     }
6519                   else
6520                     emitcode ("anl", "%s,a",
6521                               aopGet (left, offset, FALSE, TRUE));
6522                 }
6523             }
6524         }
6525     }
6526   else
6527     {
6528       // left & result in different registers
6529       if (AOP_TYPE (result) == AOP_CRY)
6530         {
6531           // result = bit
6532           // if(size), result in bit
6533           // if(!size && ifx), conditional oper: if(left & right)
6534           symbol *tlbl = newiTempLabel (NULL);
6535           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6536           if (size)
6537             emitcode ("setb", "c");
6538           while (sizer--)
6539             {
6540               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6541                   && AOP_TYPE(left)==AOP_ACC)
6542                 {
6543                   if (offset)
6544                     emitcode("mov", "a,b");
6545                   emitcode ("anl", "a,%s",
6546                             aopGet (right, offset, FALSE, FALSE));
6547                 } else {
6548                   if (AOP_TYPE(left)==AOP_ACC)
6549                     {
6550                       if (!offset)
6551                         {
6552                           bool pushedB = pushB ();
6553                           emitcode("mov", "b,a");
6554                           MOVA (aopGet (right, offset, FALSE, FALSE));
6555                           emitcode("anl", "a,b");
6556                           popB (pushedB);
6557                         }
6558                       else
6559                         {
6560                           MOVA (aopGet (right, offset, FALSE, FALSE));
6561                           emitcode("anl", "a,b");
6562                         }
6563                     } else {
6564                       MOVA (aopGet (right, offset, FALSE, FALSE));
6565                       emitcode ("anl", "a,%s",
6566                                 aopGet (left, offset, FALSE, FALSE));
6567                     }
6568                 }
6569               emitcode ("jnz", "%05d$", tlbl->key + 100);
6570               offset++;
6571             }
6572           if (size)
6573             {
6574               CLRC;
6575               emitcode ("", "%05d$:", tlbl->key + 100);
6576               outBitC (result);
6577             }
6578           else if (ifx)
6579             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6580           else
6581             emitcode ("", "%05d$:", tlbl->key + 100);
6582         }
6583       else
6584         {
6585           for (; (size--); offset++)
6586             {
6587               // normal case
6588               // result = left & right
6589               if (AOP_TYPE (right) == AOP_LIT)
6590                 {
6591                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6592                   if (bytelit == 0x0FF)
6593                     {
6594                       aopPut (result,
6595                               aopGet (left, offset, FALSE, FALSE),
6596                               offset,
6597                               isOperandVolatile (result, FALSE));
6598                       continue;
6599                     }
6600                   else if (bytelit == 0)
6601                     {
6602                       /* dummy read of volatile operand */
6603                       if (isOperandVolatile (left, FALSE))
6604                         MOVA (aopGet (left, offset, FALSE, FALSE));
6605                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6606                       continue;
6607                     }
6608                   else if (AOP_TYPE (left) == AOP_ACC)
6609                     {
6610                       if (!offset)
6611                         {
6612                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6613                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6614                           continue;
6615                         }
6616                       else
6617                         {
6618                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6619                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6620                           continue;
6621                         }
6622                     }
6623                 }
6624               // faster than result <- left, anl result,right
6625               // and better if result is SFR
6626               if (AOP_TYPE (left) == AOP_ACC)
6627                 {
6628                   if (offset)
6629                     emitcode("mov", "a,b");
6630                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6631                 }
6632               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6633                 {
6634                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6635                   MOVA (aopGet (right, offset, FALSE, FALSE));
6636                   emitcode ("anl", "a,b");
6637                 }
6638               else if (aopGetUsesAcc (left, offset))
6639                 {
6640                   MOVA (aopGet (left, offset, FALSE, FALSE));
6641                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6642                 }
6643               else
6644                 {
6645                   MOVA (aopGet (right, offset, FALSE, FALSE));
6646                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6647                 }
6648               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6649             }
6650         }
6651     }
6652
6653 release:
6654   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6655   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6656   freeAsmop (result, NULL, ic, TRUE);
6657 }
6658
6659 /*-----------------------------------------------------------------*/
6660 /* genOr  - code for or                                            */
6661 /*-----------------------------------------------------------------*/
6662 static void
6663 genOr (iCode * ic, iCode * ifx)
6664 {
6665   operand *left, *right, *result;
6666   int size, offset = 0;
6667   unsigned long lit = 0L;
6668   int bytelit = 0;
6669
6670   D(emitcode (";     genOr",""));
6671
6672   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6673   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6674   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6675
6676 #ifdef DEBUG_TYPE
6677   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6678             AOP_TYPE (result),
6679             AOP_TYPE (left), AOP_TYPE (right));
6680   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6681             AOP_SIZE (result),
6682             AOP_SIZE (left), AOP_SIZE (right));
6683 #endif
6684
6685   /* if left is a literal & right is not then exchange them */
6686   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6687       AOP_NEEDSACC (left))
6688     {
6689       operand *tmp = right;
6690       right = left;
6691       left = tmp;
6692     }
6693
6694   /* if result = right then exchange them */
6695   if (sameRegs (AOP (result), AOP (right)))
6696     {
6697       operand *tmp = right;
6698       right = left;
6699       left = tmp;
6700     }
6701
6702   /* if right is bit then exchange them */
6703   if (AOP_TYPE (right) == AOP_CRY &&
6704       AOP_TYPE (left) != AOP_CRY)
6705     {
6706       operand *tmp = right;
6707       right = left;
6708       left = tmp;
6709     }
6710   if (AOP_TYPE (right) == AOP_LIT)
6711     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6712
6713   size = AOP_SIZE (result);
6714
6715   // if(bit | yy)
6716   // xx = bit | yy;
6717   if (AOP_TYPE (left) == AOP_CRY)
6718     {
6719       if (AOP_TYPE (right) == AOP_LIT)
6720         {
6721           // c = bit | literal;
6722           if (lit)
6723             {
6724               // lit != 0 => result = 1
6725               if (AOP_TYPE (result) == AOP_CRY)
6726                 {
6727                   if (size)
6728                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6729                   else if (ifx)
6730                     continueIfTrue (ifx);
6731                   goto release;
6732                 }
6733               emitcode ("setb", "c");
6734             }
6735           else
6736             {
6737               // lit == 0 => result = left
6738               if (size && sameRegs (AOP (result), AOP (left)))
6739                 goto release;
6740               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6741             }
6742         }
6743       else
6744         {
6745           if (AOP_TYPE (right) == AOP_CRY)
6746             {
6747               // c = bit | bit;
6748               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6749               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6750             }
6751           else
6752             {
6753               // c = bit | val;
6754               symbol *tlbl = newiTempLabel (NULL);
6755               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6756                 emitcode ("setb", "c");
6757               emitcode ("jb", "%s,%05d$",
6758                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6759               toBoolean (right);
6760               emitcode ("jnz", "%05d$", tlbl->key + 100);
6761               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6762                 {
6763                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6764                   goto release;
6765                 }
6766               else
6767                 {
6768                   CLRC;
6769                   emitcode ("", "%05d$:", tlbl->key + 100);
6770                 }
6771             }
6772         }
6773       // bit = c
6774       // val = c
6775       if (size)
6776         outBitC (result);
6777       // if(bit | ...)
6778       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6779         genIfxJump (ifx, "c", left, right, result);
6780       goto release;
6781     }
6782
6783   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6784   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6785   if ((AOP_TYPE (right) == AOP_LIT) &&
6786       (AOP_TYPE (result) == AOP_CRY) &&
6787       (AOP_TYPE (left) != AOP_CRY))
6788     {
6789       if (lit)
6790         {
6791           // result = 1
6792           if (size)
6793             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6794           else
6795             continueIfTrue (ifx);
6796           goto release;
6797         }
6798       else
6799         {
6800           // lit = 0, result = boolean(left)
6801           if (size)
6802             emitcode ("setb", "c");
6803           toBoolean (right);
6804           if (size)
6805             {
6806               symbol *tlbl = newiTempLabel (NULL);
6807               emitcode ("jnz", "%05d$", tlbl->key + 100);
6808               CLRC;
6809               emitcode ("", "%05d$:", tlbl->key + 100);
6810             }
6811           else
6812             {
6813               genIfxJump (ifx, "a", left, right, result);
6814               goto release;
6815             }
6816         }
6817       outBitC (result);
6818       goto release;
6819     }
6820
6821   /* if left is same as result */
6822   if (sameRegs (AOP (result), AOP (left)))
6823     {
6824       for (; size--; offset++)
6825         {
6826           if (AOP_TYPE (right) == AOP_LIT)
6827             {
6828               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6829               if (bytelit == 0)
6830                 {
6831                   /* dummy read of volatile operand */
6832                   if (isOperandVolatile (left, FALSE))
6833                     MOVA (aopGet (left, offset, FALSE, FALSE));
6834                   else
6835                     continue;
6836                 }
6837               else if (bytelit == 0x0FF)
6838                 {
6839                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6840                 }
6841               else if (IS_AOP_PREG (left))
6842                 {
6843                   MOVA (aopGet (left, offset, FALSE, TRUE));
6844                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6845                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6846                 }
6847               else
6848                 {
6849                   emitcode ("orl", "%s,%s",
6850                             aopGet (left, offset, FALSE, TRUE),
6851                             aopGet (right, offset, FALSE, FALSE));
6852                 }
6853             }
6854           else
6855             {
6856               if (AOP_TYPE (left) == AOP_ACC)
6857                 {
6858                   if (offset)
6859                     emitcode("mov", "a,b");
6860                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6861                 }
6862               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6863                 {
6864                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6865                   MOVA (aopGet (right, offset, FALSE, FALSE));
6866                   emitcode ("orl", "a,b");
6867                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6868                 }
6869               else if (aopGetUsesAcc (left, offset))
6870                 {
6871                   MOVA (aopGet (left, offset, FALSE, FALSE));
6872                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6873                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6874                 }
6875               else
6876                 {
6877                   MOVA (aopGet (right, offset, FALSE, FALSE));
6878                   if (IS_AOP_PREG (left))
6879                     {
6880                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6881                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6882                     }
6883                   else
6884                     {
6885                       emitcode ("orl", "%s,a",
6886                                 aopGet (left, offset, FALSE, TRUE));
6887                     }
6888                 }
6889             }
6890         }
6891     }
6892   else
6893     {
6894       // left & result in different registers
6895       if (AOP_TYPE (result) == AOP_CRY)
6896         {
6897           // result = bit
6898           // if(size), result in bit
6899           // if(!size && ifx), conditional oper: if(left | right)
6900           symbol *tlbl = newiTempLabel (NULL);
6901           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6902           if (size)
6903             emitcode ("setb", "c");
6904           while (sizer--)
6905             {
6906               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6907                 if (offset)
6908                   emitcode("mov", "a,b");
6909                 emitcode ("orl", "a,%s",
6910                           aopGet (right, offset, FALSE, FALSE));
6911               } else {
6912                 MOVA (aopGet (right, offset, FALSE, FALSE));
6913                 emitcode ("orl", "a,%s",
6914                           aopGet (left, offset, FALSE, FALSE));
6915               }
6916               emitcode ("jnz", "%05d$", tlbl->key + 100);
6917               offset++;
6918             }
6919           if (size)
6920             {
6921               CLRC;
6922               emitcode ("", "%05d$:", tlbl->key + 100);
6923               outBitC (result);
6924             }
6925           else if (ifx)
6926             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6927           else
6928             emitcode ("", "%05d$:", tlbl->key + 100);
6929         }
6930       else
6931         {
6932           for (; (size--); offset++)
6933             {
6934               // normal case
6935               // result = left | right
6936               if (AOP_TYPE (right) == AOP_LIT)
6937                 {
6938                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6939                   if (bytelit == 0)
6940                     {
6941                       aopPut (result,
6942                               aopGet (left, offset, FALSE, FALSE),
6943                               offset,
6944                               isOperandVolatile (result, FALSE));
6945                       continue;
6946                     }
6947                   else if (bytelit == 0x0FF)
6948                     {
6949                       /* dummy read of volatile operand */
6950                       if (isOperandVolatile (left, FALSE))
6951                         MOVA (aopGet (left, offset, FALSE, FALSE));
6952                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6953                       continue;
6954                     }
6955                 }
6956               // faster than result <- left, anl result,right
6957               // and better if result is SFR
6958               if (AOP_TYPE (left) == AOP_ACC)
6959                 {
6960                   if (offset)
6961                     emitcode("mov", "a,b");
6962                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6963                 }
6964               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6965                 {
6966                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6967                   MOVA (aopGet (right, offset, FALSE, FALSE));
6968                   emitcode ("orl", "a,b");
6969                 }
6970               else if (aopGetUsesAcc (left, offset))
6971                 {
6972                   MOVA (aopGet (left, offset, FALSE, FALSE));
6973                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6974                 }
6975               else
6976                 {
6977                   MOVA (aopGet (right, offset, FALSE, FALSE));
6978                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6979                 }
6980               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6981             }
6982         }
6983     }
6984
6985 release:
6986   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6987   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6988   freeAsmop (result, NULL, ic, TRUE);
6989 }
6990
6991 /*-----------------------------------------------------------------*/
6992 /* genXor - code for xclusive or                                   */
6993 /*-----------------------------------------------------------------*/
6994 static void
6995 genXor (iCode * ic, iCode * ifx)
6996 {
6997   operand *left, *right, *result;
6998   int size, offset = 0;
6999   unsigned long lit = 0L;
7000   int bytelit = 0;
7001
7002   D(emitcode (";     genXor",""));
7003
7004   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7005   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7006   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7007
7008 #ifdef DEBUG_TYPE
7009   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7010             AOP_TYPE (result),
7011             AOP_TYPE (left), AOP_TYPE (right));
7012   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7013             AOP_SIZE (result),
7014             AOP_SIZE (left), AOP_SIZE (right));
7015 #endif
7016
7017   /* if left is a literal & right is not ||
7018      if left needs acc & right does not */
7019   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7020       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7021     {
7022       operand *tmp = right;
7023       right = left;
7024       left = tmp;
7025     }
7026
7027   /* if result = right then exchange them */
7028   if (sameRegs (AOP (result), AOP (right)))
7029     {
7030       operand *tmp = right;
7031       right = left;
7032       left = tmp;
7033     }
7034
7035   /* if right is bit then exchange them */
7036   if (AOP_TYPE (right) == AOP_CRY &&
7037       AOP_TYPE (left) != AOP_CRY)
7038     {
7039       operand *tmp = right;
7040       right = left;
7041       left = tmp;
7042     }
7043   if (AOP_TYPE (right) == AOP_LIT)
7044     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7045
7046   size = AOP_SIZE (result);
7047
7048   // if(bit ^ yy)
7049   // xx = bit ^ yy;
7050   if (AOP_TYPE (left) == AOP_CRY)
7051     {
7052       if (AOP_TYPE (right) == AOP_LIT)
7053         {
7054           // c = bit & literal;
7055           if (lit >> 1)
7056             {
7057               // lit>>1  != 0 => result = 1
7058               if (AOP_TYPE (result) == AOP_CRY)
7059                 {
7060                   if (size)
7061                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7062                   else if (ifx)
7063                     continueIfTrue (ifx);
7064                   goto release;
7065                 }
7066               emitcode ("setb", "c");
7067             }
7068           else
7069             {
7070               // lit == (0 or 1)
7071               if (lit == 0)
7072                 {
7073                   // lit == 0, result = left
7074                   if (size && sameRegs (AOP (result), AOP (left)))
7075                     goto release;
7076                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7077                 }
7078               else
7079                 {
7080                   // lit == 1, result = not(left)
7081                   if (size && sameRegs (AOP (result), AOP (left)))
7082                     {
7083                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7084                       goto release;
7085                     }
7086                   else
7087                     {
7088                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7089                       emitcode ("cpl", "c");
7090                     }
7091                 }
7092             }
7093
7094         }
7095       else
7096         {
7097           // right != literal
7098           symbol *tlbl = newiTempLabel (NULL);
7099           if (AOP_TYPE (right) == AOP_CRY)
7100             {
7101               // c = bit ^ bit;
7102               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7103             }
7104           else
7105             {
7106               int sizer = AOP_SIZE (right);
7107               // c = bit ^ val
7108               // if val>>1 != 0, result = 1
7109               emitcode ("setb", "c");
7110               while (sizer)
7111                 {
7112                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7113                   if (sizer == 1)
7114                     // test the msb of the lsb
7115                     emitcode ("anl", "a,#0xfe");
7116                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7117                   sizer--;
7118                 }
7119               // val = (0,1)
7120               emitcode ("rrc", "a");
7121             }
7122           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7123           emitcode ("cpl", "c");
7124           emitcode ("", "%05d$:", (tlbl->key + 100));
7125         }
7126       // bit = c
7127       // val = c
7128       if (size)
7129         outBitC (result);
7130       // if(bit | ...)
7131       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7132         genIfxJump (ifx, "c", left, right, result);
7133       goto release;
7134     }
7135
7136   /* if left is same as result */
7137   if (sameRegs (AOP (result), AOP (left)))
7138     {
7139       for (; size--; offset++)
7140         {
7141           if (AOP_TYPE (right) == AOP_LIT)
7142             {
7143               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7144               if (bytelit == 0)
7145                 {
7146                   /* dummy read of volatile operand */
7147                   if (isOperandVolatile (left, FALSE))
7148                     MOVA (aopGet (left, offset, FALSE, FALSE));
7149                   else
7150                     continue;
7151                 }
7152               else if (IS_AOP_PREG (left))
7153                 {
7154                   MOVA (aopGet (left, offset, FALSE, TRUE));
7155                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7156                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7157                 }
7158               else
7159                 {
7160                   emitcode ("xrl", "%s,%s",
7161                             aopGet (left, offset, FALSE, TRUE),
7162                             aopGet (right, offset, FALSE, FALSE));
7163                 }
7164             }
7165           else
7166             {
7167               if (AOP_TYPE (left) == AOP_ACC)
7168                 {
7169                   if (offset)
7170                     emitcode("mov", "a,b");
7171                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7172                 }
7173               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7174                 {
7175                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7176                   MOVA (aopGet (right, offset, FALSE, FALSE));
7177                   emitcode ("xrl", "a,b");
7178                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7179                 }
7180               else if (aopGetUsesAcc (left, offset))
7181                 {
7182                   MOVA (aopGet (left, offset, FALSE, FALSE));
7183                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7184                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7185                 }
7186               else
7187                 {
7188                   MOVA (aopGet (right, offset, FALSE, FALSE));
7189                   if (IS_AOP_PREG (left))
7190                     {
7191                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7192                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7193                     }
7194                   else
7195                     emitcode ("xrl", "%s,a",
7196                               aopGet (left, offset, FALSE, TRUE));
7197                 }
7198             }
7199         }
7200     }
7201   else
7202     {
7203       // left & result in different registers
7204       if (AOP_TYPE (result) == AOP_CRY)
7205         {
7206           // result = bit
7207           // if(size), result in bit
7208           // if(!size && ifx), conditional oper: if(left ^ right)
7209           symbol *tlbl = newiTempLabel (NULL);
7210           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7211           if (size)
7212             emitcode ("setb", "c");
7213           while (sizer--)
7214             {
7215               if ((AOP_TYPE (right) == AOP_LIT) &&
7216                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7217                 {
7218                   MOVA (aopGet (left, offset, FALSE, FALSE));
7219                 }
7220               else
7221                 {
7222                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7223                     if (offset)
7224                       emitcode("mov", "a,b");
7225                     emitcode ("xrl", "a,%s",
7226                               aopGet (right, offset, FALSE, FALSE));
7227                   } else {
7228                     MOVA (aopGet (right, offset, FALSE, FALSE));
7229                     emitcode ("xrl", "a,%s",
7230                               aopGet (left, offset, FALSE, FALSE));
7231                   }
7232                 }
7233               emitcode ("jnz", "%05d$", tlbl->key + 100);
7234               offset++;
7235             }
7236           if (size)
7237             {
7238               CLRC;
7239               emitcode ("", "%05d$:", tlbl->key + 100);
7240               outBitC (result);
7241             }
7242           else if (ifx)
7243             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7244         }
7245       else
7246         {
7247           for (; (size--); offset++)
7248             {
7249               // normal case
7250               // result = left & right
7251               if (AOP_TYPE (right) == AOP_LIT)
7252                 {
7253                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7254                   if (bytelit == 0)
7255                     {
7256                       aopPut (result,
7257                               aopGet (left, offset, FALSE, FALSE),
7258                               offset,
7259                               isOperandVolatile (result, FALSE));
7260                       continue;
7261                     }
7262                 }
7263               // faster than result <- left, anl result,right
7264               // and better if result is SFR
7265               if (AOP_TYPE (left) == AOP_ACC)
7266                 {
7267                   if (offset)
7268                     emitcode("mov", "a,b");
7269                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7270                 }
7271               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7272                 {
7273                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7274                   MOVA (aopGet (right, offset, FALSE, FALSE));
7275                   emitcode ("xrl", "a,b");
7276                 }
7277               else if (aopGetUsesAcc (left, offset))
7278                 {
7279                   MOVA (aopGet (left, offset, FALSE, FALSE));
7280                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7281                 }
7282               else
7283                 {
7284                   MOVA (aopGet (right, offset, FALSE, FALSE));
7285                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7286                 }
7287               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7288             }
7289         }
7290     }
7291
7292 release:
7293   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7294   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7295   freeAsmop (result, NULL, ic, TRUE);
7296 }
7297
7298 /*-----------------------------------------------------------------*/
7299 /* genInline - write the inline code out                           */
7300 /*-----------------------------------------------------------------*/
7301 static void
7302 genInline (iCode * ic)
7303 {
7304   char *buffer, *bp, *bp1;
7305
7306   D(emitcode (";     genInline",""));
7307
7308   _G.inLine += (!options.asmpeep);
7309
7310   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
7311   strcpy (buffer, IC_INLINE (ic));
7312
7313   /* emit each line as a code */
7314   while (*bp)
7315     {
7316       if (*bp == '\n')
7317         {
7318           *bp++ = '\0';
7319           emitcode (bp1, "");
7320           bp1 = bp;
7321         }
7322       else
7323         {
7324           /* Add \n for labels, not dirs such as c:\mydir */
7325           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7326             {
7327               bp++;
7328               *bp = '\0';
7329               bp++;
7330               emitcode (bp1, "");
7331               bp1 = bp;
7332             }
7333           else
7334             bp++;
7335         }
7336     }
7337   if (bp1 != bp)
7338     emitcode (bp1, "");
7339   /*     emitcode("",buffer); */
7340   _G.inLine -= (!options.asmpeep);
7341 }
7342
7343 /*-----------------------------------------------------------------*/
7344 /* genRRC - rotate right with carry                                */
7345 /*-----------------------------------------------------------------*/
7346 static void
7347 genRRC (iCode * ic)
7348 {
7349   operand *left, *result;
7350   int size, offset = 0;
7351   char *l;
7352
7353   D(emitcode (";     genRRC",""));
7354
7355   /* rotate right with carry */
7356   left = IC_LEFT (ic);
7357   result = IC_RESULT (ic);
7358   aopOp (left, ic, FALSE);
7359   aopOp (result, ic, FALSE);
7360
7361   /* move it to the result */
7362   size = AOP_SIZE (result);
7363   offset = size - 1;
7364   if (size == 1) { /* special case for 1 byte */
7365       l = aopGet (left, offset, FALSE, FALSE);
7366       MOVA (l);
7367       emitcode ("rr", "a");
7368       goto release;
7369   }
7370   /* no need to clear carry, bit7 will be written later */
7371   while (size--)
7372     {
7373       l = aopGet (left, offset, FALSE, FALSE);
7374       MOVA (l);
7375       emitcode ("rrc", "a");
7376       if (AOP_SIZE (result) > 1)
7377         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
7378     }
7379   /* now we need to put the carry into the
7380      highest order byte of the result */
7381   if (AOP_SIZE (result) > 1)
7382     {
7383       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7384       MOVA (l);
7385     }
7386   emitcode ("mov", "acc.7,c");
7387  release:
7388   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
7389   freeAsmop (left, NULL, ic, TRUE);
7390   freeAsmop (result, NULL, ic, TRUE);
7391 }
7392
7393 /*-----------------------------------------------------------------*/
7394 /* genRLC - generate code for rotate left with carry               */
7395 /*-----------------------------------------------------------------*/
7396 static void
7397 genRLC (iCode * ic)
7398 {
7399   operand *left, *result;
7400   int size, offset = 0;
7401   char *l;
7402
7403   D(emitcode (";     genRLC",""));
7404
7405   /* rotate right with carry */
7406   left = IC_LEFT (ic);
7407   result = IC_RESULT (ic);
7408   aopOp (left, ic, FALSE);
7409   aopOp (result, ic, FALSE);
7410
7411   /* move it to the result */
7412   size = AOP_SIZE (result);
7413   offset = 0;
7414   if (size--)
7415     {
7416       l = aopGet (left, offset, FALSE, FALSE);
7417       MOVA (l);
7418       if (size == 0) { /* special case for 1 byte */
7419               emitcode("rl","a");
7420               goto release;
7421       }
7422       emitcode("rlc","a"); /* bit0 will be written later */
7423       if (AOP_SIZE (result) > 1)
7424         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7425       while (size--)
7426         {
7427           l = aopGet (left, offset, FALSE, FALSE);
7428           MOVA (l);
7429           emitcode ("rlc", "a");
7430           if (AOP_SIZE (result) > 1)
7431             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7432         }
7433     }
7434   /* now we need to put the carry into the
7435      highest order byte of the result */
7436   if (AOP_SIZE (result) > 1)
7437     {
7438       l = aopGet (result, 0, FALSE, FALSE);
7439       MOVA (l);
7440     }
7441   emitcode ("mov", "acc.0,c");
7442  release:
7443   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7444   freeAsmop (left, NULL, ic, TRUE);
7445   freeAsmop (result, NULL, ic, TRUE);
7446 }
7447
7448 /*-----------------------------------------------------------------*/
7449 /* genGetHbit - generates code get highest order bit               */
7450 /*-----------------------------------------------------------------*/
7451 static void
7452 genGetHbit (iCode * ic)
7453 {
7454   operand *left, *result;
7455
7456   D(emitcode (";     genGetHbit",""));
7457
7458   left = IC_LEFT (ic);
7459   result = IC_RESULT (ic);
7460   aopOp (left, ic, FALSE);
7461   aopOp (result, ic, FALSE);
7462
7463   /* get the highest order byte into a */
7464   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7465   if (AOP_TYPE (result) == AOP_CRY)
7466     {
7467       emitcode ("rlc", "a");
7468       outBitC (result);
7469     }
7470   else
7471     {
7472       emitcode ("rl", "a");
7473       emitcode ("anl", "a,#0x01");
7474       outAcc (result);
7475     }
7476
7477
7478   freeAsmop (left, NULL, ic, TRUE);
7479   freeAsmop (result, NULL, ic, TRUE);
7480 }
7481
7482 /*-----------------------------------------------------------------*/
7483 /* genGetAbit - generates code get a single bit                    */
7484 /*-----------------------------------------------------------------*/
7485 static void
7486 genGetAbit (iCode * ic)
7487 {
7488   operand *left, *right, *result;
7489   int shCount;
7490
7491   D(emitcode (";     genGetAbit",""));
7492
7493   left = IC_LEFT (ic);
7494   right = IC_RIGHT (ic);
7495   result = IC_RESULT (ic);
7496   aopOp (left, ic, FALSE);
7497   aopOp (right, ic, FALSE);
7498   aopOp (result, ic, FALSE);
7499
7500   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7501
7502   /* get the needed byte into a */
7503   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7504   shCount %= 8;
7505   if (AOP_TYPE (result) == AOP_CRY)
7506     {
7507       if ((shCount) == 7)
7508           emitcode ("rlc", "a");
7509       else if ((shCount) == 0)
7510           emitcode ("rrc", "a");
7511       else
7512           emitcode ("mov", "c,acc[%d]", shCount);
7513       outBitC (result);
7514     }
7515   else
7516     {
7517       switch (shCount)
7518         {
7519         case 2:
7520           emitcode ("rr", "a");
7521           //fallthrough
7522         case 1:
7523           emitcode ("rr", "a");
7524           //fallthrough
7525         case 0:
7526           emitcode ("anl", "a,#0x01");
7527           break;
7528         case 3:
7529         case 5:
7530           emitcode ("mov", "c,acc[%d]", shCount);
7531           emitcode ("clr", "a");
7532           emitcode ("rlc", "a");
7533           break;
7534         case 4:
7535           emitcode ("swap", "a");
7536           emitcode ("anl", "a,#0x01");
7537           break;
7538         case 6:
7539           emitcode ("rl", "a");
7540           //fallthrough
7541         case 7:
7542           emitcode ("rl", "a");
7543           emitcode ("anl", "a,#0x01");
7544           break;
7545         }
7546       outAcc (result);
7547     }
7548
7549   freeAsmop (left, NULL, ic, TRUE);
7550   freeAsmop (right, NULL, ic, TRUE);
7551   freeAsmop (result, NULL, ic, TRUE);
7552 }
7553
7554 /*-----------------------------------------------------------------*/
7555 /* genGetByte - generates code get a single byte                   */
7556 /*-----------------------------------------------------------------*/
7557 static void
7558 genGetByte (iCode * ic)
7559 {
7560   operand *left, *right, *result;
7561   int offset;
7562
7563   D(emitcode (";     genGetByte",""));
7564
7565   left = IC_LEFT (ic);
7566   right = IC_RIGHT (ic);
7567   result = IC_RESULT (ic);
7568   aopOp (left, ic, FALSE);
7569   aopOp (right, ic, FALSE);
7570   aopOp (result, ic, FALSE);
7571
7572   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7573   aopPut (result,
7574           aopGet (left, offset, FALSE, FALSE),
7575           0,
7576           isOperandVolatile (result, FALSE));
7577
7578   freeAsmop (left, NULL, ic, TRUE);
7579   freeAsmop (right, NULL, ic, TRUE);
7580   freeAsmop (result, NULL, ic, TRUE);
7581 }
7582
7583 /*-----------------------------------------------------------------*/
7584 /* genGetWord - generates code get two bytes                       */
7585 /*-----------------------------------------------------------------*/
7586 static void
7587 genGetWord (iCode * ic)
7588 {
7589   operand *left, *right, *result;
7590   int offset;
7591
7592   D(emitcode (";     genGetWord",""));
7593
7594   left = IC_LEFT (ic);
7595   right = IC_RIGHT (ic);
7596   result = IC_RESULT (ic);
7597   aopOp (left, ic, FALSE);
7598   aopOp (right, ic, FALSE);
7599   aopOp (result, ic, FALSE);
7600
7601   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7602   aopPut (result,
7603           aopGet (left, offset, FALSE, FALSE),
7604           0,
7605           isOperandVolatile (result, FALSE));
7606   aopPut (result,
7607           aopGet (left, offset+1, FALSE, FALSE),
7608           1,
7609           isOperandVolatile (result, FALSE));
7610
7611   freeAsmop (left, NULL, ic, TRUE);
7612   freeAsmop (right, NULL, ic, TRUE);
7613   freeAsmop (result, NULL, ic, TRUE);
7614 }
7615
7616 /*-----------------------------------------------------------------*/
7617 /* genSwap - generates code to swap nibbles or bytes               */
7618 /*-----------------------------------------------------------------*/
7619 static void
7620 genSwap (iCode * ic)
7621 {
7622   operand *left, *result;
7623
7624   D(emitcode (";     genSwap",""));
7625
7626   left = IC_LEFT (ic);
7627   result = IC_RESULT (ic);
7628   aopOp (left, ic, FALSE);
7629   aopOp (result, ic, FALSE);
7630
7631   switch (AOP_SIZE (left))
7632     {
7633     case 1: /* swap nibbles in byte */
7634       MOVA (aopGet (left, 0, FALSE, FALSE));
7635       emitcode ("swap", "a");
7636       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7637       break;
7638     case 2: /* swap bytes in word */
7639       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7640         {
7641           MOVA (aopGet (left, 0, FALSE, FALSE));
7642           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7643                   0, isOperandVolatile (result, FALSE));
7644           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7645         }
7646       else if (operandsEqu (left, result))
7647         {
7648           char * reg = "a";
7649           bool pushedB = FALSE, leftInB = FALSE;
7650
7651           MOVA (aopGet (left, 0, FALSE, FALSE));
7652           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7653             {
7654               pushedB = pushB ();
7655               emitcode ("mov", "b,a");
7656               reg = "b";
7657               leftInB = TRUE;
7658             }
7659           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7660                   0, isOperandVolatile (result, FALSE));
7661           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7662
7663           if (leftInB)
7664             popB (pushedB);
7665         }
7666       else
7667         {
7668           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7669                   0, isOperandVolatile (result, FALSE));
7670           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7671                   1, isOperandVolatile (result, FALSE));
7672         }
7673       break;
7674     default:
7675       wassertl(FALSE, "unsupported SWAP operand size");
7676     }
7677
7678   freeAsmop (left, NULL, ic, TRUE);
7679   freeAsmop (result, NULL, ic, TRUE);
7680 }
7681
7682
7683 /*-----------------------------------------------------------------*/
7684 /* AccRol - rotate left accumulator by known count                 */
7685 /*-----------------------------------------------------------------*/
7686 static void
7687 AccRol (int shCount)
7688 {
7689   shCount &= 0x0007;            // shCount : 0..7
7690
7691   switch (shCount)
7692     {
7693     case 0:
7694       break;
7695     case 1:
7696       emitcode ("rl", "a");
7697       break;
7698     case 2:
7699       emitcode ("rl", "a");
7700       emitcode ("rl", "a");
7701       break;
7702     case 3:
7703       emitcode ("swap", "a");
7704       emitcode ("rr", "a");
7705       break;
7706     case 4:
7707       emitcode ("swap", "a");
7708       break;
7709     case 5:
7710       emitcode ("swap", "a");
7711       emitcode ("rl", "a");
7712       break;
7713     case 6:
7714       emitcode ("rr", "a");
7715       emitcode ("rr", "a");
7716       break;
7717     case 7:
7718       emitcode ("rr", "a");
7719       break;
7720     }
7721 }
7722
7723 /*-----------------------------------------------------------------*/
7724 /* AccLsh - left shift accumulator by known count                  */
7725 /*-----------------------------------------------------------------*/
7726 static void
7727 AccLsh (int shCount)
7728 {
7729   if (shCount != 0)
7730     {
7731       if (shCount == 1)
7732         emitcode ("add", "a,acc");
7733       else if (shCount == 2)
7734         {
7735           emitcode ("add", "a,acc");
7736           emitcode ("add", "a,acc");
7737         }
7738       else
7739         {
7740           /* rotate left accumulator */
7741           AccRol (shCount);
7742           /* and kill the lower order bits */
7743           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7744         }
7745     }
7746 }
7747
7748 /*-----------------------------------------------------------------*/
7749 /* AccRsh - right shift accumulator by known count                 */
7750 /*-----------------------------------------------------------------*/
7751 static void
7752 AccRsh (int shCount)
7753 {
7754   if (shCount != 0)
7755     {
7756       if (shCount == 1)
7757         {
7758           CLRC;
7759           emitcode ("rrc", "a");
7760         }
7761       else
7762         {
7763           /* rotate right accumulator */
7764           AccRol (8 - shCount);
7765           /* and kill the higher order bits */
7766           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7767         }
7768     }
7769 }
7770
7771 /*-----------------------------------------------------------------*/
7772 /* AccSRsh - signed right shift accumulator by known count                 */
7773 /*-----------------------------------------------------------------*/
7774 static void
7775 AccSRsh (int shCount)
7776 {
7777   symbol *tlbl;
7778   if (shCount != 0)
7779     {
7780       if (shCount == 1)
7781         {
7782           emitcode ("mov", "c,acc.7");
7783           emitcode ("rrc", "a");
7784         }
7785       else if (shCount == 2)
7786         {
7787           emitcode ("mov", "c,acc.7");
7788           emitcode ("rrc", "a");
7789           emitcode ("mov", "c,acc.7");
7790           emitcode ("rrc", "a");
7791         }
7792       else
7793         {
7794           tlbl = newiTempLabel (NULL);
7795           /* rotate right accumulator */
7796           AccRol (8 - shCount);
7797           /* and kill the higher order bits */
7798           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7799           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7800           emitcode ("orl", "a,#0x%02x",
7801                     (unsigned char) ~SRMask[shCount]);
7802           emitcode ("", "%05d$:", tlbl->key + 100);
7803         }
7804     }
7805 }
7806
7807 /*-----------------------------------------------------------------*/
7808 /* shiftR1Left2Result - shift right one byte from left to result   */
7809 /*-----------------------------------------------------------------*/
7810 static void
7811 shiftR1Left2Result (operand * left, int offl,
7812                     operand * result, int offr,
7813                     int shCount, int sign)
7814 {
7815   MOVA (aopGet (left, offl, FALSE, FALSE));
7816   /* shift right accumulator */
7817   if (sign)
7818     AccSRsh (shCount);
7819   else
7820     AccRsh (shCount);
7821   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7822 }
7823
7824 /*-----------------------------------------------------------------*/
7825 /* shiftL1Left2Result - shift left one byte from left to result    */
7826 /*-----------------------------------------------------------------*/
7827 static void
7828 shiftL1Left2Result (operand * left, int offl,
7829                     operand * result, int offr, int shCount)
7830 {
7831   char *l;
7832   l = aopGet (left, offl, FALSE, FALSE);
7833   MOVA (l);
7834   /* shift left accumulator */
7835   AccLsh (shCount);
7836   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7837 }
7838
7839 /*-----------------------------------------------------------------*/
7840 /* movLeft2Result - move byte from left to result                  */
7841 /*-----------------------------------------------------------------*/
7842 static void
7843 movLeft2Result (operand * left, int offl,
7844                 operand * result, int offr, int sign)
7845 {
7846   char *l;
7847   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7848     {
7849       l = aopGet (left, offl, FALSE, FALSE);
7850
7851       if (*l == '@' && (IS_AOP_PREG (result)))
7852         {
7853           emitcode ("mov", "a,%s", l);
7854           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7855         }
7856       else
7857         {
7858           if (!sign)
7859             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7860           else
7861             {
7862               /* MSB sign in acc.7 ! */
7863               if (getDataSize (left) == offl + 1)
7864                 {
7865                   MOVA (l);
7866                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7867                 }
7868             }
7869         }
7870     }
7871 }
7872
7873 /*-----------------------------------------------------------------*/
7874 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7875 /*-----------------------------------------------------------------*/
7876 static void
7877 AccAXRrl1 (char *x)
7878 {
7879   emitcode ("rrc", "a");
7880   emitcode ("xch", "a,%s", x);
7881   emitcode ("rrc", "a");
7882   emitcode ("xch", "a,%s", x);
7883 }
7884
7885 /*-----------------------------------------------------------------*/
7886 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7887 /*-----------------------------------------------------------------*/
7888 static void
7889 AccAXLrl1 (char *x)
7890 {
7891   emitcode ("xch", "a,%s", x);
7892   emitcode ("rlc", "a");
7893   emitcode ("xch", "a,%s", x);
7894   emitcode ("rlc", "a");
7895 }
7896
7897 /*-----------------------------------------------------------------*/
7898 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7899 /*-----------------------------------------------------------------*/
7900 static void
7901 AccAXLsh1 (char *x)
7902 {
7903   emitcode ("xch", "a,%s", x);
7904   emitcode ("add", "a,acc");
7905   emitcode ("xch", "a,%s", x);
7906   emitcode ("rlc", "a");
7907 }
7908
7909 /*-----------------------------------------------------------------*/
7910 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7911 /*-----------------------------------------------------------------*/
7912 static void
7913 AccAXLsh (char *x, int shCount)
7914 {
7915   switch (shCount)
7916     {
7917     case 0:
7918       break;
7919     case 1:
7920       AccAXLsh1 (x);
7921       break;
7922     case 2:
7923       AccAXLsh1 (x);
7924       AccAXLsh1 (x);
7925       break;
7926     case 3:
7927     case 4:
7928     case 5:                     // AAAAABBB:CCCCCDDD
7929
7930       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7931
7932       emitcode ("anl", "a,#0x%02x",
7933                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7934
7935       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7936
7937       AccRol (shCount);         // DDDCCCCC:BBB00000
7938
7939       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7940
7941       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7942
7943       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7944
7945       emitcode ("anl", "a,#0x%02x",
7946                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7947
7948       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7949
7950       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7951
7952       break;
7953     case 6:                     // AAAAAABB:CCCCCCDD
7954       emitcode ("anl", "a,#0x%02x",
7955                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7956       emitcode ("mov", "c,acc.0");      // c = B
7957       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7958 #if 0 // REMOVE ME
7959       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7960       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7961 #else
7962       emitcode("rrc","a");
7963       emitcode("xch","a,%s", x);
7964       emitcode("rrc","a");
7965       emitcode("mov","c,acc.0"); //<< get correct bit
7966       emitcode("xch","a,%s", x);
7967
7968       emitcode("rrc","a");
7969       emitcode("xch","a,%s", x);
7970       emitcode("rrc","a");
7971       emitcode("xch","a,%s", x);
7972 #endif
7973       break;
7974     case 7:                     // a:x <<= 7
7975
7976       emitcode ("anl", "a,#0x%02x",
7977                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7978
7979       emitcode ("mov", "c,acc.0");      // c = B
7980
7981       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7982
7983       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7984
7985       break;
7986     default:
7987       break;
7988     }
7989 }
7990
7991 /*-----------------------------------------------------------------*/
7992 /* AccAXRsh - right shift a:x known count (0..7)                   */
7993 /*-----------------------------------------------------------------*/
7994 static void
7995 AccAXRsh (char *x, int shCount)
7996 {
7997   switch (shCount)
7998     {
7999     case 0:
8000       break;
8001     case 1:
8002       CLRC;
8003       AccAXRrl1 (x);            // 0->a:x
8004
8005       break;
8006     case 2:
8007       CLRC;
8008       AccAXRrl1 (x);            // 0->a:x
8009
8010       CLRC;
8011       AccAXRrl1 (x);            // 0->a:x
8012
8013       break;
8014     case 3:
8015     case 4:
8016     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8017
8018       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8019
8020       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8021
8022       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8023
8024       emitcode ("anl", "a,#0x%02x",
8025                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8026
8027       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8028
8029       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8030
8031       emitcode ("anl", "a,#0x%02x",
8032                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8033
8034       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8035
8036       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8037
8038       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8039
8040       break;
8041     case 6:                     // AABBBBBB:CCDDDDDD
8042
8043       emitcode ("mov", "c,acc.7");
8044       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8045
8046       emitcode ("mov", "c,acc.7");
8047       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8048
8049       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8050
8051       emitcode ("anl", "a,#0x%02x",
8052                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8053
8054       break;
8055     case 7:                     // ABBBBBBB:CDDDDDDD
8056
8057       emitcode ("mov", "c,acc.7");      // c = A
8058
8059       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8060
8061       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8062
8063       emitcode ("anl", "a,#0x%02x",
8064                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8065
8066       break;
8067     default:
8068       break;
8069     }
8070 }
8071
8072 /*-----------------------------------------------------------------*/
8073 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8074 /*-----------------------------------------------------------------*/
8075 static void
8076 AccAXRshS (char *x, int shCount)
8077 {
8078   symbol *tlbl;
8079   switch (shCount)
8080     {
8081     case 0:
8082       break;
8083     case 1:
8084       emitcode ("mov", "c,acc.7");
8085       AccAXRrl1 (x);            // s->a:x
8086
8087       break;
8088     case 2:
8089       emitcode ("mov", "c,acc.7");
8090       AccAXRrl1 (x);            // s->a:x
8091
8092       emitcode ("mov", "c,acc.7");
8093       AccAXRrl1 (x);            // s->a:x
8094
8095       break;
8096     case 3:
8097     case 4:
8098     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8099
8100       tlbl = newiTempLabel (NULL);
8101       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8102
8103       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8104
8105       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8106
8107       emitcode ("anl", "a,#0x%02x",
8108                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8109
8110       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8111
8112       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8113
8114       emitcode ("anl", "a,#0x%02x",
8115                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8116
8117       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8118
8119       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8120
8121       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8122
8123       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8124       emitcode ("orl", "a,#0x%02x",
8125                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8126
8127       emitcode ("", "%05d$:", tlbl->key + 100);
8128       break;                    // SSSSAAAA:BBBCCCCC
8129
8130     case 6:                     // AABBBBBB:CCDDDDDD
8131
8132       tlbl = newiTempLabel (NULL);
8133       emitcode ("mov", "c,acc.7");
8134       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8135
8136       emitcode ("mov", "c,acc.7");
8137       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8138
8139       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8140
8141       emitcode ("anl", "a,#0x%02x",
8142                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8143
8144       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8145       emitcode ("orl", "a,#0x%02x",
8146                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8147
8148       emitcode ("", "%05d$:", tlbl->key + 100);
8149       break;
8150     case 7:                     // ABBBBBBB:CDDDDDDD
8151
8152       tlbl = newiTempLabel (NULL);
8153       emitcode ("mov", "c,acc.7");      // c = A
8154
8155       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8156
8157       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8158
8159       emitcode ("anl", "a,#0x%02x",
8160                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8161
8162       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8163       emitcode ("orl", "a,#0x%02x",
8164                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8165
8166       emitcode ("", "%05d$:", tlbl->key + 100);
8167       break;
8168     default:
8169       break;
8170     }
8171 }
8172
8173 /*-----------------------------------------------------------------*/
8174 /* shiftL2Left2Result - shift left two bytes from left to result   */
8175 /*-----------------------------------------------------------------*/
8176 static void
8177 shiftL2Left2Result (operand * left, int offl,
8178                     operand * result, int offr, int shCount)
8179 {
8180   char * x;
8181   bool pushedB = FALSE;
8182   bool usedB = FALSE;
8183
8184   if (sameRegs (AOP (result), AOP (left)) &&
8185       ((offl + MSB16) == offr))
8186     {
8187       /* don't crash result[offr] */
8188       MOVA (aopGet (left, offl, FALSE, FALSE));
8189       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8190       x = aopGet (result, offr, FALSE, FALSE);
8191     }
8192   else if (aopGetUsesAcc (result, offr))
8193     {
8194       movLeft2Result (left, offl, result, offr, 0);
8195       pushedB = pushB ();
8196       usedB = TRUE;
8197       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8198       MOVA (aopGet (result, offr, FALSE, FALSE));
8199       emitcode ("xch", "a,b");
8200       x = "b";
8201     }
8202   else
8203     {
8204       movLeft2Result (left, offl, result, offr, 0);
8205       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8206       x = aopGet (result, offr, FALSE, FALSE);
8207     }
8208   /* ax << shCount (x = lsb(result)) */
8209   AccAXLsh (x, shCount);
8210   if (usedB)
8211     {
8212       emitcode ("xch", "a,b");
8213       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8214       aopPut (result, "b", offr + MSB16, isOperandVolatile (result, FALSE));
8215       popB (pushedB);
8216     }
8217   else
8218     {
8219       aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8220     }
8221 }
8222
8223
8224 /*-----------------------------------------------------------------*/
8225 /* shiftR2Left2Result - shift right two bytes from left to result  */
8226 /*-----------------------------------------------------------------*/
8227 static void
8228 shiftR2Left2Result (operand * left, int offl,
8229                     operand * result, int offr,
8230                     int shCount, int sign)
8231 {
8232   char * x;
8233   bool pushedB = FALSE;
8234   bool usedB = FALSE;
8235
8236   if (sameRegs (AOP (result), AOP (left)) &&
8237       ((offl + MSB16) == offr))
8238     {
8239       /* don't crash result[offr] */
8240       MOVA (aopGet (left, offl, FALSE, FALSE));
8241       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8242       x = aopGet (result, offr, FALSE, FALSE);
8243     }
8244   else if (aopGetUsesAcc (result, offr))
8245     {
8246       movLeft2Result (left, offl, result, offr, 0);
8247       pushedB = pushB ();
8248       usedB = TRUE;
8249       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8250       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8251       x = "b";
8252     }
8253   else
8254     {
8255       movLeft2Result (left, offl, result, offr, 0);
8256       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8257       x = aopGet (result, offr, FALSE, FALSE);
8258     }
8259   /* a:x >> shCount (x = lsb(result)) */
8260   if (sign)
8261     AccAXRshS (x, shCount);
8262   else
8263     AccAXRsh (x, shCount);
8264   if (usedB)
8265     {
8266       emitcode ("xch", "a,b");
8267       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8268       emitcode ("xch", "a,b");
8269       popB (pushedB);
8270     }
8271   if (getDataSize (result) > 1)
8272     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8273 }
8274
8275 /*-----------------------------------------------------------------*/
8276 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8277 /*-----------------------------------------------------------------*/
8278 static void
8279 shiftLLeftOrResult (operand * left, int offl,
8280                     operand * result, int offr, int shCount)
8281 {
8282   MOVA (aopGet (left, offl, FALSE, FALSE));
8283   /* shift left accumulator */
8284   AccLsh (shCount);
8285   /* or with result */
8286   if (aopGetUsesAcc (result, offr))
8287     {
8288       emitcode ("xch", "a,b");
8289       MOVA (aopGet (result, offr, FALSE, FALSE));
8290       emitcode ("orl", "a,b");
8291     }
8292   else
8293     {
8294       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8295     }
8296   /* back to result */
8297   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8298 }
8299
8300 /*-----------------------------------------------------------------*/
8301 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8302 /*-----------------------------------------------------------------*/
8303 static void
8304 shiftRLeftOrResult (operand * left, int offl,
8305                     operand * result, int offr, int shCount)
8306 {
8307   MOVA (aopGet (left, offl, FALSE, FALSE));
8308   /* shift right accumulator */
8309   AccRsh (shCount);
8310   /* or with result */
8311   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8312   /* back to result */
8313   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8314 }
8315
8316 /*-----------------------------------------------------------------*/
8317 /* genlshOne - left shift a one byte quantity by known count       */
8318 /*-----------------------------------------------------------------*/
8319 static void
8320 genlshOne (operand * result, operand * left, int shCount)
8321 {
8322   D(emitcode (";     genlshOne",""));
8323
8324   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8325 }
8326
8327 /*-----------------------------------------------------------------*/
8328 /* genlshTwo - left shift two bytes by known amount != 0           */
8329 /*-----------------------------------------------------------------*/
8330 static void
8331 genlshTwo (operand * result, operand * left, int shCount)
8332 {
8333   int size;
8334
8335   D(emitcode (";     genlshTwo",""));
8336
8337   size = getDataSize (result);
8338
8339   /* if shCount >= 8 */
8340   if (shCount >= 8)
8341     {
8342       shCount -= 8;
8343
8344       if (size > 1)
8345         {
8346           if (shCount)
8347             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8348           else
8349             movLeft2Result (left, LSB, result, MSB16, 0);
8350         }
8351       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8352     }
8353
8354   /*  1 <= shCount <= 7 */
8355   else
8356     {
8357       if (size == 1)
8358         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8359       else
8360         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8361     }
8362 }
8363
8364 /*-----------------------------------------------------------------*/
8365 /* shiftLLong - shift left one long from left to result            */
8366 /* offl = LSB or MSB16                                             */
8367 /*-----------------------------------------------------------------*/
8368 static void
8369 shiftLLong (operand * left, operand * result, int offr)
8370 {
8371   char *l;
8372   int size = AOP_SIZE (result);
8373
8374   if (size >= LSB + offr)
8375     {
8376       l = aopGet (left, LSB, FALSE, FALSE);
8377       MOVA (l);
8378       emitcode ("add", "a,acc");
8379       if (sameRegs (AOP (left), AOP (result)) &&
8380           size >= MSB16 + offr && offr != LSB)
8381         emitcode ("xch", "a,%s",
8382                   aopGet (left, LSB + offr, FALSE, FALSE));
8383       else
8384         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
8385     }
8386
8387   if (size >= MSB16 + offr)
8388     {
8389       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8390         {
8391           l = aopGet (left, MSB16, FALSE, FALSE);
8392           MOVA (l);
8393         }
8394       emitcode ("rlc", "a");
8395       if (sameRegs (AOP (left), AOP (result)) &&
8396           size >= MSB24 + offr && offr != LSB)
8397         emitcode ("xch", "a,%s",
8398                   aopGet (left, MSB16 + offr, FALSE, FALSE));
8399       else
8400         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
8401     }
8402
8403   if (size >= MSB24 + offr)
8404     {
8405       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8406         {
8407           l = aopGet (left, MSB24, FALSE, FALSE);
8408           MOVA (l);
8409         }
8410       emitcode ("rlc", "a");
8411       if (sameRegs (AOP (left), AOP (result)) &&
8412           size >= MSB32 + offr && offr != LSB)
8413         emitcode ("xch", "a,%s",
8414                   aopGet (left, MSB24 + offr, FALSE, FALSE));
8415       else
8416         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
8417     }
8418
8419   if (size > MSB32 + offr)
8420     {
8421       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8422         {
8423           l = aopGet (left, MSB32, FALSE, FALSE);
8424           MOVA (l);
8425         }
8426       emitcode ("rlc", "a");
8427       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
8428     }
8429   if (offr != LSB)
8430     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8431 }
8432
8433 /*-----------------------------------------------------------------*/
8434 /* genlshFour - shift four byte by a known amount != 0             */
8435 /*-----------------------------------------------------------------*/
8436 static void
8437 genlshFour (operand * result, operand * left, int shCount)
8438 {
8439   int size;
8440
8441   D(emitcode (";     genlshFour",""));
8442
8443   size = AOP_SIZE (result);
8444
8445   /* if shifting more that 3 bytes */
8446   if (shCount >= 24)
8447     {
8448       shCount -= 24;
8449       if (shCount)
8450         /* lowest order of left goes to the highest
8451            order of the destination */
8452         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8453       else
8454         movLeft2Result (left, LSB, result, MSB32, 0);
8455       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8456       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8457       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
8458       return;
8459     }
8460
8461   /* more than two bytes */
8462   else if (shCount >= 16)
8463     {
8464       /* lower order two bytes goes to higher order two bytes */
8465       shCount -= 16;
8466       /* if some more remaining */
8467       if (shCount)
8468         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8469       else
8470         {
8471           movLeft2Result (left, MSB16, result, MSB32, 0);
8472           movLeft2Result (left, LSB, result, MSB24, 0);
8473         }
8474       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8475       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8476       return;
8477     }
8478
8479   /* if more than 1 byte */
8480   else if (shCount >= 8)
8481     {
8482       /* lower order three bytes goes to higher order  three bytes */
8483       shCount -= 8;
8484       if (size == 2)
8485         {
8486           if (shCount)
8487             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8488           else
8489             movLeft2Result (left, LSB, result, MSB16, 0);
8490         }
8491       else
8492         {                       /* size = 4 */
8493           if (shCount == 0)
8494             {
8495               movLeft2Result (left, MSB24, result, MSB32, 0);
8496               movLeft2Result (left, MSB16, result, MSB24, 0);
8497               movLeft2Result (left, LSB, result, MSB16, 0);
8498               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8499             }
8500           else if (shCount == 1)
8501             shiftLLong (left, result, MSB16);
8502           else
8503             {
8504               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8505               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8506               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8507               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8508             }
8509         }
8510     }
8511
8512   /* 1 <= shCount <= 7 */
8513   else if (shCount <= 2)
8514     {
8515       shiftLLong (left, result, LSB);
8516       if (shCount == 2)
8517         shiftLLong (result, result, LSB);
8518     }
8519   /* 3 <= shCount <= 7, optimize */
8520   else
8521     {
8522       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8523       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8524       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8525     }
8526 }
8527
8528 /*-----------------------------------------------------------------*/
8529 /* genLeftShiftLiteral - left shifting by known count              */
8530 /*-----------------------------------------------------------------*/
8531 static void
8532 genLeftShiftLiteral (operand * left,
8533                      operand * right,
8534                      operand * result,
8535                      iCode * ic)
8536 {
8537   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8538   int size;
8539
8540   D(emitcode (";     genLeftShiftLiteral",""));
8541
8542   freeAsmop (right, NULL, ic, TRUE);
8543
8544   aopOp (left, ic, FALSE);
8545   aopOp (result, ic, FALSE);
8546
8547   size = getSize (operandType (result));
8548
8549 #if VIEW_SIZE
8550   emitcode ("; shift left ", "result %d, left %d", size,
8551             AOP_SIZE (left));
8552 #endif
8553
8554   /* I suppose that the left size >= result size */
8555   if (shCount == 0)
8556     {
8557       while (size--)
8558         {
8559           movLeft2Result (left, size, result, size, 0);
8560         }
8561     }
8562
8563   else if (shCount >= (size * 8))
8564     while (size--)
8565       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
8566   else
8567     {
8568       switch (size)
8569         {
8570         case 1:
8571           genlshOne (result, left, shCount);
8572           break;
8573
8574         case 2:
8575           genlshTwo (result, left, shCount);
8576           break;
8577
8578         case 4:
8579           genlshFour (result, left, shCount);
8580           break;
8581         default:
8582           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8583                   "*** ack! mystery literal shift!\n");
8584           break;
8585         }
8586     }
8587   freeAsmop (left, NULL, ic, TRUE);
8588   freeAsmop (result, NULL, ic, TRUE);
8589 }
8590
8591 /*-----------------------------------------------------------------*/
8592 /* genLeftShift - generates code for left shifting                 */
8593 /*-----------------------------------------------------------------*/
8594 static void
8595 genLeftShift (iCode * ic)
8596 {
8597   operand *left, *right, *result;
8598   int size, offset;
8599   char *l;
8600   symbol *tlbl, *tlbl1;
8601   bool pushedB;
8602
8603   D(emitcode (";     genLeftShift",""));
8604
8605   right = IC_RIGHT (ic);
8606   left = IC_LEFT (ic);
8607   result = IC_RESULT (ic);
8608
8609   aopOp (right, ic, FALSE);
8610
8611   /* if the shift count is known then do it
8612      as efficiently as possible */
8613   if (AOP_TYPE (right) == AOP_LIT)
8614     {
8615       genLeftShiftLiteral (left, right, result, ic);
8616       return;
8617     }
8618
8619   /* shift count is unknown then we have to form
8620      a loop get the loop count in B : Note: we take
8621      only the lower order byte since shifting
8622      more that 32 bits make no sense anyway, ( the
8623      largest size of an object can be only 32 bits ) */
8624
8625   pushedB = pushB ();
8626   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8627   emitcode ("inc", "b");
8628   freeAsmop (right, NULL, ic, TRUE);
8629   aopOp (left, ic, FALSE);
8630   aopOp (result, ic, FALSE);
8631
8632   /* now move the left to the result if they are not the same */
8633   if (!sameRegs (AOP (left), AOP (result)) &&
8634       AOP_SIZE (result) > 1)
8635     {
8636
8637       size = AOP_SIZE (result);
8638       offset = 0;
8639       while (size--)
8640         {
8641           l = aopGet (left, offset, FALSE, TRUE);
8642           if (*l == '@' && (IS_AOP_PREG (result)))
8643             {
8644
8645               emitcode ("mov", "a,%s", l);
8646               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8647             }
8648           else
8649             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8650           offset++;
8651         }
8652     }
8653
8654   tlbl = newiTempLabel (NULL);
8655   size = AOP_SIZE (result);
8656   offset = 0;
8657   tlbl1 = newiTempLabel (NULL);
8658
8659   /* if it is only one byte then */
8660   if (size == 1)
8661     {
8662       symbol *tlbl1 = newiTempLabel (NULL);
8663
8664       l = aopGet (left, 0, FALSE, FALSE);
8665       MOVA (l);
8666       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8667       emitcode ("", "%05d$:", tlbl->key + 100);
8668       emitcode ("add", "a,acc");
8669       emitcode ("", "%05d$:", tlbl1->key + 100);
8670       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8671       popB (pushedB);
8672       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8673       goto release;
8674     }
8675
8676   reAdjustPreg (AOP (result));
8677
8678   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8679   emitcode ("", "%05d$:", tlbl->key + 100);
8680   l = aopGet (result, offset, FALSE, FALSE);
8681   MOVA (l);
8682   emitcode ("add", "a,acc");
8683   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8684   while (--size)
8685     {
8686       l = aopGet (result, offset, FALSE, FALSE);
8687       MOVA (l);
8688       emitcode ("rlc", "a");
8689       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8690     }
8691   reAdjustPreg (AOP (result));
8692
8693   emitcode ("", "%05d$:", tlbl1->key + 100);
8694   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8695   popB (pushedB);
8696 release:
8697   freeAsmop (left, NULL, ic, TRUE);
8698   freeAsmop (result, NULL, ic, TRUE);
8699 }
8700
8701 /*-----------------------------------------------------------------*/
8702 /* genrshOne - right shift a one byte quantity by known count      */
8703 /*-----------------------------------------------------------------*/
8704 static void
8705 genrshOne (operand * result, operand * left,
8706            int shCount, int sign)
8707 {
8708   D(emitcode (";     genrshOne",""));
8709
8710   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8711 }
8712
8713 /*-----------------------------------------------------------------*/
8714 /* genrshTwo - right shift two bytes by known amount != 0          */
8715 /*-----------------------------------------------------------------*/
8716 static void
8717 genrshTwo (operand * result, operand * left,
8718            int shCount, int sign)
8719 {
8720   D(emitcode (";     genrshTwo",""));
8721
8722   /* if shCount >= 8 */
8723   if (shCount >= 8)
8724     {
8725       shCount -= 8;
8726       if (shCount)
8727         shiftR1Left2Result (left, MSB16, result, LSB,
8728                             shCount, sign);
8729       else
8730         movLeft2Result (left, MSB16, result, LSB, sign);
8731       addSign (result, MSB16, sign);
8732     }
8733
8734   /*  1 <= shCount <= 7 */
8735   else
8736     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8737 }
8738
8739 /*-----------------------------------------------------------------*/
8740 /* shiftRLong - shift right one long from left to result           */
8741 /* offl = LSB or MSB16                                             */
8742 /*-----------------------------------------------------------------*/
8743 static void
8744 shiftRLong (operand * left, int offl,
8745             operand * result, int sign)
8746 {
8747   int isSameRegs = sameRegs (AOP (left), AOP (result));
8748
8749   if (isSameRegs && offl>1) {
8750     // we are in big trouble, but this shouldn't happen
8751     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8752   }
8753
8754   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8755
8756   if (offl==MSB16) {
8757     // shift is > 8
8758     if (sign) {
8759       emitcode ("rlc", "a");
8760       emitcode ("subb", "a,acc");
8761       if (isSameRegs)
8762         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8763       else {
8764         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8765         MOVA (aopGet (left, MSB32, FALSE, FALSE));
8766       }
8767     } else {
8768       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8769     }
8770   }
8771
8772   if (!sign) {
8773     emitcode ("clr", "c");
8774   } else {
8775     emitcode ("mov", "c,acc.7");
8776   }
8777
8778   emitcode ("rrc", "a");
8779
8780   if (isSameRegs && offl==MSB16) {
8781     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8782   } else {
8783     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8784     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8785   }
8786
8787   emitcode ("rrc", "a");
8788   if (isSameRegs && offl==1) {
8789     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8790   } else {
8791     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8792     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8793   }
8794   emitcode ("rrc", "a");
8795   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8796
8797   if (offl == LSB)
8798     {
8799       MOVA (aopGet (left, LSB, FALSE, FALSE));
8800       emitcode ("rrc", "a");
8801       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8802     }
8803 }
8804
8805 /*-----------------------------------------------------------------*/
8806 /* genrshFour - shift four byte by a known amount != 0             */
8807 /*-----------------------------------------------------------------*/
8808 static void
8809 genrshFour (operand * result, operand * left,
8810             int shCount, int sign)
8811 {
8812   D(emitcode (";     genrshFour",""));
8813
8814   /* if shifting more that 3 bytes */
8815   if (shCount >= 24)
8816     {
8817       shCount -= 24;
8818       if (shCount)
8819         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8820       else
8821         movLeft2Result (left, MSB32, result, LSB, sign);
8822       addSign (result, MSB16, sign);
8823     }
8824   else if (shCount >= 16)
8825     {
8826       shCount -= 16;
8827       if (shCount)
8828         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8829       else
8830         {
8831           movLeft2Result (left, MSB24, result, LSB, 0);
8832           movLeft2Result (left, MSB32, result, MSB16, sign);
8833         }
8834       addSign (result, MSB24, sign);
8835     }
8836   else if (shCount >= 8)
8837     {
8838       shCount -= 8;
8839       if (shCount == 1)
8840         shiftRLong (left, MSB16, result, sign);
8841       else if (shCount == 0)
8842         {
8843           movLeft2Result (left, MSB16, result, LSB, 0);
8844           movLeft2Result (left, MSB24, result, MSB16, 0);
8845           movLeft2Result (left, MSB32, result, MSB24, sign);
8846           addSign (result, MSB32, sign);
8847         }
8848       else
8849         {
8850           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8851           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8852           /* the last shift is signed */
8853           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8854           addSign (result, MSB32, sign);
8855         }
8856     }
8857   else
8858     {                           /* 1 <= shCount <= 7 */
8859       if (shCount <= 2)
8860         {
8861           shiftRLong (left, LSB, result, sign);
8862           if (shCount == 2)
8863             shiftRLong (result, LSB, result, sign);
8864         }
8865       else
8866         {
8867           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8868           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8869           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8870         }
8871     }
8872 }
8873
8874 /*-----------------------------------------------------------------*/
8875 /* genRightShiftLiteral - right shifting by known count            */
8876 /*-----------------------------------------------------------------*/
8877 static void
8878 genRightShiftLiteral (operand * left,
8879                       operand * right,
8880                       operand * result,
8881                       iCode * ic,
8882                       int sign)
8883 {
8884   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8885   int size;
8886
8887   D(emitcode (";     genRightShiftLiteral",""));
8888
8889   freeAsmop (right, NULL, ic, TRUE);
8890
8891   aopOp (left, ic, FALSE);
8892   aopOp (result, ic, FALSE);
8893
8894 #if VIEW_SIZE
8895   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8896             AOP_SIZE (left));
8897 #endif
8898
8899   size = getDataSize (left);
8900   /* test the LEFT size !!! */
8901
8902   /* I suppose that the left size >= result size */
8903   if (shCount == 0)
8904     {
8905       size = getDataSize (result);
8906       while (size--)
8907         movLeft2Result (left, size, result, size, 0);
8908     }
8909
8910   else if (shCount >= (size * 8))
8911     {
8912       if (sign) {
8913         /* get sign in acc.7 */
8914         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8915       }
8916       addSign (result, LSB, sign);
8917     }
8918   else
8919     {
8920       switch (size)
8921         {
8922         case 1:
8923           genrshOne (result, left, shCount, sign);
8924           break;
8925
8926         case 2:
8927           genrshTwo (result, left, shCount, sign);
8928           break;
8929
8930         case 4:
8931           genrshFour (result, left, shCount, sign);
8932           break;
8933         default:
8934           break;
8935         }
8936     }
8937   freeAsmop (left, NULL, ic, TRUE);
8938   freeAsmop (result, NULL, ic, TRUE);
8939 }
8940
8941 /*-----------------------------------------------------------------*/
8942 /* genSignedRightShift - right shift of signed number              */
8943 /*-----------------------------------------------------------------*/
8944 static void
8945 genSignedRightShift (iCode * ic)
8946 {
8947   operand *right, *left, *result;
8948   int size, offset;
8949   char *l;
8950   symbol *tlbl, *tlbl1;
8951   bool pushedB;
8952
8953   D(emitcode (";     genSignedRightShift",""));
8954
8955   /* we do it the hard way put the shift count in b
8956      and loop thru preserving the sign */
8957
8958   right = IC_RIGHT (ic);
8959   left = IC_LEFT (ic);
8960   result = IC_RESULT (ic);
8961
8962   aopOp (right, ic, FALSE);
8963
8964
8965   if (AOP_TYPE (right) == AOP_LIT)
8966     {
8967       genRightShiftLiteral (left, right, result, ic, 1);
8968       return;
8969     }
8970   /* shift count is unknown then we have to form
8971      a loop get the loop count in B : Note: we take
8972      only the lower order byte since shifting
8973      more that 32 bits make no sense anyway, ( the
8974      largest size of an object can be only 32 bits ) */
8975
8976   pushedB = pushB ();
8977   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8978   emitcode ("inc", "b");
8979   freeAsmop (right, NULL, ic, TRUE);
8980   aopOp (left, ic, FALSE);
8981   aopOp (result, ic, FALSE);
8982
8983   /* now move the left to the result if they are not the
8984      same */
8985   if (!sameRegs (AOP (left), AOP (result)) &&
8986       AOP_SIZE (result) > 1)
8987     {
8988
8989       size = AOP_SIZE (result);
8990       offset = 0;
8991       while (size--)
8992         {
8993           l = aopGet (left, offset, FALSE, TRUE);
8994           if (*l == '@' && IS_AOP_PREG (result))
8995             {
8996
8997               emitcode ("mov", "a,%s", l);
8998               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8999             }
9000           else
9001             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
9002           offset++;
9003         }
9004     }
9005
9006   /* mov the highest order bit to OVR */
9007   tlbl = newiTempLabel (NULL);
9008   tlbl1 = newiTempLabel (NULL);
9009
9010   size = AOP_SIZE (result);
9011   offset = size - 1;
9012   MOVA (aopGet (left, offset, FALSE, FALSE));
9013   emitcode ("rlc", "a");
9014   emitcode ("mov", "ov,c");
9015   /* if it is only one byte then */
9016   if (size == 1)
9017     {
9018       l = aopGet (left, 0, FALSE, FALSE);
9019       MOVA (l);
9020       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9021       emitcode ("", "%05d$:", tlbl->key + 100);
9022       emitcode ("mov", "c,ov");
9023       emitcode ("rrc", "a");
9024       emitcode ("", "%05d$:", tlbl1->key + 100);
9025       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9026       popB (pushedB);
9027       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9028       goto release;
9029     }
9030
9031   reAdjustPreg (AOP (result));
9032   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9033   emitcode ("", "%05d$:", tlbl->key + 100);
9034   emitcode ("mov", "c,ov");
9035   while (size--)
9036     {
9037       l = aopGet (result, offset, FALSE, FALSE);
9038       MOVA (l);
9039       emitcode ("rrc", "a");
9040       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9041     }
9042   reAdjustPreg (AOP (result));
9043   emitcode ("", "%05d$:", tlbl1->key + 100);
9044   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9045   popB (pushedB);
9046
9047 release:
9048   freeAsmop (left, NULL, ic, TRUE);
9049   freeAsmop (result, NULL, ic, TRUE);
9050 }
9051
9052 /*-----------------------------------------------------------------*/
9053 /* genRightShift - generate code for right shifting                */
9054 /*-----------------------------------------------------------------*/
9055 static void
9056 genRightShift (iCode * ic)
9057 {
9058   operand *right, *left, *result;
9059   sym_link *letype;
9060   int size, offset;
9061   char *l;
9062   symbol *tlbl, *tlbl1;
9063   bool pushedB;
9064
9065   D(emitcode (";     genRightShift",""));
9066
9067   /* if signed then we do it the hard way preserve the
9068      sign bit moving it inwards */
9069   letype = getSpec (operandType (IC_LEFT (ic)));
9070
9071   if (!SPEC_USIGN (letype))
9072     {
9073       genSignedRightShift (ic);
9074       return;
9075     }
9076
9077   /* signed & unsigned types are treated the same : i.e. the
9078      signed is NOT propagated inwards : quoting from the
9079      ANSI - standard : "for E1 >> E2, is equivalent to division
9080      by 2**E2 if unsigned or if it has a non-negative value,
9081      otherwise the result is implementation defined ", MY definition
9082      is that the sign does not get propagated */
9083
9084   right = IC_RIGHT (ic);
9085   left = IC_LEFT (ic);
9086   result = IC_RESULT (ic);
9087
9088   aopOp (right, ic, FALSE);
9089
9090   /* if the shift count is known then do it
9091      as efficiently as possible */
9092   if (AOP_TYPE (right) == AOP_LIT)
9093     {
9094       genRightShiftLiteral (left, right, result, ic, 0);
9095       return;
9096     }
9097
9098   /* shift count is unknown then we have to form
9099      a loop get the loop count in B : Note: we take
9100      only the lower order byte since shifting
9101      more that 32 bits make no sense anyway, ( the
9102      largest size of an object can be only 32 bits ) */
9103
9104   pushedB = pushB ();
9105   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
9106   emitcode ("inc", "b");
9107   freeAsmop (right, NULL, ic, TRUE);
9108   aopOp (left, ic, FALSE);
9109   aopOp (result, ic, FALSE);
9110
9111   /* now move the left to the result if they are not the
9112      same */
9113   if (!sameRegs (AOP (left), AOP (result)) &&
9114       AOP_SIZE (result) > 1)
9115     {
9116
9117       size = AOP_SIZE (result);
9118       offset = 0;
9119       while (size--)
9120         {
9121           l = aopGet (left, offset, FALSE, TRUE);
9122           if (*l == '@' && IS_AOP_PREG (result))
9123             {
9124
9125               emitcode ("mov", "a,%s", l);
9126               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9127             }
9128           else
9129             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
9130           offset++;
9131         }
9132     }
9133
9134   tlbl = newiTempLabel (NULL);
9135   tlbl1 = newiTempLabel (NULL);
9136   size = AOP_SIZE (result);
9137   offset = size - 1;
9138
9139   /* if it is only one byte then */
9140   if (size == 1)
9141     {
9142       l = aopGet (left, 0, FALSE, FALSE);
9143       MOVA (l);
9144       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9145       emitcode ("", "%05d$:", tlbl->key + 100);
9146       CLRC;
9147       emitcode ("rrc", "a");
9148       emitcode ("", "%05d$:", tlbl1->key + 100);
9149       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9150       popB (pushedB);
9151       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9152       goto release;
9153     }
9154
9155   reAdjustPreg (AOP (result));
9156   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9157   emitcode ("", "%05d$:", tlbl->key + 100);
9158   CLRC;
9159   while (size--)
9160     {
9161       l = aopGet (result, offset, FALSE, FALSE);
9162       MOVA (l);
9163       emitcode ("rrc", "a");
9164       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9165     }
9166   reAdjustPreg (AOP (result));
9167
9168   emitcode ("", "%05d$:", tlbl1->key + 100);
9169   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9170   popB (pushedB);
9171
9172 release:
9173   freeAsmop (left, NULL, ic, TRUE);
9174   freeAsmop (result, NULL, ic, TRUE);
9175 }
9176
9177 /*-----------------------------------------------------------------*/
9178 /* emitPtrByteGet - emits code to get a byte into A through a      */
9179 /*                  pointer register (R0, R1, or DPTR). The        */
9180 /*                  original value of A can be preserved in B.     */
9181 /*-----------------------------------------------------------------*/
9182 static void
9183 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9184 {
9185   switch (p_type)
9186     {
9187     case IPOINTER:
9188     case POINTER:
9189       if (preserveAinB)
9190         emitcode ("mov", "b,a");
9191       emitcode ("mov", "a,@%s", rname);
9192       break;
9193
9194     case PPOINTER:
9195       if (preserveAinB)
9196         emitcode ("mov", "b,a");
9197       emitcode ("movx", "a,@%s", rname);
9198       break;
9199
9200     case FPOINTER:
9201       if (preserveAinB)
9202         emitcode ("mov", "b,a");
9203       emitcode ("movx", "a,@dptr");
9204       break;
9205
9206     case CPOINTER:
9207       if (preserveAinB)
9208         emitcode ("mov", "b,a");
9209       emitcode ("clr", "a");
9210       emitcode ("movc", "a,@a+dptr");
9211       break;
9212
9213     case GPOINTER:
9214       if (preserveAinB)
9215         {
9216           emitcode ("push", "b");
9217           emitcode ("push", "acc");
9218         }
9219       emitcode ("lcall", "__gptrget");
9220       if (preserveAinB)
9221         emitcode ("pop", "b");
9222       break;
9223     }
9224 }
9225
9226 /*-----------------------------------------------------------------*/
9227 /* emitPtrByteSet - emits code to set a byte from src through a    */
9228 /*                  pointer register (R0, R1, or DPTR).            */
9229 /*-----------------------------------------------------------------*/
9230 static void
9231 emitPtrByteSet (char *rname, int p_type, char *src)
9232 {
9233   switch (p_type)
9234     {
9235     case IPOINTER:
9236     case POINTER:
9237       if (*src=='@')
9238         {
9239           MOVA (src);
9240           emitcode ("mov", "@%s,a", rname);
9241         }
9242       else
9243         emitcode ("mov", "@%s,%s", rname, src);
9244       break;
9245
9246     case PPOINTER:
9247       MOVA (src);
9248       emitcode ("movx", "@%s,a", rname);
9249       break;
9250
9251     case FPOINTER:
9252       MOVA (src);
9253       emitcode ("movx", "@dptr,a");
9254       break;
9255
9256     case GPOINTER:
9257       MOVA (src);
9258       emitcode ("lcall", "__gptrput");
9259       break;
9260     }
9261 }
9262
9263 /*-----------------------------------------------------------------*/
9264 /* genUnpackBits - generates code for unpacking bits               */
9265 /*-----------------------------------------------------------------*/
9266 static void
9267 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9268 {
9269   int offset = 0;       /* result byte offset */
9270   int rsize;            /* result size */
9271   int rlen = 0;         /* remaining bitfield length */
9272   sym_link *etype;      /* bitfield type information */
9273   int blen;             /* bitfield length */
9274   int bstr;             /* bitfield starting bit within byte */
9275   char buffer[10];
9276
9277   D(emitcode (";     genUnpackBits",""));
9278
9279   etype = getSpec (operandType (result));
9280   rsize = getSize (operandType (result));
9281   blen = SPEC_BLEN (etype);
9282   bstr = SPEC_BSTR (etype);
9283
9284   if (ifx && blen <= 8)
9285     {
9286       emitPtrByteGet (rname, ptype, FALSE);
9287       if (blen == 1)
9288         {
9289           SNPRINTF (buffer, sizeof(buffer),
9290                     "acc.%d", bstr);
9291           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9292         }
9293       else
9294         {
9295           if (blen < 8)
9296             emitcode ("anl", "a,#0x%02x",
9297                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9298           genIfxJump (ifx, "a", NULL, NULL, NULL);
9299         }
9300       return;
9301     }
9302   wassert (!ifx);
9303
9304   /* If the bitfield length is less than a byte */
9305   if (blen < 8)
9306     {
9307       emitPtrByteGet (rname, ptype, FALSE);
9308       AccRsh (bstr);
9309       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9310       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9311       goto finish;
9312     }
9313
9314   /* Bit field did not fit in a byte. Copy all
9315      but the partial byte at the end.  */
9316   for (rlen=blen;rlen>=8;rlen-=8)
9317     {
9318       emitPtrByteGet (rname, ptype, FALSE);
9319       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9320       if (rlen>8)
9321         emitcode ("inc", "%s", rname);
9322     }
9323
9324   /* Handle the partial byte at the end */
9325   if (rlen)
9326     {
9327       emitPtrByteGet (rname, ptype, FALSE);
9328       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9329       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9330     }
9331
9332 finish:
9333   if (offset < rsize)
9334     {
9335       rsize -= offset;
9336       while (rsize--)
9337         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
9338     }
9339 }
9340
9341
9342 /*-----------------------------------------------------------------*/
9343 /* genDataPointerGet - generates code when ptr offset is known     */
9344 /*-----------------------------------------------------------------*/
9345 static void
9346 genDataPointerGet (operand * left,
9347                    operand * result,
9348                    iCode * ic)
9349 {
9350   char *l;
9351   char buffer[256];
9352   int size, offset = 0;
9353
9354   D(emitcode (";     genDataPointerGet",""));
9355
9356   aopOp (result, ic, TRUE);
9357
9358   /* get the string representation of the name */
9359   l = aopGet (left, 0, FALSE, TRUE);
9360   size = AOP_SIZE (result);
9361   while (size--)
9362     {
9363       if (offset)
9364         sprintf (buffer, "(%s + %d)", l + 1, offset);
9365       else
9366         sprintf (buffer, "%s", l + 1);
9367       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
9368     }
9369
9370   freeAsmop (left, NULL, ic, TRUE);
9371   freeAsmop (result, NULL, ic, TRUE);
9372 }
9373
9374 /*-----------------------------------------------------------------*/
9375 /* genNearPointerGet - emitcode for near pointer fetch             */
9376 /*-----------------------------------------------------------------*/
9377 static void
9378 genNearPointerGet (operand * left,
9379                    operand * result,
9380                    iCode * ic,
9381                    iCode * pi,
9382                    iCode * ifx)
9383 {
9384   asmop *aop = NULL;
9385   regs *preg = NULL;
9386   char *rname;
9387   sym_link *rtype, *retype;
9388   sym_link *ltype = operandType (left);
9389   char buffer[80];
9390
9391   D(emitcode (";     genNearPointerGet",""));
9392
9393   rtype = operandType (result);
9394   retype = getSpec (rtype);
9395
9396   aopOp (left, ic, FALSE);
9397
9398   /* if left is rematerialisable and
9399      result is not bitfield variable type and
9400      the left is pointer to data space i.e
9401      lower 128 bytes of space */
9402   if (AOP_TYPE (left) == AOP_IMMD &&
9403       !IS_BITFIELD (retype) &&
9404       DCL_TYPE (ltype) == POINTER)
9405     {
9406       genDataPointerGet (left, result, ic);
9407       return;
9408     }
9409
9410  /* if the value is already in a pointer register
9411      then don't need anything more */
9412   if (!AOP_INPREG (AOP (left)))
9413     {
9414       if (IS_AOP_PREG (left))
9415         {
9416           // Aha, it is a pointer, just in disguise.
9417           rname = aopGet (left, 0, FALSE, FALSE);
9418           if (*rname != '@')
9419             {
9420               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9421                       __FILE__, __LINE__);
9422             }
9423           else
9424             {
9425               // Expected case.
9426               emitcode ("mov", "a%s,%s", rname + 1, rname);
9427               rname++;  // skip the '@'.
9428             }
9429         }
9430       else
9431         {
9432           /* otherwise get a free pointer register */
9433           aop = newAsmop (0);
9434           preg = getFreePtr (ic, &aop, FALSE);
9435           emitcode ("mov", "%s,%s",
9436                     preg->name,
9437                     aopGet (left, 0, FALSE, TRUE));
9438           rname = preg->name;
9439         }
9440     }
9441   else
9442     rname = aopGet (left, 0, FALSE, FALSE);
9443
9444   //aopOp (result, ic, FALSE);
9445   aopOp (result, ic, result?TRUE:FALSE);
9446
9447   /* if bitfield then unpack the bits */
9448   if (IS_BITFIELD (retype))
9449     genUnpackBits (result, rname, POINTER, ifx);
9450   else
9451     {
9452       /* we have can just get the values */
9453       int size = AOP_SIZE (result);
9454       int offset = 0;
9455
9456       while (size--)
9457         {
9458           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9459             {
9460
9461               emitcode ("mov", "a,@%s", rname);
9462               if (!ifx)
9463               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9464             }
9465           else
9466             {
9467               sprintf (buffer, "@%s", rname);
9468               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
9469             }
9470           offset++;
9471           if (size || pi)
9472             emitcode ("inc", "%s", rname);
9473         }
9474     }
9475
9476   /* now some housekeeping stuff */
9477   if (aop)       /* we had to allocate for this iCode */
9478     {
9479       if (pi) { /* post increment present */
9480         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9481       }
9482       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9483     }
9484   else
9485     {
9486       /* we did not allocate which means left
9487          already in a pointer register, then
9488          if size > 0 && this could be used again
9489          we have to point it back to where it
9490          belongs */
9491       if ((AOP_SIZE (result) > 1 &&
9492            !OP_SYMBOL (left)->remat &&
9493            (OP_SYMBOL (left)->liveTo > ic->seq ||
9494             ic->depth)) &&
9495           !pi)
9496         {
9497           int size = AOP_SIZE (result) - 1;
9498           while (size--)
9499             emitcode ("dec", "%s", rname);
9500         }
9501     }
9502
9503   if (ifx && !ifx->generated)
9504     {
9505       genIfxJump (ifx, "a", left, NULL, result);
9506     }
9507
9508   /* done */
9509   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9510   freeAsmop (left, NULL, ic, TRUE);
9511   if (pi) pi->generated = 1;
9512 }
9513
9514 /*-----------------------------------------------------------------*/
9515 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9516 /*-----------------------------------------------------------------*/
9517 static void
9518 genPagedPointerGet (operand * left,
9519                     operand * result,
9520                     iCode * ic,
9521                     iCode *pi,
9522                     iCode *ifx)
9523 {
9524   asmop *aop = NULL;
9525   regs *preg = NULL;
9526   char *rname;
9527   sym_link *rtype, *retype;
9528
9529   D(emitcode (";     genPagedPointerGet",""));
9530
9531   rtype = operandType (result);
9532   retype = getSpec (rtype);
9533
9534   aopOp (left, ic, FALSE);
9535
9536   /* if the value is already in a pointer register
9537      then don't need anything more */
9538   if (!AOP_INPREG (AOP (left)))
9539     {
9540       /* otherwise get a free pointer register */
9541       aop = newAsmop (0);
9542       preg = getFreePtr (ic, &aop, FALSE);
9543       emitcode ("mov", "%s,%s",
9544                 preg->name,
9545                 aopGet (left, 0, FALSE, TRUE));
9546       rname = preg->name;
9547     }
9548   else
9549     rname = aopGet (left, 0, FALSE, FALSE);
9550
9551   aopOp (result, ic, FALSE);
9552
9553   /* if bitfield then unpack the bits */
9554   if (IS_BITFIELD (retype))
9555     genUnpackBits (result, rname, PPOINTER, ifx);
9556   else
9557     {
9558       /* we have can just get the values */
9559       int size = AOP_SIZE (result);
9560       int offset = 0;
9561
9562       while (size--)
9563         {
9564
9565           emitcode ("movx", "a,@%s", rname);
9566           if (!ifx)
9567           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9568
9569           offset++;
9570
9571           if (size || pi)
9572             emitcode ("inc", "%s", rname);
9573         }
9574     }
9575
9576   /* now some housekeeping stuff */
9577   if (aop) /* we had to allocate for this iCode */
9578     {
9579       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9580       freeAsmop (NULL, aop, ic, TRUE);
9581     }
9582   else
9583     {
9584       /* we did not allocate which means left
9585          already in a pointer register, then
9586          if size > 0 && this could be used again
9587          we have to point it back to where it
9588          belongs */
9589       if ((AOP_SIZE (result) > 1 &&
9590            !OP_SYMBOL (left)->remat &&
9591            (OP_SYMBOL (left)->liveTo > ic->seq ||
9592             ic->depth)) &&
9593           !pi)
9594         {
9595           int size = AOP_SIZE (result) - 1;
9596           while (size--)
9597             emitcode ("dec", "%s", rname);
9598         }
9599     }
9600
9601   if (ifx && !ifx->generated)
9602     {
9603       genIfxJump (ifx, "a", left, NULL, result);
9604     }
9605
9606   /* done */
9607   freeAsmop (left, NULL, ic, TRUE);
9608   freeAsmop (result, NULL, ic, TRUE);
9609   if (pi) pi->generated = 1;
9610
9611 }
9612
9613 /*--------------------------------------------------------------------*/
9614 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
9615 /*--------------------------------------------------------------------*/
9616 static void
9617 loadDptrFromOperand (operand *op, bool loadBToo)
9618 {
9619   if (AOP_TYPE (op) != AOP_STR)
9620     {
9621       /* if this is rematerializable */
9622       if (AOP_TYPE (op) == AOP_IMMD)
9623         {
9624           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
9625           if (loadBToo)
9626             {
9627               if (AOP(op)->aopu.aop_immd.from_cast_remat)
9628                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
9629               else
9630                 {
9631                   wassertl(FALSE, "need pointerCode");
9632                   emitcode ("", "; mov b,???");
9633                   /* genPointerGet and genPointerSet originally did different
9634                   ** things for this case. Both seem wrong.
9635                   ** from genPointerGet:
9636                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
9637                   ** from genPointerSet:
9638                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
9639                   */
9640                 }
9641             }
9642         }
9643       else if (AOP_TYPE (op) == AOP_DPTR)
9644         {
9645           if (loadBToo)
9646             {
9647               MOVA (aopGet (op, 0, FALSE, FALSE));
9648               emitcode ("push", "acc");
9649               MOVA (aopGet (op, 1, FALSE, FALSE));
9650               emitcode ("push", "acc");
9651               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9652               emitcode ("pop", "dph");
9653               emitcode ("pop", "dpl");
9654             }
9655           else
9656             {
9657               MOVA (aopGet (op, 0, FALSE, FALSE));
9658               emitcode ("push", "acc");
9659               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9660               emitcode ("pop", "dpl");
9661             }
9662         }
9663       else
9664         {                       /* we need to get it byte by byte */
9665           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9666           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9667           if (loadBToo)
9668             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9669         }
9670     }
9671 }
9672
9673 /*-----------------------------------------------------------------*/
9674 /* genFarPointerGet - gget value from far space                    */
9675 /*-----------------------------------------------------------------*/
9676 static void
9677 genFarPointerGet (operand * left,
9678                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9679 {
9680   int size, offset;
9681   sym_link *retype = getSpec (operandType (result));
9682
9683   D(emitcode (";     genFarPointerGet",""));
9684
9685   aopOp (left, ic, FALSE);
9686   loadDptrFromOperand (left, FALSE);
9687
9688   /* so dptr now contains the address */
9689   aopOp (result, ic, FALSE);
9690
9691   /* if bit then unpack */
9692   if (IS_BITFIELD (retype))
9693     genUnpackBits (result, "dptr", FPOINTER, ifx);
9694   else
9695     {
9696       size = AOP_SIZE (result);
9697       offset = 0;
9698
9699       while (size--)
9700         {
9701           emitcode ("movx", "a,@dptr");
9702           if (!ifx)
9703             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9704           if (size || pi)
9705             emitcode ("inc", "dptr");
9706         }
9707     }
9708
9709   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9710     {
9711     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9712     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9713     pi->generated = 1;
9714   }
9715
9716   if (ifx && !ifx->generated)
9717     {
9718       genIfxJump (ifx, "a", left, NULL, result);
9719     }
9720
9721   freeAsmop (left, NULL, ic, TRUE);
9722   freeAsmop (result, NULL, ic, TRUE);
9723 }
9724
9725 /*-----------------------------------------------------------------*/
9726 /* genCodePointerGet - gget value from code space                  */
9727 /*-----------------------------------------------------------------*/
9728 static void
9729 genCodePointerGet (operand * left,
9730                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9731 {
9732   int size, offset;
9733   sym_link *retype = getSpec (operandType (result));
9734
9735   D(emitcode (";     genCodePointerGet",""));
9736
9737   aopOp (left, ic, FALSE);
9738   loadDptrFromOperand (left, FALSE);
9739
9740   /* so dptr now contains the address */
9741   aopOp (result, ic, FALSE);
9742
9743   /* if bit then unpack */
9744   if (IS_BITFIELD (retype))
9745     genUnpackBits (result, "dptr", CPOINTER, ifx);
9746   else
9747     {
9748       size = AOP_SIZE (result);
9749       offset = 0;
9750
9751       while (size--)
9752         {
9753           if (pi)
9754             {
9755               emitcode ("clr", "a");
9756               emitcode ("movc", "a,@a+dptr");
9757               if (!ifx)
9758               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9759               emitcode ("inc", "dptr");
9760             }
9761           else
9762             {
9763               emitcode ("mov", "a,#0x%02x", offset);
9764               emitcode ("movc", "a,@a+dptr");
9765               if (!ifx)
9766               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9767             }
9768         }
9769     }
9770
9771   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9772     {
9773     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9774     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9775     pi->generated = 1;
9776   }
9777
9778   if (ifx && !ifx->generated)
9779     {
9780       genIfxJump (ifx, "a", left, NULL, result);
9781     }
9782
9783   freeAsmop (left, NULL, ic, TRUE);
9784   freeAsmop (result, NULL, ic, TRUE);
9785 }
9786
9787 /*-----------------------------------------------------------------*/
9788 /* genGenPointerGet - gget value from generic pointer space        */
9789 /*-----------------------------------------------------------------*/
9790 static void
9791 genGenPointerGet (operand * left,
9792                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9793 {
9794   int size, offset;
9795   sym_link *retype = getSpec (operandType (result));
9796
9797   D(emitcode (";     genGenPointerGet",""));
9798
9799   aopOp (left, ic, FALSE);
9800   loadDptrFromOperand (left, TRUE);
9801
9802   /* so dptr know contains the address */
9803   aopOp (result, ic, FALSE);
9804
9805   /* if bit then unpack */
9806   if (IS_BITFIELD (retype))
9807     genUnpackBits (result, "dptr", GPOINTER, ifx);
9808   else
9809     {
9810       size = AOP_SIZE (result);
9811       offset = 0;
9812
9813       while (size--)
9814         {
9815           emitcode ("lcall", "__gptrget");
9816           if (!ifx)
9817           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9818           if (size || pi)
9819             emitcode ("inc", "dptr");
9820         }
9821     }
9822
9823   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9824     {
9825     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9826     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9827     pi->generated = 1;
9828   }
9829
9830   if (ifx && !ifx->generated)
9831     {
9832       genIfxJump (ifx, "a", left, NULL, result);
9833     }
9834
9835
9836   freeAsmop (left, NULL, ic, TRUE);
9837   freeAsmop (result, NULL, ic, TRUE);
9838 }
9839
9840 /*-----------------------------------------------------------------*/
9841 /* genPointerGet - generate code for pointer get                   */
9842 /*-----------------------------------------------------------------*/
9843 static void
9844 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9845 {
9846   operand *left, *result;
9847   sym_link *type, *etype;
9848   int p_type;
9849
9850   D(emitcode (";     genPointerGet",""));
9851
9852   left = IC_LEFT (ic);
9853   result = IC_RESULT (ic);
9854
9855   if (getSize (operandType (result))>1)
9856     ifx = NULL;
9857
9858   /* depending on the type of pointer we need to
9859      move it to the correct pointer register */
9860   type = operandType (left);
9861   etype = getSpec (type);
9862   /* if left is of type of pointer then it is simple */
9863   if (IS_PTR (type) && !IS_FUNC (type->next))
9864     p_type = DCL_TYPE (type);
9865   else
9866     {
9867       /* we have to go by the storage class */
9868       p_type = PTR_TYPE (SPEC_OCLS (etype));
9869     }
9870
9871   /* special case when cast remat */
9872   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9873       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9874           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9875           type = operandType (left);
9876           p_type = DCL_TYPE (type);
9877   }
9878   /* now that we have the pointer type we assign
9879      the pointer values */
9880   switch (p_type)
9881     {
9882
9883     case POINTER:
9884     case IPOINTER:
9885       genNearPointerGet (left, result, ic, pi, ifx);
9886       break;
9887
9888     case PPOINTER:
9889       genPagedPointerGet (left, result, ic, pi, ifx);
9890       break;
9891
9892     case FPOINTER:
9893       genFarPointerGet (left, result, ic, pi, ifx);
9894       break;
9895
9896     case CPOINTER:
9897       genCodePointerGet (left, result, ic, pi, ifx);
9898       break;
9899
9900     case GPOINTER:
9901       genGenPointerGet (left, result, ic, pi, ifx);
9902       break;
9903     }
9904
9905 }
9906
9907
9908
9909 /*-----------------------------------------------------------------*/
9910 /* genPackBits - generates code for packed bit storage             */
9911 /*-----------------------------------------------------------------*/
9912 static void
9913 genPackBits (sym_link * etype,
9914              operand * right,
9915              char *rname, int p_type)
9916 {
9917   int offset = 0;       /* source byte offset */
9918   int rlen = 0;         /* remaining bitfield length */
9919   int blen;             /* bitfield length */
9920   int bstr;             /* bitfield starting bit within byte */
9921   int litval;           /* source literal value (if AOP_LIT) */
9922   unsigned char mask;   /* bitmask within current byte */
9923
9924   D(emitcode (";     genPackBits",""));
9925
9926   blen = SPEC_BLEN (etype);
9927   bstr = SPEC_BSTR (etype);
9928
9929   /* If the bitfield length is less than a byte */
9930   if (blen < 8)
9931     {
9932       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9933               (unsigned char) (0xFF >> (8 - bstr)));
9934
9935       if (AOP_TYPE (right) == AOP_LIT)
9936         {
9937           /* Case with a bitfield length <8 and literal source
9938           */
9939           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9940           litval <<= bstr;
9941           litval &= (~mask) & 0xff;
9942           emitPtrByteGet (rname, p_type, FALSE);
9943           if ((mask|litval)!=0xff)
9944             emitcode ("anl","a,#0x%02x", mask);
9945           if (litval)
9946             emitcode ("orl","a,#0x%02x", litval);
9947         }
9948       else
9949         {
9950           if ((blen==1) && (p_type!=GPOINTER))
9951             {
9952               /* Case with a bitfield length == 1 and no generic pointer
9953               */
9954               if (AOP_TYPE (right) == AOP_CRY)
9955                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9956               else
9957                 {
9958                   MOVA (aopGet (right, 0, FALSE, FALSE));
9959                   emitcode ("rrc","a");
9960                 }
9961               emitPtrByteGet (rname, p_type, FALSE);
9962               emitcode ("mov","acc.%d,c",bstr);
9963             }
9964           else
9965             {
9966               bool pushedB;
9967               /* Case with a bitfield length < 8 and arbitrary source
9968               */
9969               MOVA (aopGet (right, 0, FALSE, FALSE));
9970               /* shift and mask source value */
9971               AccLsh (bstr);
9972               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9973
9974               pushedB = pushB ();
9975               /* transfer A to B and get next byte */
9976               emitPtrByteGet (rname, p_type, TRUE);
9977
9978               emitcode ("anl", "a,#0x%02x", mask);
9979               emitcode ("orl", "a,b");
9980               if (p_type == GPOINTER)
9981                 emitcode ("pop", "b");
9982
9983               popB (pushedB);
9984            }
9985         }
9986
9987       emitPtrByteSet (rname, p_type, "a");
9988       return;
9989     }
9990
9991   /* Bit length is greater than 7 bits. In this case, copy  */
9992   /* all except the partial byte at the end                 */
9993   for (rlen=blen;rlen>=8;rlen-=8)
9994     {
9995       emitPtrByteSet (rname, p_type,
9996                       aopGet (right, offset++, FALSE, TRUE) );
9997       if (rlen>8)
9998         emitcode ("inc", "%s", rname);
9999     }
10000
10001   /* If there was a partial byte at the end */
10002   if (rlen)
10003     {
10004       mask = (((unsigned char) -1 << rlen) & 0xff);
10005
10006       if (AOP_TYPE (right) == AOP_LIT)
10007         {
10008           /* Case with partial byte and literal source
10009           */
10010           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10011           litval >>= (blen-rlen);
10012           litval &= (~mask) & 0xff;
10013           emitPtrByteGet (rname, p_type, FALSE);
10014           if ((mask|litval)!=0xff)
10015             emitcode ("anl","a,#0x%02x", mask);
10016           if (litval)
10017             emitcode ("orl","a,#0x%02x", litval);
10018         }
10019       else
10020         {
10021           bool pushedB;
10022           /* Case with partial byte and arbitrary source
10023           */
10024           MOVA (aopGet (right, offset++, FALSE, FALSE));
10025           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10026
10027           pushedB = pushB ();
10028           /* transfer A to B and get next byte */
10029           emitPtrByteGet (rname, p_type, TRUE);
10030
10031           emitcode ("anl", "a,#0x%02x", mask);
10032           emitcode ("orl", "a,b");
10033           if (p_type == GPOINTER)
10034             emitcode ("pop", "b");
10035
10036           popB (pushedB);
10037         }
10038       emitPtrByteSet (rname, p_type, "a");
10039     }
10040
10041 }
10042
10043
10044 /*-----------------------------------------------------------------*/
10045 /* genDataPointerSet - remat pointer to data space                 */
10046 /*-----------------------------------------------------------------*/
10047 static void
10048 genDataPointerSet (operand * right,
10049                    operand * result,
10050                    iCode * ic)
10051 {
10052   int size, offset = 0;
10053   char *l, buffer[256];
10054
10055   D(emitcode (";     genDataPointerSet",""));
10056
10057   aopOp (right, ic, FALSE);
10058
10059   l = aopGet (result, 0, FALSE, TRUE);
10060   size = AOP_SIZE (right);
10061   while (size--)
10062     {
10063       if (offset)
10064         sprintf (buffer, "(%s + %d)", l + 1, offset);
10065       else
10066         sprintf (buffer, "%s", l + 1);
10067       emitcode ("mov", "%s,%s", buffer,
10068                 aopGet (right, offset++, FALSE, FALSE));
10069     }
10070
10071   freeAsmop (right, NULL, ic, TRUE);
10072   freeAsmop (result, NULL, ic, TRUE);
10073 }
10074
10075 /*-----------------------------------------------------------------*/
10076 /* genNearPointerSet - emitcode for near pointer put                */
10077 /*-----------------------------------------------------------------*/
10078 static void
10079 genNearPointerSet (operand * right,
10080                    operand * result,
10081                    iCode * ic,
10082                    iCode * pi)
10083 {
10084   asmop *aop = NULL;
10085   regs *preg = NULL;
10086   char *rname, *l;
10087   sym_link *retype, *letype;
10088   sym_link *ptype = operandType (result);
10089
10090   D(emitcode (";     genNearPointerSet",""));
10091
10092   retype = getSpec (operandType (right));
10093   letype = getSpec (ptype);
10094   aopOp (result, ic, FALSE);
10095
10096   /* if the result is rematerializable &
10097      in data space & not a bit variable */
10098   if (AOP_TYPE (result) == AOP_IMMD &&
10099       DCL_TYPE (ptype) == POINTER &&
10100       !IS_BITVAR (retype) &&
10101       !IS_BITVAR (letype))
10102     {
10103       genDataPointerSet (right, result, ic);
10104       return;
10105     }
10106
10107   /* if the value is already in a pointer register
10108      then don't need anything more */
10109   if (!AOP_INPREG (AOP (result)))
10110     {
10111         if (
10112             //AOP_TYPE (result) == AOP_STK
10113             IS_AOP_PREG(result)
10114             )
10115         {
10116             // Aha, it is a pointer, just in disguise.
10117             rname = aopGet (result, 0, FALSE, FALSE);
10118             if (*rname != '@')
10119             {
10120                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10121                         __FILE__, __LINE__);
10122             }
10123             else
10124             {
10125                 // Expected case.
10126                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10127                 rname++;  // skip the '@'.
10128             }
10129         }
10130         else
10131         {
10132             /* otherwise get a free pointer register */
10133             aop = newAsmop (0);
10134             preg = getFreePtr (ic, &aop, FALSE);
10135             emitcode ("mov", "%s,%s",
10136                       preg->name,
10137                       aopGet (result, 0, FALSE, TRUE));
10138             rname = preg->name;
10139         }
10140     }
10141     else
10142     {
10143         rname = aopGet (result, 0, FALSE, FALSE);
10144     }
10145
10146   aopOp (right, ic, FALSE);
10147
10148   /* if bitfield then unpack the bits */
10149   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10150     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10151   else
10152     {
10153       /* we have can just get the values */
10154       int size = AOP_SIZE (right);
10155       int offset = 0;
10156
10157       while (size--)
10158         {
10159           l = aopGet (right, offset, FALSE, TRUE);
10160           if (*l == '@')
10161             {
10162               MOVA (l);
10163               emitcode ("mov", "@%s,a", rname);
10164             }
10165           else
10166             emitcode ("mov", "@%s,%s", rname, l);
10167           if (size || pi)
10168             emitcode ("inc", "%s", rname);
10169           offset++;
10170         }
10171     }
10172
10173   /* now some housekeeping stuff */
10174   if (aop) /* we had to allocate for this iCode */
10175     {
10176       if (pi)
10177         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10178       freeAsmop (NULL, aop, ic, TRUE);
10179     }
10180   else
10181     {
10182       /* we did not allocate which means left
10183          already in a pointer register, then
10184          if size > 0 && this could be used again
10185          we have to point it back to where it
10186          belongs */
10187       if ((AOP_SIZE (right) > 1 &&
10188            !OP_SYMBOL (result)->remat &&
10189            (OP_SYMBOL (result)->liveTo > ic->seq ||
10190             ic->depth)) &&
10191           !pi)
10192         {
10193           int size = AOP_SIZE (right) - 1;
10194           while (size--)
10195             emitcode ("dec", "%s", rname);
10196         }
10197     }
10198
10199   /* done */
10200   if (pi) pi->generated = 1;
10201   freeAsmop (result, NULL, ic, TRUE);
10202   freeAsmop (right, NULL, ic, TRUE);
10203 }
10204
10205 /*-----------------------------------------------------------------*/
10206 /* genPagedPointerSet - emitcode for Paged pointer put             */
10207 /*-----------------------------------------------------------------*/
10208 static void
10209 genPagedPointerSet (operand * right,
10210                     operand * result,
10211                     iCode * ic,
10212                     iCode * pi)
10213 {
10214   asmop *aop = NULL;
10215   regs *preg = NULL;
10216   char *rname, *l;
10217   sym_link *retype, *letype;
10218
10219   D(emitcode (";     genPagedPointerSet",""));
10220
10221   retype = getSpec (operandType (right));
10222   letype = getSpec (operandType (result));
10223
10224   aopOp (result, ic, FALSE);
10225
10226   /* if the value is already in a pointer register
10227      then don't need anything more */
10228   if (!AOP_INPREG (AOP (result)))
10229     {
10230       /* otherwise get a free pointer register */
10231       aop = newAsmop (0);
10232       preg = getFreePtr (ic, &aop, FALSE);
10233       emitcode ("mov", "%s,%s",
10234                 preg->name,
10235                 aopGet (result, 0, FALSE, TRUE));
10236       rname = preg->name;
10237     }
10238   else
10239     rname = aopGet (result, 0, FALSE, FALSE);
10240
10241   aopOp (right, ic, FALSE);
10242
10243   /* if bitfield then unpack the bits */
10244   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10245     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10246   else
10247     {
10248       /* we have can just get the values */
10249       int size = AOP_SIZE (right);
10250       int offset = 0;
10251
10252       while (size--)
10253         {
10254           l = aopGet (right, offset, FALSE, TRUE);
10255
10256           MOVA (l);
10257           emitcode ("movx", "@%s,a", rname);
10258
10259           if (size || pi)
10260             emitcode ("inc", "%s", rname);
10261
10262           offset++;
10263         }
10264     }
10265
10266   /* now some housekeeping stuff */
10267   if (aop) /* we had to allocate for this iCode */
10268     {
10269       if (pi)
10270         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10271       freeAsmop (NULL, aop, ic, TRUE);
10272     }
10273   else
10274     {
10275       /* we did not allocate which means left
10276          already in a pointer register, then
10277          if size > 0 && this could be used again
10278          we have to point it back to where it
10279          belongs */
10280       if (AOP_SIZE (right) > 1 &&
10281           !OP_SYMBOL (result)->remat &&
10282           (OP_SYMBOL (result)->liveTo > ic->seq ||
10283            ic->depth))
10284         {
10285           int size = AOP_SIZE (right) - 1;
10286           while (size--)
10287             emitcode ("dec", "%s", rname);
10288         }
10289     }
10290
10291   /* done */
10292   if (pi) pi->generated = 1;
10293   freeAsmop (result, NULL, ic, TRUE);
10294   freeAsmop (right, NULL, ic, TRUE);
10295
10296
10297 }
10298
10299 /*-----------------------------------------------------------------*/
10300 /* genFarPointerSet - set value from far space                     */
10301 /*-----------------------------------------------------------------*/
10302 static void
10303 genFarPointerSet (operand * right,
10304                   operand * result, iCode * ic, iCode * pi)
10305 {
10306   int size, offset;
10307   sym_link *retype = getSpec (operandType (right));
10308   sym_link *letype = getSpec (operandType (result));
10309
10310   D(emitcode (";     genFarPointerSet",""));
10311
10312   aopOp (result, ic, FALSE);
10313   loadDptrFromOperand (result, FALSE);
10314
10315   /* so dptr know contains the address */
10316   aopOp (right, ic, FALSE);
10317
10318   /* if bit then unpack */
10319   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10320     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10321   else
10322     {
10323       size = AOP_SIZE (right);
10324       offset = 0;
10325
10326       while (size--)
10327         {
10328           char *l = aopGet (right, offset++, FALSE, FALSE);
10329           MOVA (l);
10330           emitcode ("movx", "@dptr,a");
10331           if (size || pi)
10332             emitcode ("inc", "dptr");
10333         }
10334     }
10335   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10336     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10337     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10338     pi->generated=1;
10339   }
10340   freeAsmop (result, NULL, ic, TRUE);
10341   freeAsmop (right, NULL, ic, TRUE);
10342 }
10343
10344 /*-----------------------------------------------------------------*/
10345 /* genGenPointerSet - set value from generic pointer space         */
10346 /*-----------------------------------------------------------------*/
10347 static void
10348 genGenPointerSet (operand * right,
10349                   operand * result, iCode * ic, iCode * pi)
10350 {
10351   int size, offset;
10352   sym_link *retype = getSpec (operandType (right));
10353   sym_link *letype = getSpec (operandType (result));
10354
10355   D(emitcode (";     genGenPointerSet",""));
10356
10357   aopOp (result, ic, FALSE);
10358   loadDptrFromOperand (result, TRUE);
10359
10360   /* so dptr know contains the address */
10361   aopOp (right, ic, FALSE);
10362
10363   /* if bit then unpack */
10364   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10365     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10366   else
10367     {
10368       size = AOP_SIZE (right);
10369       offset = 0;
10370
10371       while (size--)
10372         {
10373           char *l = aopGet (right, offset++, FALSE, FALSE);
10374           MOVA (l);
10375           emitcode ("lcall", "__gptrput");
10376           if (size || pi)
10377             emitcode ("inc", "dptr");
10378         }
10379     }
10380
10381   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10382     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10383     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10384     pi->generated=1;
10385   }
10386   freeAsmop (result, NULL, ic, TRUE);
10387   freeAsmop (right, NULL, ic, TRUE);
10388 }
10389
10390 /*-----------------------------------------------------------------*/
10391 /* genPointerSet - stores the value into a pointer location        */
10392 /*-----------------------------------------------------------------*/
10393 static void
10394 genPointerSet (iCode * ic, iCode *pi)
10395 {
10396   operand *right, *result;
10397   sym_link *type, *etype;
10398   int p_type;
10399
10400   D(emitcode (";     genPointerSet",""));
10401
10402   right = IC_RIGHT (ic);
10403   result = IC_RESULT (ic);
10404
10405   /* depending on the type of pointer we need to
10406      move it to the correct pointer register */
10407   type = operandType (result);
10408   etype = getSpec (type);
10409   /* if left is of type of pointer then it is simple */
10410   if (IS_PTR (type) && !IS_FUNC (type->next))
10411     {
10412       p_type = DCL_TYPE (type);
10413     }
10414   else
10415     {
10416       /* we have to go by the storage class */
10417       p_type = PTR_TYPE (SPEC_OCLS (etype));
10418     }
10419
10420   /* special case when cast remat */
10421   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10422       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10423           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10424           type = operandType (result);
10425           p_type = DCL_TYPE (type);
10426   }
10427   /* now that we have the pointer type we assign
10428      the pointer values */
10429   switch (p_type)
10430     {
10431
10432     case POINTER:
10433     case IPOINTER:
10434       genNearPointerSet (right, result, ic, pi);
10435       break;
10436
10437     case PPOINTER:
10438       genPagedPointerSet (right, result, ic, pi);
10439       break;
10440
10441     case FPOINTER:
10442       genFarPointerSet (right, result, ic, pi);
10443       break;
10444
10445     case GPOINTER:
10446       genGenPointerSet (right, result, ic, pi);
10447       break;
10448
10449     default:
10450       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10451               "genPointerSet: illegal pointer type");
10452     }
10453
10454 }
10455
10456 /*-----------------------------------------------------------------*/
10457 /* genIfx - generate code for Ifx statement                        */
10458 /*-----------------------------------------------------------------*/
10459 static void
10460 genIfx (iCode * ic, iCode * popIc)
10461 {
10462   operand *cond = IC_COND (ic);
10463   int isbit = 0;
10464   char *dup = NULL;
10465
10466   D(emitcode (";     genIfx",""));
10467
10468   aopOp (cond, ic, FALSE);
10469
10470   /* get the value into acc */
10471   if (AOP_TYPE (cond) != AOP_CRY)
10472     toBoolean (cond);
10473   else
10474     {
10475       isbit = 1;
10476       if (AOP(cond)->aopu.aop_dir)
10477         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10478     }
10479   /* the result is now in the accumulator or a directly addressable bit */
10480   freeAsmop (cond, NULL, ic, TRUE);
10481
10482   /* if there was something to be popped then do it */
10483   if (popIc)
10484     genIpop (popIc);
10485
10486   /* if the condition is a bit variable */
10487   if (isbit && dup)
10488     genIfxJump(ic, dup, NULL, NULL, NULL);
10489   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10490     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10491   else if (isbit && !IS_ITEMP (cond))
10492     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10493   else
10494     genIfxJump (ic, "a", NULL, NULL, NULL);
10495
10496   ic->generated = 1;
10497 }
10498
10499 /*-----------------------------------------------------------------*/
10500 /* genAddrOf - generates code for address of                       */
10501 /*-----------------------------------------------------------------*/
10502 static void
10503 genAddrOf (iCode * ic)
10504 {
10505   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10506   int size, offset;
10507
10508   D(emitcode (";     genAddrOf",""));
10509
10510   aopOp (IC_RESULT (ic), ic, FALSE);
10511
10512   /* if the operand is on the stack then we
10513      need to get the stack offset of this
10514      variable */
10515   if (sym->onStack)
10516     {
10517       /* if it has an offset then we need to compute
10518          it */
10519       if (sym->stack)
10520         {
10521           emitcode ("mov", "a,%s", SYM_BP (sym));
10522           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
10523                                          ((char) (sym->stack - _G.nRegsSaved)) :
10524                                          ((char) sym->stack)) & 0xff);
10525           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10526         }
10527       else
10528         {
10529           /* we can just move _bp */
10530           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10531         }
10532       /* fill the result with zero */
10533       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10534
10535       offset = 1;
10536       while (size--)
10537         {
10538           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10539         }
10540
10541       goto release;
10542     }
10543
10544   /* object not on stack then we need the name */
10545   size = AOP_SIZE (IC_RESULT (ic));
10546   offset = 0;
10547
10548   while (size--)
10549     {
10550       char s[SDCC_NAME_MAX];
10551       if (offset)
10552         sprintf (s, "#(%s >> %d)",
10553                  sym->rname,
10554                  offset * 8);
10555       else
10556         sprintf (s, "#%s", sym->rname);
10557       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10558     }
10559
10560 release:
10561   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10562
10563 }
10564
10565 /*-----------------------------------------------------------------*/
10566 /* genFarFarAssign - assignment when both are in far space         */
10567 /*-----------------------------------------------------------------*/
10568 static void
10569 genFarFarAssign (operand * result, operand * right, iCode * ic)
10570 {
10571   int size = AOP_SIZE (right);
10572   int offset = 0;
10573   char *l;
10574
10575   D(emitcode (";     genFarFarAssign",""));
10576
10577   /* first push the right side on to the stack */
10578   while (size--)
10579     {
10580       l = aopGet (right, offset++, FALSE, FALSE);
10581       MOVA (l);
10582       emitcode ("push", "acc");
10583     }
10584
10585   freeAsmop (right, NULL, ic, FALSE);
10586   /* now assign DPTR to result */
10587   aopOp (result, ic, FALSE);
10588   size = AOP_SIZE (result);
10589   while (size--)
10590     {
10591       emitcode ("pop", "acc");
10592       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
10593     }
10594   freeAsmop (result, NULL, ic, FALSE);
10595
10596 }
10597
10598 /*-----------------------------------------------------------------*/
10599 /* genAssign - generate code for assignment                        */
10600 /*-----------------------------------------------------------------*/
10601 static void
10602 genAssign (iCode * ic)
10603 {
10604   operand *result, *right;
10605   int size, offset;
10606   unsigned long lit = 0L;
10607
10608   D(emitcode(";     genAssign",""));
10609
10610   result = IC_RESULT (ic);
10611   right = IC_RIGHT (ic);
10612
10613   /* if they are the same */
10614   if (operandsEqu (result, right) &&
10615       !isOperandVolatile (result, FALSE) &&
10616       !isOperandVolatile (right, FALSE))
10617     return;
10618
10619   aopOp (right, ic, FALSE);
10620
10621   /* special case both in far space */
10622   if (AOP_TYPE (right) == AOP_DPTR &&
10623       IS_TRUE_SYMOP (result) &&
10624       isOperandInFarSpace (result))
10625     {
10626
10627       genFarFarAssign (result, right, ic);
10628       return;
10629     }
10630
10631   aopOp (result, ic, TRUE);
10632
10633   /* if they are the same registers */
10634   if (sameRegs (AOP (right), AOP (result)) &&
10635       !isOperandVolatile (result, FALSE) &&
10636       !isOperandVolatile (right, FALSE))
10637     goto release;
10638
10639   /* if the result is a bit */
10640   if (AOP_TYPE (result) == AOP_CRY)
10641     {
10642
10643       /* if the right size is a literal then
10644          we know what the value is */
10645       if (AOP_TYPE (right) == AOP_LIT)
10646         {
10647           if (((int) operandLitValue (right)))
10648             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10649           else
10650             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10651           goto release;
10652         }
10653
10654       /* the right is also a bit variable */
10655       if (AOP_TYPE (right) == AOP_CRY)
10656         {
10657           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10658           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10659           goto release;
10660         }
10661
10662       /* we need to or */
10663       toBoolean (right);
10664       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10665       goto release;
10666     }
10667
10668   /* bit variables done */
10669   /* general case */
10670   size = AOP_SIZE (result);
10671   offset = 0;
10672   if (AOP_TYPE (right) == AOP_LIT)
10673     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10674   if ((size > 1) &&
10675       (AOP_TYPE (result) != AOP_REG) &&
10676       (AOP_TYPE (right) == AOP_LIT) &&
10677       !IS_FLOAT (operandType (right)) &&
10678       (lit < 256L))
10679     {
10680       while ((size) && (lit))
10681         {
10682           aopPut (result,
10683                   aopGet (right, offset, FALSE, FALSE),
10684                   offset,
10685                   isOperandVolatile (result, FALSE));
10686           lit >>= 8;
10687           offset++;
10688           size--;
10689         }
10690       emitcode ("clr", "a");
10691       while (size--)
10692         {
10693           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10694           offset++;
10695         }
10696     }
10697   else
10698     {
10699       while (size--)
10700         {
10701           aopPut (result,
10702                   aopGet (right, offset, FALSE, FALSE),
10703                   offset,
10704                   isOperandVolatile (result, FALSE));
10705           offset++;
10706         }
10707     }
10708
10709 release:
10710   freeAsmop (right, NULL, ic, TRUE);
10711   freeAsmop (result, NULL, ic, TRUE);
10712 }
10713
10714 /*-----------------------------------------------------------------*/
10715 /* genJumpTab - generates code for jump table                      */
10716 /*-----------------------------------------------------------------*/
10717 static void
10718 genJumpTab (iCode * ic)
10719 {
10720   symbol *jtab,*jtablo,*jtabhi;
10721   char *l;
10722   unsigned int count;
10723
10724   D(emitcode (";     genJumpTab",""));
10725
10726   count = elementsInSet( IC_JTLABELS (ic) );
10727
10728   if( count <= 16 )
10729     {
10730       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10731          if the switch argument is in a register.
10732          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10733       /* (MB) What if peephole converts ljmp to sjmp or ret ???
10734          How will multiply by three be updated ???*/
10735       aopOp (IC_JTCOND (ic), ic, FALSE);
10736       /* get the condition into accumulator */
10737       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10738       MOVA (l);
10739       /* multiply by three */
10740       emitcode ("add", "a,acc");
10741       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10742       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10743
10744       jtab = newiTempLabel (NULL);
10745       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10746       emitcode ("jmp", "@a+dptr");
10747       emitcode ("", "%05d$:", jtab->key + 100);
10748       /* now generate the jump labels */
10749       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10750            jtab = setNextItem (IC_JTLABELS (ic)))
10751         emitcode ("ljmp", "%05d$", jtab->key + 100);
10752     }
10753   else
10754     {
10755       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10756          if the switch argument is in a register.
10757          For n>6 this algorithm may be more compact */
10758       jtablo = newiTempLabel (NULL);
10759       jtabhi = newiTempLabel (NULL);
10760
10761       /* get the condition into accumulator.
10762          Using b as temporary storage, if register push/pop is needed */
10763       aopOp (IC_JTCOND (ic), ic, FALSE);
10764       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10765       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10766           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10767         {
10768           // (MB) what if B is in use???
10769           wassertl(!BINUSE, "B was in use");
10770           emitcode ("mov", "b,%s", l);
10771           l = "b";
10772         }
10773       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10774       MOVA (l);
10775       if( count <= 112 )
10776         {
10777           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10778           emitcode ("movc", "a,@a+pc");
10779           emitcode ("push", "acc");
10780
10781           MOVA (l);
10782           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10783           emitcode ("movc", "a,@a+pc");
10784           emitcode ("push", "acc");
10785         }
10786       else
10787         {
10788           /* this scales up to n<=255, but needs two more bytes
10789              and changes dptr */
10790           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10791           emitcode ("movc", "a,@a+dptr");
10792           emitcode ("push", "acc");
10793
10794           MOVA (l);
10795           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10796           emitcode ("movc", "a,@a+dptr");
10797           emitcode ("push", "acc");
10798         }
10799
10800       emitcode ("ret", "");
10801
10802       /* now generate jump table, LSB */
10803       emitcode ("", "%05d$:", jtablo->key + 100);
10804       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10805            jtab = setNextItem (IC_JTLABELS (ic)))
10806         emitcode (".db", "%05d$", jtab->key + 100);
10807
10808       /* now generate jump table, MSB */
10809       emitcode ("", "%05d$:", jtabhi->key + 100);
10810       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10811            jtab = setNextItem (IC_JTLABELS (ic)))
10812          emitcode (".db", "%05d$>>8", jtab->key + 100);
10813     }
10814 }
10815
10816 /*-----------------------------------------------------------------*/
10817 /* genCast - gen code for casting                                  */
10818 /*-----------------------------------------------------------------*/
10819 static void
10820 genCast (iCode * ic)
10821 {
10822   operand *result = IC_RESULT (ic);
10823   sym_link *ctype = operandType (IC_LEFT (ic));
10824   sym_link *rtype = operandType (IC_RIGHT (ic));
10825   operand *right = IC_RIGHT (ic);
10826   int size, offset;
10827
10828   D(emitcode(";     genCast",""));
10829
10830   /* if they are equivalent then do nothing */
10831   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10832     return;
10833
10834   aopOp (right, ic, FALSE);
10835   aopOp (result, ic, FALSE);
10836
10837   /* if the result is a bit (and not a bitfield) */
10838   // if (AOP_TYPE (result) == AOP_CRY)
10839   if (IS_BITVAR (OP_SYMBOL (result)->type)
10840       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10841     {
10842       /* if the right size is a literal then
10843          we know what the value is */
10844       if (AOP_TYPE (right) == AOP_LIT)
10845         {
10846           if (((int) operandLitValue (right)))
10847             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10848           else
10849             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10850
10851           goto release;
10852         }
10853
10854       /* the right is also a bit variable */
10855       if (AOP_TYPE (right) == AOP_CRY)
10856         {
10857           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10858           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10859           goto release;
10860         }
10861
10862       /* we need to or */
10863       toBoolean (right);
10864       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10865       goto release;
10866     }
10867
10868
10869   /* if they are the same size : or less */
10870   if (AOP_SIZE (result) <= AOP_SIZE (right))
10871     {
10872
10873       /* if they are in the same place */
10874       if (sameRegs (AOP (right), AOP (result)))
10875         goto release;
10876
10877       /* if they in different places then copy */
10878       size = AOP_SIZE (result);
10879       offset = 0;
10880       while (size--)
10881         {
10882           aopPut (result,
10883                   aopGet (right, offset, FALSE, FALSE),
10884                   offset,
10885                   isOperandVolatile (result, FALSE));
10886           offset++;
10887         }
10888       goto release;
10889     }
10890
10891
10892   /* if the result is of type pointer */
10893   if (IS_PTR (ctype))
10894     {
10895
10896       int p_type;
10897       sym_link *type = operandType (right);
10898       sym_link *etype = getSpec (type);
10899
10900       /* pointer to generic pointer */
10901       if (IS_GENPTR (ctype))
10902         {
10903           if (IS_PTR (type))
10904             p_type = DCL_TYPE (type);
10905           else
10906             {
10907               if (SPEC_SCLS(etype)==S_REGISTER) {
10908                 // let's assume it is a generic pointer
10909                 p_type=GPOINTER;
10910               } else {
10911                 /* we have to go by the storage class */
10912                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10913               }
10914             }
10915
10916           /* the first two bytes are known */
10917           size = GPTRSIZE - 1;
10918           offset = 0;
10919           while (size--)
10920             {
10921               aopPut (result,
10922                       aopGet (right, offset, FALSE, FALSE),
10923                       offset,
10924                       isOperandVolatile (result, FALSE));
10925               offset++;
10926             }
10927           /* the last byte depending on type */
10928             {
10929                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10930                 char gpValStr[10];
10931
10932                 if (gpVal == -1)
10933                 {
10934                     // pointerTypeToGPByte will have bitched.
10935                     exit(1);
10936                 }
10937
10938                 sprintf(gpValStr, "#0x%x", gpVal);
10939                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10940             }
10941           goto release;
10942         }
10943
10944       /* just copy the pointers */
10945       size = AOP_SIZE (result);
10946       offset = 0;
10947       while (size--)
10948         {
10949           aopPut (result,
10950                   aopGet (right, offset, FALSE, FALSE),
10951                   offset,
10952                   isOperandVolatile (result, FALSE));
10953           offset++;
10954         }
10955       goto release;
10956     }
10957
10958   /* so we now know that the size of destination is greater
10959      than the size of the source */
10960   /* we move to result for the size of source */
10961   size = AOP_SIZE (right);
10962   offset = 0;
10963   while (size--)
10964     {
10965       aopPut (result,
10966               aopGet (right, offset, FALSE, FALSE),
10967               offset,
10968               isOperandVolatile (result, FALSE));
10969       offset++;
10970     }
10971
10972   /* now depending on the sign of the source && destination */
10973   size = AOP_SIZE (result) - AOP_SIZE (right);
10974   /* if unsigned or not an integral type */
10975   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10976     {
10977       while (size--)
10978         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10979     }
10980   else
10981     {
10982       /* we need to extend the sign :{ */
10983       char *l = aopGet (right, AOP_SIZE (right) - 1,
10984                         FALSE, FALSE);
10985       MOVA (l);
10986       emitcode ("rlc", "a");
10987       emitcode ("subb", "a,acc");
10988       while (size--)
10989         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10990     }
10991
10992   /* we are done hurray !!!! */
10993
10994 release:
10995   freeAsmop (right, NULL, ic, TRUE);
10996   freeAsmop (result, NULL, ic, TRUE);
10997
10998 }
10999
11000 /*-----------------------------------------------------------------*/
11001 /* genDjnz - generate decrement & jump if not zero instrucion      */
11002 /*-----------------------------------------------------------------*/
11003 static int
11004 genDjnz (iCode * ic, iCode * ifx)
11005 {
11006   symbol *lbl, *lbl1;
11007   if (!ifx)
11008     return 0;
11009
11010   D(emitcode (";     genDjnz",""));
11011
11012   /* if the if condition has a false label
11013      then we cannot save */
11014   if (IC_FALSE (ifx))
11015     return 0;
11016
11017   /* if the minus is not of the form
11018      a = a - 1 */
11019   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11020       !IS_OP_LITERAL (IC_RIGHT (ic)))
11021     return 0;
11022
11023   if (operandLitValue (IC_RIGHT (ic)) != 1)
11024     return 0;
11025
11026   /* if the size of this greater than one then no
11027      saving */
11028   if (getSize (operandType (IC_RESULT (ic))) > 1)
11029     return 0;
11030
11031   /* otherwise we can save BIG */
11032   lbl = newiTempLabel (NULL);
11033   lbl1 = newiTempLabel (NULL);
11034
11035   aopOp (IC_RESULT (ic), ic, FALSE);
11036
11037   if (AOP_NEEDSACC(IC_RESULT(ic)))
11038   {
11039       /* If the result is accessed indirectly via
11040        * the accumulator, we must explicitly write
11041        * it back after the decrement.
11042        */
11043       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11044
11045       if (strcmp(rByte, "a"))
11046       {
11047            /* Something is hopelessly wrong */
11048            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11049                    __FILE__, __LINE__);
11050            /* We can just give up; the generated code will be inefficient,
11051             * but what the hey.
11052             */
11053            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11054            return 0;
11055       }
11056       emitcode ("dec", "%s", rByte);
11057       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
11058       emitcode ("jnz", "%05d$", lbl->key + 100);
11059   }
11060   else if (IS_AOP_PREG (IC_RESULT (ic)))
11061     {
11062       emitcode ("dec", "%s",
11063                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11064       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11065       emitcode ("jnz", "%05d$", lbl->key + 100);
11066     }
11067   else
11068     {
11069       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11070                 lbl->key + 100);
11071     }
11072   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11073   emitcode ("", "%05d$:", lbl->key + 100);
11074   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11075   emitcode ("", "%05d$:", lbl1->key + 100);
11076
11077   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11078   ifx->generated = 1;
11079   return 1;
11080 }
11081
11082 /*-----------------------------------------------------------------*/
11083 /* genReceive - generate code for a receive iCode                  */
11084 /*-----------------------------------------------------------------*/
11085 static void
11086 genReceive (iCode * ic)
11087 {
11088   int size = getSize (operandType (IC_RESULT (ic)));
11089   int offset = 0;
11090
11091   D(emitcode (";     genReceive",""));
11092
11093   if (ic->argreg == 1)
11094     { /* first parameter */
11095       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11096            isOperandInPagedSpace (IC_RESULT (ic))) &&
11097           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11098            IS_TRUE_SYMOP (IC_RESULT (ic))))
11099         {
11100           regs *tempRegs[4];
11101           int receivingA = 0;
11102           int roffset = 0;
11103
11104           for (offset = 0; offset<size; offset++)
11105             if (!strcmp (fReturn[offset], "a"))
11106               receivingA = 1;
11107
11108           if (!receivingA)
11109             {
11110               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11111                 {
11112                   for (offset = size-1; offset>0; offset--)
11113                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11114                   emitcode("mov","a,%s", fReturn[0]);
11115                   _G.accInUse++;
11116                   aopOp (IC_RESULT (ic), ic, FALSE);
11117                   _G.accInUse--;
11118                   aopPut (IC_RESULT (ic), "a", offset,
11119                           isOperandVolatile (IC_RESULT (ic), FALSE));
11120                   for (offset = 1; offset<size; offset++)
11121                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
11122                             isOperandVolatile (IC_RESULT (ic), FALSE));
11123                   goto release;
11124                 }
11125             }
11126           else
11127             {
11128               if (getTempRegs(tempRegs, size, ic))
11129                 {
11130                   for (offset = 0; offset<size; offset++)
11131                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11132                   aopOp (IC_RESULT (ic), ic, FALSE);
11133                   for (offset = 0; offset<size; offset++)
11134                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
11135                             isOperandVolatile (IC_RESULT (ic), FALSE));
11136                   goto release;
11137                 }
11138             }
11139
11140           offset = fReturnSizeMCS51 - size;
11141           while (size--)
11142             {
11143               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11144                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11145               offset++;
11146             }
11147           aopOp (IC_RESULT (ic), ic, FALSE);
11148           size = AOP_SIZE (IC_RESULT (ic));
11149           offset = 0;
11150           while (size--)
11151             {
11152               emitcode ("pop", "acc");
11153               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11154             }
11155         }
11156       else
11157         {
11158           _G.accInUse++;
11159           aopOp (IC_RESULT (ic), ic, FALSE);
11160           _G.accInUse--;
11161           assignResultValue (IC_RESULT (ic), NULL);
11162         }
11163     }
11164   else if (ic->argreg > 12)
11165     { /* bit parameters */
11166       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11167         {
11168           aopOp (IC_RESULT (ic), ic, FALSE);
11169           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11170           outBitC(IC_RESULT (ic));
11171         }
11172     }
11173   else
11174     { /* other parameters */
11175       int rb1off ;
11176       aopOp (IC_RESULT (ic), ic, FALSE);
11177       rb1off = ic->argreg;
11178       while (size--)
11179         {
11180           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11181         }
11182     }
11183
11184 release:
11185   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11186 }
11187
11188 /*-----------------------------------------------------------------*/
11189 /* genDummyRead - generate code for dummy read of volatiles        */
11190 /*-----------------------------------------------------------------*/
11191 static void
11192 genDummyRead (iCode * ic)
11193 {
11194   operand *op;
11195   int size, offset;
11196
11197   D(emitcode(";     genDummyRead",""));
11198
11199   op = IC_RIGHT (ic);
11200   if (op && IS_SYMOP (op))
11201     {
11202       aopOp (op, ic, FALSE);
11203
11204       /* if the result is a bit */
11205       if (AOP_TYPE (op) == AOP_CRY)
11206         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11207       else
11208         {
11209           /* bit variables done */
11210           /* general case */
11211           size = AOP_SIZE (op);
11212           offset = 0;
11213           while (size--)
11214           {
11215             MOVA (aopGet (op, offset, FALSE, FALSE));
11216             offset++;
11217           }
11218         }
11219
11220       freeAsmop (op, NULL, ic, TRUE);
11221     }
11222
11223   op = IC_LEFT (ic);
11224   if (op && IS_SYMOP (op))
11225     {
11226       aopOp (op, ic, FALSE);
11227
11228       /* if the result is a bit */
11229       if (AOP_TYPE (op) == AOP_CRY)
11230         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11231       else
11232         {
11233           /* bit variables done */
11234           /* general case */
11235           size = AOP_SIZE (op);
11236           offset = 0;
11237           while (size--)
11238           {
11239             MOVA (aopGet (op, offset, FALSE, FALSE));
11240             offset++;
11241           }
11242         }
11243
11244       freeAsmop (op, NULL, ic, TRUE);
11245     }
11246 }
11247
11248 /*-----------------------------------------------------------------*/
11249 /* genCritical - generate code for start of a critical sequence    */
11250 /*-----------------------------------------------------------------*/
11251 static void
11252 genCritical (iCode *ic)
11253 {
11254   symbol *tlbl = newiTempLabel (NULL);
11255
11256   D(emitcode(";     genCritical",""));
11257
11258   if (IC_RESULT (ic))
11259     {
11260       aopOp (IC_RESULT (ic), ic, TRUE);
11261       aopPut (IC_RESULT (ic), one, 0, 0);
11262       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11263       aopPut (IC_RESULT (ic), zero, 0, 0);
11264       emitcode ("", "%05d$:", (tlbl->key + 100));
11265       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11266     }
11267   else
11268     {
11269       emitcode ("setb", "c");
11270       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11271       emitcode ("clr", "c");
11272       emitcode ("", "%05d$:", (tlbl->key + 100));
11273       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11274     }
11275 }
11276
11277 /*-----------------------------------------------------------------*/
11278 /* genEndCritical - generate code for end of a critical sequence   */
11279 /*-----------------------------------------------------------------*/
11280 static void
11281 genEndCritical (iCode *ic)
11282 {
11283   D(emitcode(";     genEndCritical",""));
11284
11285   if (IC_RIGHT (ic))
11286     {
11287       aopOp (IC_RIGHT (ic), ic, FALSE);
11288       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11289         {
11290           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11291           emitcode ("mov", "ea,c");
11292         }
11293       else
11294         {
11295           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11296             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11297           emitcode ("rrc", "a");
11298           emitcode ("mov", "ea,c");
11299         }
11300       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11301     }
11302   else
11303     {
11304       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11305       emitcode ("mov", "ea,c");
11306     }
11307 }
11308
11309 /*-----------------------------------------------------------------*/
11310 /* gen51Code - generate code for 8051 based controllers            */
11311 /*-----------------------------------------------------------------*/
11312 void
11313 gen51Code (iCode * lic)
11314 {
11315   iCode *ic;
11316   int cln = 0;
11317   /* int cseq = 0; */
11318
11319   _G.currentFunc = NULL;
11320   lineHead = lineCurr = NULL;
11321
11322   /* print the allocation information */
11323   if (allocInfo && currFunc)
11324     printAllocInfo (currFunc, codeOutFile);
11325   /* if debug information required */
11326   if (options.debug && currFunc)
11327     {
11328       debugFile->writeFunction (currFunc, lic);
11329     }
11330   /* stack pointer name */
11331   if (options.useXstack)
11332     spname = "_spx";
11333   else
11334     spname = "sp";
11335
11336
11337   for (ic = lic; ic; ic = ic->next)
11338     {
11339       _G.current_iCode = ic;
11340
11341       if (ic->lineno && cln != ic->lineno)
11342         {
11343           if (options.debug)
11344             {
11345               debugFile->writeCLine (ic);
11346             }
11347           if (!options.noCcodeInAsm) {
11348             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
11349                       printCLine(ic->filename, ic->lineno));
11350           }
11351           cln = ic->lineno;
11352         }
11353       #if 0
11354       if (ic->seqPoint && ic->seqPoint != cseq)
11355         {
11356           emitcode ("", "; sequence point %d", ic->seqPoint);
11357           cseq = ic->seqPoint;
11358         }
11359       #endif
11360       if (options.iCodeInAsm) {
11361         char regsInUse[80];
11362         int i;
11363
11364         for (i=0; i<8; i++) {
11365           sprintf (&regsInUse[i],
11366                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
11367         }
11368         regsInUse[i]=0;
11369         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11370       }
11371       /* if the result is marked as
11372          spilt and rematerializable or code for
11373          this has already been generated then
11374          do nothing */
11375       if (resultRemat (ic) || ic->generated)
11376         continue;
11377
11378       /* depending on the operation */
11379       switch (ic->op)
11380         {
11381         case '!':
11382           genNot (ic);
11383           break;
11384
11385         case '~':
11386           genCpl (ic);
11387           break;
11388
11389         case UNARYMINUS:
11390           genUminus (ic);
11391           break;
11392
11393         case IPUSH:
11394           genIpush (ic);
11395           break;
11396
11397         case IPOP:
11398           /* IPOP happens only when trying to restore a
11399              spilt live range, if there is an ifx statement
11400              following this pop then the if statement might
11401              be using some of the registers being popped which
11402              would destory the contents of the register so
11403              we need to check for this condition and handle it */
11404           if (ic->next &&
11405               ic->next->op == IFX &&
11406               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11407             genIfx (ic->next, ic);
11408           else
11409             genIpop (ic);
11410           break;
11411
11412         case CALL:
11413           genCall (ic);
11414           break;
11415
11416         case PCALL:
11417           genPcall (ic);
11418           break;
11419
11420         case FUNCTION:
11421           genFunction (ic);
11422           break;
11423
11424         case ENDFUNCTION:
11425           genEndFunction (ic);
11426           break;
11427
11428         case RETURN:
11429           genRet (ic);
11430           break;
11431
11432         case LABEL:
11433           genLabel (ic);
11434           break;
11435
11436         case GOTO:
11437           genGoto (ic);
11438           break;
11439
11440         case '+':
11441           genPlus (ic);
11442           break;
11443
11444         case '-':
11445           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11446             genMinus (ic);
11447           break;
11448
11449         case '*':
11450           genMult (ic);
11451           break;
11452
11453         case '/':
11454           genDiv (ic);
11455           break;
11456
11457         case '%':
11458           genMod (ic);
11459           break;
11460
11461         case '>':
11462           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11463           break;
11464
11465         case '<':
11466           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11467           break;
11468
11469         case LE_OP:
11470         case GE_OP:
11471         case NE_OP:
11472
11473           /* note these two are xlated by algebraic equivalence
11474              during parsing SDCC.y */
11475           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11476                   "got '>=' or '<=' shouldn't have come here");
11477           break;
11478
11479         case EQ_OP:
11480           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11481           break;
11482
11483         case AND_OP:
11484           genAndOp (ic);
11485           break;
11486
11487         case OR_OP:
11488           genOrOp (ic);
11489           break;
11490
11491         case '^':
11492           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11493           break;
11494
11495         case '|':
11496           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11497           break;
11498
11499         case BITWISEAND:
11500           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11501           break;
11502
11503         case INLINEASM:
11504           genInline (ic);
11505           break;
11506
11507         case RRC:
11508           genRRC (ic);
11509           break;
11510
11511         case RLC:
11512           genRLC (ic);
11513           break;
11514
11515         case GETHBIT:
11516           genGetHbit (ic);
11517           break;
11518
11519         case GETABIT:
11520           genGetAbit (ic);
11521           break;
11522
11523         case GETBYTE:
11524           genGetByte (ic);
11525           break;
11526
11527         case GETWORD:
11528           genGetWord (ic);
11529           break;
11530
11531         case LEFT_OP:
11532           genLeftShift (ic);
11533           break;
11534
11535         case RIGHT_OP:
11536           genRightShift (ic);
11537           break;
11538
11539         case GET_VALUE_AT_ADDRESS:
11540           genPointerGet (ic,
11541                          hasInc (IC_LEFT (ic), ic,
11542                                  getSize (operandType (IC_RESULT (ic)))),
11543                          ifxForOp (IC_RESULT (ic), ic) );
11544           break;
11545
11546         case '=':
11547           if (POINTER_SET (ic))
11548             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
11549           else
11550             genAssign (ic);
11551           break;
11552
11553         case IFX:
11554           genIfx (ic, NULL);
11555           break;
11556
11557         case ADDRESS_OF:
11558           genAddrOf (ic);
11559           break;
11560
11561         case JUMPTABLE:
11562           genJumpTab (ic);
11563           break;
11564
11565         case CAST:
11566           genCast (ic);
11567           break;
11568
11569         case RECEIVE:
11570           genReceive (ic);
11571           break;
11572
11573         case SEND:
11574           addSet (&_G.sendSet, ic);
11575           break;
11576
11577         case DUMMY_READ_VOLATILE:
11578           genDummyRead (ic);
11579           break;
11580
11581         case CRITICAL:
11582           genCritical (ic);
11583           break;
11584
11585         case ENDCRITICAL:
11586           genEndCritical (ic);
11587           break;
11588
11589         case SWAP:
11590           genSwap (ic);
11591           break;
11592
11593         default:
11594           ic = ic;
11595         }
11596     }
11597
11598   _G.current_iCode = NULL;
11599
11600   /* now we are ready to call the
11601      peep hole optimizer */
11602   if (!options.nopeep)
11603     peepHole (&lineHead);
11604
11605   /* now do the actual printing */
11606   printLine (lineHead, codeOutFile);
11607   return;
11608 }