* src/mcs51/gen.c (getTempRegs): return 0 if not enough registers found,
[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 = mcs51_nRegs + (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 < mcs51_nRegs; 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 (pushPsw)
2454     {
2455       if (options.useXstack)
2456         {
2457           emitcode ("mov", "a,psw");
2458           emitcode ("movx", "@%s,a", r->name);
2459
2460         }
2461       else
2462         {
2463           emitcode ("push", "psw");
2464         }
2465
2466       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2467     }
2468
2469   if (aop)
2470     {
2471       freeAsmop (NULL, aop, ic, TRUE);
2472     }
2473
2474   if (ic)
2475   {
2476     ic->bankSaved = 1;
2477   }
2478 }
2479
2480 /*-----------------------------------------------------------------*/
2481 /* unsaveRBank - restores the register bank from stack             */
2482 /*-----------------------------------------------------------------*/
2483 static void
2484 unsaveRBank (int bank, iCode * ic, bool popPsw)
2485 {
2486   int i;
2487   asmop *aop = NULL;
2488   regs *r = NULL;
2489
2490   if (options.useXstack)
2491     {
2492       if (!ic)
2493         {
2494           /* Assume r0 is available for use. */
2495           r = mcs51_regWithIdx (R0_IDX);;
2496         }
2497       else
2498         {
2499           aop = newAsmop (0);
2500           r = getFreePtr (ic, &aop, FALSE);
2501         }
2502       emitcode ("mov", "%s,%s", r->name, spname);
2503     }
2504
2505   if (popPsw)
2506     {
2507       if (options.useXstack)
2508         {
2509           emitcode ("dec", "%s", r->name);
2510           emitcode ("movx", "a,@%s", r->name);
2511           emitcode ("mov", "psw,a");
2512         }
2513       else
2514         {
2515           emitcode ("pop", "psw");
2516         }
2517     }
2518
2519   for (i = (mcs51_nRegs - 1); i >= 0; i--)
2520     {
2521       if (options.useXstack)
2522         {
2523           emitcode ("dec", "%s", r->name);
2524           emitcode ("movx", "a,@%s", r->name);
2525           emitcode ("mov", "(%s+%d),a",
2526                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2527         }
2528       else
2529         {
2530           emitcode ("pop", "(%s+%d)",
2531                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2532         }
2533     }
2534
2535   if (options.useXstack)
2536     {
2537       emitcode ("mov", "%s,%s", spname, r->name);
2538     }
2539
2540   if (aop)
2541     {
2542       freeAsmop (NULL, aop, ic, TRUE);
2543     }
2544 }
2545
2546 /*-----------------------------------------------------------------*/
2547 /* genSend - gen code for SEND                                     */
2548 /*-----------------------------------------------------------------*/
2549 static void genSend(set *sendSet)
2550 {
2551   iCode *sic;
2552   int bit_count = 0;
2553
2554   /* first we do all bit parameters */
2555   for (sic = setFirstItem (sendSet); sic;
2556        sic = setNextItem (sendSet))
2557     {
2558       aopOp (IC_LEFT (sic), sic, FALSE);
2559
2560       if (sic->argreg > 12)
2561         {
2562           int bit = sic->argreg-13;
2563
2564           /* if left is a literal then
2565              we know what the value is */
2566           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2567             {
2568               if (((int) operandLitValue (IC_LEFT (sic))))
2569                   emitcode ("setb", "b[%d]", bit);
2570               else
2571                   emitcode ("clr", "b[%d]", bit);
2572             }
2573           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2574             {
2575               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2576                 if (strcmp (l, "c"))
2577                     emitcode ("mov", "c,%s", l);
2578                 emitcode ("mov", "b[%d],c", bit);
2579             }
2580           else
2581             {
2582               /* we need to or */
2583               toBoolean (IC_LEFT (sic));
2584               /* set C, if a >= 1 */
2585               emitcode ("add", "a,#0xff");
2586               emitcode ("mov", "b[%d],c", bit);
2587             }
2588           bit_count++;
2589           BitBankUsed = 1;
2590         }
2591       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2592     }
2593
2594   if (bit_count)
2595     {
2596       saveRegisters (setFirstItem (sendSet));
2597       emitcode ("mov", "bits,b");
2598     }
2599
2600   /* then we do all other parameters */
2601   for (sic = setFirstItem (sendSet); sic;
2602        sic = setNextItem (sendSet))
2603     {
2604       int size, offset = 0;
2605       aopOp (IC_LEFT (sic), sic, FALSE);
2606       size = AOP_SIZE (IC_LEFT (sic));
2607
2608       if (sic->argreg == 1)
2609         {
2610           while (size--)
2611             {
2612               char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2613               if (strcmp (l, fReturn[offset]))
2614                   emitcode ("mov", "%s,%s", fReturn[offset], l);
2615               offset++;
2616             }
2617         }
2618       else if (sic->argreg <= 12)
2619         {
2620           while (size--)
2621             {
2622               emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2623                         aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2624               offset++;
2625             }
2626         }
2627       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2628     }
2629 }
2630
2631 /*-----------------------------------------------------------------*/
2632 /* selectRegBank - emit code to select the register bank           */
2633 /*-----------------------------------------------------------------*/
2634 static void
2635 selectRegBank (short bank, bool keepFlags)
2636 {
2637   /* if f.e. result is in carry */
2638   if (keepFlags)
2639     {
2640       emitcode ("anl", "psw,#0xE7");
2641       if (bank)
2642         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2643     }
2644   else
2645     {
2646       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2647     }
2648 }
2649
2650 /*-----------------------------------------------------------------*/
2651 /* genCall - generates a call statement                            */
2652 /*-----------------------------------------------------------------*/
2653 static void
2654 genCall (iCode * ic)
2655 {
2656   sym_link *dtype;
2657   sym_link *etype;
2658 //  bool restoreBank = FALSE;
2659   bool swapBanks = FALSE;
2660   bool accuse = FALSE;
2661   bool accPushed = FALSE;
2662   bool resultInF0 = FALSE;
2663
2664   D(emitcode(";     genCall",""));
2665
2666   dtype = operandType (IC_LEFT (ic));
2667   etype = getSpec(dtype);
2668   /* if send set is not empty then assign */
2669   if (_G.sendSet)
2670     {
2671         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2672             genSend(reverseSet(_G.sendSet));
2673         } else {
2674             genSend(_G.sendSet);
2675         }
2676
2677       _G.sendSet = NULL;
2678     }
2679
2680   /* if we are calling a not _naked function that is not using
2681      the same register bank then we need to save the
2682      destination registers on the stack */
2683   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2684       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2685        !IFFUNC_ISISR (dtype))
2686     {
2687       swapBanks = TRUE;
2688     }
2689
2690   /* if caller saves & we have not saved then */
2691   if (!ic->regsSaved)
2692       saveRegisters (ic);
2693
2694   if (swapBanks)
2695     {
2696         emitcode ("mov", "psw,#0x%02x",
2697            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2698     }
2699
2700   /* make the call */
2701   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2702     {
2703       if (IFFUNC_CALLEESAVES(dtype))
2704         {
2705           werror (E_BANKED_WITH_CALLEESAVES);
2706         }
2707       else
2708         {
2709           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2710                      OP_SYMBOL (IC_LEFT (ic))->rname :
2711                      OP_SYMBOL (IC_LEFT (ic))->name);
2712
2713           emitcode ("mov", "r0,#%s", l);
2714           emitcode ("mov", "r1,#(%s >> 8)", l);
2715           emitcode ("mov", "r2,#(%s >> 16)", l);
2716           emitcode ("lcall", "__sdcc_banked_call");
2717         }
2718     }
2719   else
2720     {
2721       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2722                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2723                                 OP_SYMBOL (IC_LEFT (ic))->name));
2724     }
2725
2726   if (swapBanks)
2727     {
2728       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2729     }
2730
2731   /* if we need assign a result value */
2732   if ((IS_ITEMP (IC_RESULT (ic)) &&
2733        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2734        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2735         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2736         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2737       IS_TRUE_SYMOP (IC_RESULT (ic)))
2738     {
2739
2740       _G.accInUse++;
2741       aopOp (IC_RESULT (ic), ic, FALSE);
2742       _G.accInUse--;
2743
2744       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2745
2746       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2747     }
2748
2749   /* adjust the stack for parameters if required */
2750   if (ic->parmBytes)
2751     {
2752       int i;
2753       if (ic->parmBytes > 3)
2754         {
2755           if (accuse)
2756             {
2757               emitcode ("push", "acc");
2758               accPushed = TRUE;
2759             }
2760           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2761               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2762             {
2763               emitcode ("mov", "F0,c");
2764               resultInF0 = TRUE;
2765             }
2766
2767           emitcode ("mov", "a,%s", spname);
2768           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2769           emitcode ("mov", "%s,a", spname);
2770
2771           /* unsaveRegisters from xstack needs acc, but */
2772           /* unsaveRegisters from stack needs this popped */
2773           if (accPushed && !options.useXstack)
2774             {
2775               emitcode ("pop", "acc");
2776               accPushed = FALSE;
2777             }
2778         }
2779       else
2780         for (i = 0; i < ic->parmBytes; i++)
2781           emitcode ("dec", "%s", spname);
2782     }
2783
2784   /* if we had saved some registers then unsave them */
2785   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2786     {
2787       if (accuse && !accPushed && options.useXstack)
2788         {
2789           /* xstack needs acc, but doesn't touch normal stack */
2790           emitcode ("push", "acc");
2791           accPushed = TRUE;
2792         }
2793       unsaveRegisters (ic);
2794     }
2795
2796 //  /* if register bank was saved then pop them */
2797 //  if (restoreBank)
2798 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2799
2800   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2801     {
2802       if (resultInF0)
2803           emitcode ("mov", "c,F0");
2804
2805       aopOp (IC_RESULT (ic), ic, FALSE);
2806       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2807       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2808     }
2809
2810   if (accPushed)
2811     emitcode ("pop", "acc");
2812 }
2813
2814 /*-----------------------------------------------------------------*/
2815 /* -10l - generates a call by pointer statement                */
2816 /*-----------------------------------------------------------------*/
2817 static void
2818 genPcall (iCode * ic)
2819 {
2820   sym_link *dtype;
2821   sym_link *etype;
2822   symbol *rlbl = newiTempLabel (NULL);
2823 //  bool restoreBank=FALSE;
2824   bool swapBanks = FALSE;
2825   bool resultInF0 = FALSE;
2826
2827   D(emitcode(";     genPCall",""));
2828
2829   dtype = operandType (IC_LEFT (ic))->next;
2830   etype = getSpec(dtype);
2831   /* if caller saves & we have not saved then */
2832   if (!ic->regsSaved)
2833     saveRegisters (ic);
2834
2835   /* if we are calling a not _naked function that is not using
2836      the same register bank then we need to save the
2837      destination registers on the stack */
2838   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2839       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2840       !IFFUNC_ISISR (dtype))
2841     {
2842 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2843 //    restoreBank=TRUE;
2844       swapBanks = TRUE;
2845       // need caution message to user here
2846     }
2847
2848   if (IS_LITERAL(etype))
2849     {
2850       /* if send set is not empty then assign */
2851       if (_G.sendSet)
2852         {
2853           genSend(reverseSet(_G.sendSet));
2854           _G.sendSet = NULL;
2855         }
2856
2857       if (swapBanks)
2858         {
2859           emitcode ("mov", "psw,#0x%02x",
2860            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2861         }
2862
2863       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2864         {
2865           if (IFFUNC_CALLEESAVES(dtype))
2866             {
2867               werror (E_BANKED_WITH_CALLEESAVES);
2868             }
2869           else
2870             {
2871               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
2872
2873               emitcode ("mov", "r0,#%s", l);
2874               emitcode ("mov", "r1,#(%s >> 8)", l);
2875               emitcode ("mov", "r2,#(%s >> 16)", l);
2876               emitcode ("lcall", "__sdcc_banked_call");
2877             }
2878         }
2879       else
2880         {
2881           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
2882         }
2883     }
2884   else
2885     {
2886       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2887         {
2888           if (IFFUNC_CALLEESAVES(dtype))
2889             {
2890               werror (E_BANKED_WITH_CALLEESAVES);
2891             }
2892           else
2893             {
2894               aopOp (IC_LEFT (ic), ic, FALSE);
2895
2896               if (!swapBanks)
2897                 {
2898                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2899                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2900                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2901                 }
2902               else
2903                 {
2904                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
2905                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2906                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2907                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2908                 }
2909
2910               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2911
2912               /* if send set is not empty then assign */
2913               if (_G.sendSet)
2914                 {
2915                   genSend(reverseSet(_G.sendSet));
2916                   _G.sendSet = NULL;
2917                 }
2918
2919               if (swapBanks)
2920                 {
2921                   emitcode ("mov", "psw,#0x%02x",
2922                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2923                 }
2924
2925               /* make the call */
2926               emitcode ("lcall", "__sdcc_banked_call");
2927             }
2928         }
2929       else
2930         {
2931           /* push the return address on to the stack */
2932           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2933           emitcode ("push", "acc");
2934           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2935           emitcode ("push", "acc");
2936
2937           /* now push the calling address */
2938           aopOp (IC_LEFT (ic), ic, FALSE);
2939
2940           pushSide (IC_LEFT (ic), FPTRSIZE);
2941
2942           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2943
2944           /* if send set is not empty the assign */
2945           if (_G.sendSet)
2946             {
2947               genSend(reverseSet(_G.sendSet));
2948               _G.sendSet = NULL;
2949             }
2950
2951           if (swapBanks)
2952             {
2953               emitcode ("mov", "psw,#0x%02x",
2954                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2955             }
2956
2957           /* make the call */
2958           emitcode ("ret", "");
2959           emitcode ("", "%05d$:", (rlbl->key + 100));
2960         }
2961     }
2962   if (swapBanks)
2963     {
2964       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2965     }
2966
2967   /* if we need assign a result value */
2968   if ((IS_ITEMP (IC_RESULT (ic)) &&
2969        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2970        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2971         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2972       IS_TRUE_SYMOP (IC_RESULT (ic)))
2973     {
2974
2975       _G.accInUse++;
2976       aopOp (IC_RESULT (ic), ic, FALSE);
2977       _G.accInUse--;
2978
2979       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2980
2981       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2982     }
2983
2984   /* adjust the stack for parameters if required */
2985   if (ic->parmBytes)
2986     {
2987       int i;
2988       if (ic->parmBytes > 3)
2989         {
2990           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2991               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2992             {
2993               emitcode ("mov", "F0,c");
2994               resultInF0 = TRUE;
2995             }
2996
2997           emitcode ("mov", "a,%s", spname);
2998           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2999           emitcode ("mov", "%s,a", spname);
3000         }
3001       else
3002         for (i = 0; i < ic->parmBytes; i++)
3003           emitcode ("dec", "%s", spname);
3004
3005     }
3006
3007 //  /* if register bank was saved then unsave them */
3008 //  if (restoreBank)
3009 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3010
3011   /* if we had saved some registers then unsave them */
3012   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3013     unsaveRegisters (ic);
3014
3015   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3016     {
3017       if (resultInF0)
3018           emitcode ("mov", "c,F0");
3019
3020       aopOp (IC_RESULT (ic), ic, FALSE);
3021       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3022       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3023     }
3024 }
3025
3026 /*-----------------------------------------------------------------*/
3027 /* resultRemat - result  is rematerializable                       */
3028 /*-----------------------------------------------------------------*/
3029 static int
3030 resultRemat (iCode * ic)
3031 {
3032   if (SKIP_IC (ic) || ic->op == IFX)
3033     return 0;
3034
3035   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3036     {
3037       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3038       if (sym->remat && !POINTER_SET (ic))
3039         return 1;
3040     }
3041
3042   return 0;
3043 }
3044
3045 #if defined(__BORLANDC__) || defined(_MSC_VER)
3046 #define STRCASECMP stricmp
3047 #else
3048 #define STRCASECMP strcasecmp
3049 #endif
3050
3051 /*-----------------------------------------------------------------*/
3052 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3053 /*-----------------------------------------------------------------*/
3054 static int
3055 regsCmp(void *p1, void *p2)
3056 {
3057   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3058 }
3059
3060 static bool
3061 inExcludeList (char *s)
3062 {
3063   const char *p = setFirstItem(options.excludeRegsSet);
3064
3065   if (p == NULL || STRCASECMP(p, "none") == 0)
3066     return FALSE;
3067
3068
3069   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3070 }
3071
3072 /*-----------------------------------------------------------------*/
3073 /* genFunction - generated code for function entry                 */
3074 /*-----------------------------------------------------------------*/
3075 static void
3076 genFunction (iCode * ic)
3077 {
3078   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3079   sym_link *ftype;
3080   bool     switchedPSW = FALSE;
3081   int      calleesaves_saved_register = -1;
3082   int      stackAdjust = sym->stack;
3083   int      accIsFree = sym->recvSize < 4;
3084   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3085   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3086
3087   _G.nRegsSaved = 0;
3088   /* create the function header */
3089   emitcode (";", "-----------------------------------------");
3090   emitcode (";", " function %s", sym->name);
3091   emitcode (";", "-----------------------------------------");
3092
3093   emitcode ("", "%s:", sym->rname);
3094   ftype = operandType (IC_LEFT (ic));
3095   _G.currentFunc = sym;
3096
3097   if (IFFUNC_ISNAKED(ftype))
3098   {
3099       emitcode(";", "naked function: no prologue.");
3100       return;
3101   }
3102
3103   /* here we need to generate the equates for the
3104      register bank if required */
3105   if (FUNC_REGBANK (ftype) != rbank)
3106     {
3107       int i;
3108
3109       rbank = FUNC_REGBANK (ftype);
3110       for (i = 0; i < mcs51_nRegs; i++)
3111         {
3112           if (regs8051[i].type != REG_BIT)
3113             {
3114               if (strcmp (regs8051[i].base, "0") == 0)
3115                 emitcode ("", "%s = 0x%02x",
3116                           regs8051[i].dname,
3117                           8 * rbank + regs8051[i].offset);
3118               else
3119                 emitcode ("", "%s = %s + 0x%02x",
3120                           regs8051[i].dname,
3121                           regs8051[i].base,
3122                           8 * rbank + regs8051[i].offset);
3123             }
3124         }
3125     }
3126
3127   /* if this is an interrupt service routine then
3128      save acc, b, dpl, dph  */
3129   if (IFFUNC_ISISR (sym->type))
3130     {
3131
3132       if (!inExcludeList ("acc"))
3133         emitcode ("push", "acc");
3134       if (!inExcludeList ("b"))
3135         emitcode ("push", "b");
3136       if (!inExcludeList ("dpl"))
3137         emitcode ("push", "dpl");
3138       if (!inExcludeList ("dph"))
3139         emitcode ("push", "dph");
3140       /* if this isr has no bank i.e. is going to
3141          run with bank 0 , then we need to save more
3142          registers :-) */
3143       if (!FUNC_REGBANK (sym->type))
3144         {
3145
3146           /* if this function does not call any other
3147              function then we can be economical and
3148              save only those registers that are used */
3149           if (!IFFUNC_HASFCALL(sym->type))
3150             {
3151               int i;
3152
3153               /* if any registers used */
3154               if (sym->regsUsed)
3155                 {
3156                   bool bits_pushed = FALSE;
3157                   /* save the registers used */
3158                   for (i = 0; i < sym->regsUsed->size; i++)
3159                     {
3160                       if (bitVectBitValue (sym->regsUsed, i))
3161                         bits_pushed = pushReg (i, bits_pushed);
3162                     }
3163                 }
3164             }
3165           else
3166             {
3167
3168               /* this function has a function call. We cannot
3169                  determines register usage so we will have to push the
3170                  entire bank */
3171                 saveRBank (0, ic, FALSE);
3172                 if (options.parms_in_bank1) {
3173                     int i;
3174                     for (i=0; i < 8 ; i++ ) {
3175                         emitcode ("push","%s",rb1regs[i]);
3176                     }
3177                 }
3178             }
3179         }
3180         else
3181         {
3182             /* This ISR uses a non-zero bank.
3183              *
3184              * We assume that the bank is available for our
3185              * exclusive use.
3186              *
3187              * However, if this ISR calls a function which uses some
3188              * other bank, we must save that bank entirely.
3189              */
3190             unsigned long banksToSave = 0;
3191
3192             if (IFFUNC_HASFCALL(sym->type))
3193             {
3194
3195 #define MAX_REGISTER_BANKS 4
3196
3197                 iCode *i;
3198                 int ix;
3199
3200                 for (i = ic; i; i = i->next)
3201                 {
3202                     if (i->op == ENDFUNCTION)
3203                     {
3204                         /* we got to the end OK. */
3205                         break;
3206                     }
3207
3208                     if (i->op == CALL)
3209                     {
3210                         sym_link *dtype;
3211
3212                         dtype = operandType (IC_LEFT(i));
3213                         if (dtype
3214                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3215                         {
3216                              /* Mark this bank for saving. */
3217                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3218                              {
3219                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3220                              }
3221                              else
3222                              {
3223                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3224                              }
3225
3226                              /* And note that we don't need to do it in
3227                               * genCall.
3228                               */
3229                              i->bankSaved = 1;
3230                         }
3231                     }
3232                     if (i->op == PCALL)
3233                     {
3234                         /* This is a mess; we have no idea what
3235                          * register bank the called function might
3236                          * use.
3237                          *
3238                          * The only thing I can think of to do is
3239                          * throw a warning and hope.
3240                          */
3241                         werror(W_FUNCPTR_IN_USING_ISR);
3242                     }
3243                 }
3244
3245                 if (banksToSave && options.useXstack)
3246                 {
3247                     /* Since we aren't passing it an ic,
3248                      * saveRBank will assume r0 is available to abuse.
3249                      *
3250                      * So switch to our (trashable) bank now, so
3251                      * the caller's R0 isn't trashed.
3252                      */
3253                     emitcode ("push", "psw");
3254                     emitcode ("mov", "psw,#0x%02x",
3255                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3256                     switchedPSW = TRUE;
3257                 }
3258
3259                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3260                 {
3261                      if (banksToSave & (1 << ix))
3262                      {
3263                          saveRBank(ix, NULL, FALSE);
3264                      }
3265                 }
3266             }
3267             // TODO: this needs a closer look
3268             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3269         }
3270
3271       /* Set the register bank to the desired value if nothing else */
3272       /* has done so yet. */
3273       if (!switchedPSW)
3274         {
3275           emitcode ("push", "psw");
3276           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3277         }
3278     }
3279   else
3280     {
3281       /* This is a non-ISR function. The caller has already switched register */
3282       /* banks, if necessary, so just handle the callee-saves option. */
3283
3284       /* if callee-save to be used for this function
3285          then save the registers being used in this function */
3286       if (IFFUNC_CALLEESAVES(sym->type))
3287         {
3288           int i;
3289
3290           /* if any registers used */
3291           if (sym->regsUsed)
3292             {
3293               bool bits_pushed = FALSE;
3294               /* save the registers used */
3295               for (i = 0; i < sym->regsUsed->size; i++)
3296                 {
3297                   if (bitVectBitValue (sym->regsUsed, i))
3298                     {
3299                       /* remember one saved register for later usage */
3300                       if (calleesaves_saved_register < 0)
3301                         calleesaves_saved_register = i;
3302                       bits_pushed = pushReg (i, bits_pushed);
3303                       _G.nRegsSaved++;
3304                     }
3305                 }
3306             }
3307         }
3308     }
3309
3310
3311   if (fReentrant)
3312     {
3313       if (options.useXstack)
3314         {
3315           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3316             {
3317               emitcode ("mov", "r0,%s", spname);
3318               emitcode ("inc", "%s", spname);
3319               emitcode ("xch", "a,_bpx");
3320               emitcode ("movx", "@r0,a");
3321               emitcode ("inc", "r0");
3322               emitcode ("mov", "a,r0");
3323               emitcode ("xch", "a,_bpx");
3324             }
3325           if (sym->stack)
3326             {
3327               emitcode ("push", "_bp");     /* save the callers stack  */
3328               emitcode ("mov", "_bp,sp");
3329             }
3330         }
3331       else
3332         {
3333           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3334             {
3335               /* set up the stack */
3336               emitcode ("push", "_bp");     /* save the callers stack  */
3337               emitcode ("mov", "_bp,sp");
3338             }
3339         }
3340     }
3341
3342   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3343   /* before setting up the stack frame completely. */
3344   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3345     {
3346       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3347
3348       if (rsym->isitmp)
3349         {
3350           if (rsym && rsym->regType == REG_CND)
3351             rsym = NULL;
3352           if (rsym && (rsym->accuse || rsym->ruonly))
3353             rsym = NULL;
3354           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3355             rsym = rsym->usl.spillLoc;
3356         }
3357
3358       /* If the RECEIVE operand immediately spills to the first entry on the */
3359       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3360       /* rather than the usual @r0/r1 machinations. */
3361       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3362         {
3363           int ofs;
3364
3365           _G.current_iCode = ric;
3366           D(emitcode (";     genReceive",""));
3367           for (ofs=0; ofs < sym->recvSize; ofs++)
3368             {
3369               if (!strcmp (fReturn[ofs], "a"))
3370                 emitcode ("push", "acc");
3371               else
3372                 emitcode ("push", fReturn[ofs]);
3373             }
3374           stackAdjust -= sym->recvSize;
3375           if (stackAdjust<0)
3376             {
3377               assert (stackAdjust>=0);
3378               stackAdjust = 0;
3379             }
3380           _G.current_iCode = ic;
3381           ric->generated = 1;
3382           accIsFree = 1;
3383         }
3384       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3385       /* to free up the accumulator. */
3386       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3387         {
3388           int ofs;
3389
3390           _G.current_iCode = ric;
3391           D(emitcode (";     genReceive",""));
3392           for (ofs=0; ofs < sym->recvSize; ofs++)
3393             {
3394               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3395             }
3396           _G.current_iCode = ic;
3397           ric->generated = 1;
3398           accIsFree = 1;
3399         }
3400     }
3401
3402   /* adjust the stack for the function */
3403   if (stackAdjust)
3404     {
3405       int i = stackAdjust;
3406       if (i > 256)
3407         werror (W_STACK_OVERFLOW, sym->name);
3408
3409       if (i > 3 && accIsFree)
3410         {
3411           emitcode ("mov", "a,sp");
3412           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3413           emitcode ("mov", "sp,a");
3414         }
3415       else if (i > 5)
3416         {
3417           /* The accumulator is not free, so we will need another register */
3418           /* to clobber. No need to worry about a possible conflict with */
3419           /* the above early RECEIVE optimizations since they would have */
3420           /* freed the accumulator if they were generated. */
3421
3422           if (IFFUNC_CALLEESAVES(sym->type))
3423             {
3424               /* if it's a callee-saves function we need a saved register */
3425               if (calleesaves_saved_register >= 0)
3426                 {
3427                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3428                   emitcode ("mov", "a,sp");
3429                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3430                   emitcode ("mov", "sp,a");
3431                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3432                 }
3433               else
3434                 /* do it the hard way */
3435                 while (i--)
3436                   emitcode ("inc", "sp");
3437             }
3438           else
3439             {
3440               /* not callee-saves, we can clobber r0 */
3441               emitcode ("mov", "r0,a");
3442               emitcode ("mov", "a,sp");
3443               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3444               emitcode ("mov", "sp,a");
3445               emitcode ("mov", "a,r0");
3446             }
3447         }
3448       else
3449         while (i--)
3450           emitcode ("inc", "sp");
3451     }
3452
3453   if (sym->xstack)
3454     {
3455       char i = ((char) sym->xstack & 0xff);
3456
3457       if (i > 3 && accIsFree)
3458         {
3459           emitcode ("mov", "a,_spx");
3460           emitcode ("add", "a,#0x%02x", i);
3461           emitcode ("mov", "_spx,a");
3462         }
3463       else if (i > 5)
3464         {
3465           emitcode ("push", "acc");
3466           emitcode ("mov", "a,_spx");
3467           emitcode ("add", "a,#0x%02x", i);
3468           emitcode ("mov", "_spx,a");
3469           emitcode ("pop", "acc");
3470         }
3471       else
3472         {
3473           while (i--)
3474             emitcode ("inc", "_spx");
3475         }
3476     }
3477
3478   /* if critical function then turn interrupts off */
3479   if (IFFUNC_ISCRITICAL (ftype))
3480     {
3481       symbol *tlbl = newiTempLabel (NULL);
3482       emitcode ("setb", "c");
3483       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3484       emitcode ("clr", "c");
3485       emitcode ("", "%05d$:", (tlbl->key + 100));
3486       emitcode ("push", "psw"); /* save old ea via c in psw */
3487     }
3488 }
3489
3490 /*-----------------------------------------------------------------*/
3491 /* genEndFunction - generates epilogue for functions               */
3492 /*-----------------------------------------------------------------*/
3493 static void
3494 genEndFunction (iCode * ic)
3495 {
3496   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3497   lineNode *lnp = lineCurr;
3498   bitVect  *regsUsed;
3499   bitVect  *regsUsedPrologue;
3500   bitVect  *regsUnneeded;
3501   int      idx;
3502
3503   _G.currentFunc = NULL;
3504   if (IFFUNC_ISNAKED(sym->type))
3505   {
3506       emitcode(";", "naked function: no epilogue.");
3507       if (options.debug && currFunc)
3508         debugFile->writeEndFunction (currFunc, ic, 0);
3509       return;
3510   }
3511
3512   if (IFFUNC_ISCRITICAL (sym->type))
3513     {
3514       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3515         {
3516           emitcode ("rlc", "a");   /* save c in a */
3517           emitcode ("pop", "psw"); /* restore ea via c in psw */
3518           emitcode ("mov", "ea,c");
3519           emitcode ("rrc", "a");   /* restore c from a */
3520         }
3521       else
3522         {
3523           emitcode ("pop", "psw"); /* restore ea via c in psw */
3524           emitcode ("mov", "ea,c");
3525         }
3526     }
3527
3528   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3529     {
3530       if (options.useXstack)
3531         {
3532           if (sym->stack)
3533             {
3534               emitcode ("mov", "sp,_bp");
3535               emitcode ("pop", "_bp");
3536             }
3537           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3538             {
3539               emitcode ("xch", "a,_bpx");
3540               emitcode ("mov", "r0,a");
3541               emitcode ("dec", "r0");
3542               emitcode ("movx", "a,@r0");
3543               emitcode ("xch", "a,_bpx");
3544               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3545             }
3546         }
3547       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3548         {
3549           emitcode ("mov", "sp,_bp");
3550           emitcode ("pop", "_bp");
3551         }
3552     }
3553
3554   /* restore the register bank  */
3555   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3556   {
3557     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3558      || !options.useXstack)
3559     {
3560         /* Special case of ISR using non-zero bank with useXstack
3561          * is handled below.
3562          */
3563         emitcode ("pop", "psw");
3564     }
3565   }
3566
3567   if (IFFUNC_ISISR (sym->type))
3568     {
3569
3570       /* now we need to restore the registers */
3571       /* if this isr has no bank i.e. is going to
3572          run with bank 0 , then we need to save more
3573          registers :-) */
3574       if (!FUNC_REGBANK (sym->type))
3575         {
3576           /* if this function does not call any other
3577              function then we can be economical and
3578              save only those registers that are used */
3579           if (!IFFUNC_HASFCALL(sym->type))
3580             {
3581               int i;
3582
3583               /* if any registers used */
3584               if (sym->regsUsed)
3585                 {
3586                   bool bits_popped = FALSE;
3587                   /* save the registers used */
3588                   for (i = sym->regsUsed->size; i >= 0; i--)
3589                     {
3590                       if (bitVectBitValue (sym->regsUsed, i))
3591                         bits_popped = popReg (i, bits_popped);
3592                     }
3593                 }
3594             }
3595           else
3596             {
3597               if (options.parms_in_bank1) {
3598                   int i;
3599                   for (i = 7 ; i >= 0 ; i-- ) {
3600                       emitcode ("pop","%s",rb1regs[i]);
3601                   }
3602               }
3603               /* this function has  a function call cannot
3604                  determines register usage so we will have to pop the
3605                  entire bank */
3606               unsaveRBank (0, ic, FALSE);
3607             }
3608         }
3609         else
3610         {
3611             /* This ISR uses a non-zero bank.
3612              *
3613              * Restore any register banks saved by genFunction
3614              * in reverse order.
3615              */
3616             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3617             int ix;
3618
3619             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3620             {
3621                 if (savedBanks & (1 << ix))
3622                 {
3623                     unsaveRBank(ix, NULL, FALSE);
3624                 }
3625             }
3626
3627             if (options.useXstack)
3628             {
3629                 /* Restore bank AFTER calling unsaveRBank,
3630                  * since it can trash r0.
3631                  */
3632                 emitcode ("pop", "psw");
3633             }
3634         }
3635
3636       if (!inExcludeList ("dph"))
3637         emitcode ("pop", "dph");
3638       if (!inExcludeList ("dpl"))
3639         emitcode ("pop", "dpl");
3640       if (!inExcludeList ("b"))
3641         emitcode ("pop", "b");
3642       if (!inExcludeList ("acc"))
3643         emitcode ("pop", "acc");
3644
3645       /* if debug then send end of function */
3646       if (options.debug && currFunc)
3647         {
3648           debugFile->writeEndFunction (currFunc, ic, 1);
3649         }
3650
3651       emitcode ("reti", "");
3652     }
3653   else
3654     {
3655       if (IFFUNC_CALLEESAVES(sym->type))
3656         {
3657           int i;
3658
3659           /* if any registers used */
3660           if (sym->regsUsed)
3661             {
3662               /* save the registers used */
3663               for (i = sym->regsUsed->size; i >= 0; i--)
3664                 {
3665                   if (bitVectBitValue (sym->regsUsed, i) ||
3666                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3667                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3668                 }
3669             }
3670           else if (mcs51_ptrRegReq)
3671             {
3672               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3673               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3674             }
3675
3676         }
3677
3678       /* if debug then send end of function */
3679       if (options.debug && currFunc)
3680         {
3681           debugFile->writeEndFunction (currFunc, ic, 1);
3682         }
3683
3684       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3685         {
3686           emitcode ("ljmp", "__sdcc_banked_ret");
3687         }
3688       else
3689         {
3690           emitcode ("ret", "");
3691         }
3692     }
3693
3694   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3695     return;
3696
3697   /* If this was an interrupt handler using bank 0 that called another */
3698   /* function, then all registers must be saved; nothing to optimized. */
3699   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3700       && !FUNC_REGBANK(sym->type))
3701     return;
3702
3703   /* There are no push/pops to optimize if not callee-saves or ISR */
3704   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3705     return;
3706
3707   /* If there were stack parameters, we cannot optimize without also    */
3708   /* fixing all of the stack offsets; this is too dificult to consider. */
3709   if (FUNC_HASSTACKPARM(sym->type))
3710     return;
3711
3712   /* Compute the registers actually used */
3713   regsUsed = newBitVect (mcs51_nRegs);
3714   regsUsedPrologue = newBitVect (mcs51_nRegs);
3715   while (lnp)
3716     {
3717       if (lnp->ic && lnp->ic->op == FUNCTION)
3718         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3719       else
3720         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3721
3722       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3723           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3724         break;
3725       if (!lnp->prev)
3726         break;
3727       lnp = lnp->prev;
3728     }
3729
3730   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3731       && !bitVectBitValue (regsUsed, CND_IDX))
3732     {
3733       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3734       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3735           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3736         bitVectUnSetBit (regsUsed, CND_IDX);
3737     }
3738   else
3739     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3740
3741   /* If this was an interrupt handler that called another function */
3742   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3743   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3744     {
3745       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3746       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3747       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3748       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3749       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3750     }
3751
3752   /* Remove the unneeded push/pops */
3753   regsUnneeded = newBitVect (mcs51_nRegs);
3754   while (lnp)
3755     {
3756       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3757         {
3758           if (!strncmp(lnp->line, "push", 4))
3759             {
3760               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3761               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3762                 {
3763                   connectLine (lnp->prev, lnp->next);
3764                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3765                 }
3766             }
3767           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3768             {
3769               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3770               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3771                 {
3772                   connectLine (lnp->prev, lnp->next);
3773                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3774                 }
3775             }
3776         }
3777       lnp = lnp->next;
3778     }
3779
3780   for (idx = 0; idx < regsUnneeded->size; idx++)
3781     if (bitVectBitValue (regsUnneeded, idx))
3782       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3783
3784   freeBitVect (regsUnneeded);
3785   freeBitVect (regsUsed);
3786   freeBitVect (regsUsedPrologue);
3787 }
3788
3789 /*-----------------------------------------------------------------*/
3790 /* genRet - generate code for return statement                     */
3791 /*-----------------------------------------------------------------*/
3792 static void
3793 genRet (iCode * ic)
3794 {
3795   int size, offset = 0, pushed = 0;
3796
3797   D(emitcode (";     genRet",""));
3798
3799   /* if we have no return value then
3800      just generate the "ret" */
3801   if (!IC_LEFT (ic))
3802     goto jumpret;
3803
3804   /* we have something to return then
3805      move the return value into place */
3806   aopOp (IC_LEFT (ic), ic, FALSE);
3807   size = AOP_SIZE (IC_LEFT (ic));
3808
3809
3810   if (IS_BIT(_G.currentFunc->etype))
3811     {
3812       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3813       size = 0;
3814     }
3815
3816   while (size--)
3817     {
3818       char *l;
3819       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3820         {
3821           /* #NOCHANGE */
3822           l = aopGet (IC_LEFT (ic), offset++,
3823                       FALSE, TRUE);
3824           emitcode ("push", "%s", l);
3825           pushed++;
3826         }
3827       else
3828         {
3829           l = aopGet (IC_LEFT (ic), offset,
3830                       FALSE, FALSE);
3831           if (strcmp (fReturn[offset], l))
3832             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3833         }
3834     }
3835
3836   while (pushed)
3837     {
3838       pushed--;
3839       if (strcmp (fReturn[pushed], "a"))
3840         emitcode ("pop", fReturn[pushed]);
3841       else
3842         emitcode ("pop", "acc");
3843     }
3844   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3845
3846 jumpret:
3847   /* generate a jump to the return label
3848      if the next is not the return statement */
3849   if (!(ic->next && ic->next->op == LABEL &&
3850         IC_LABEL (ic->next) == returnLabel))
3851
3852     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3853
3854 }
3855
3856 /*-----------------------------------------------------------------*/
3857 /* genLabel - generates a label                                    */
3858 /*-----------------------------------------------------------------*/
3859 static void
3860 genLabel (iCode * ic)
3861 {
3862   /* special case never generate */
3863   if (IC_LABEL (ic) == entryLabel)
3864     return;
3865
3866   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3867 }
3868
3869 /*-----------------------------------------------------------------*/
3870 /* genGoto - generates a ljmp                                      */
3871 /*-----------------------------------------------------------------*/
3872 static void
3873 genGoto (iCode * ic)
3874 {
3875   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3876 }
3877
3878 /*-----------------------------------------------------------------*/
3879 /* findLabelBackwards: walks back through the iCode chain looking  */
3880 /* for the given label. Returns number of iCode instructions     */
3881 /* between that label and given ic.          */
3882 /* Returns zero if label not found.          */
3883 /*-----------------------------------------------------------------*/
3884 static int
3885 findLabelBackwards (iCode * ic, int key)
3886 {
3887   int count = 0;
3888
3889   while (ic->prev)
3890     {
3891       ic = ic->prev;
3892       count++;
3893
3894       /* If we have any pushes or pops, we cannot predict the distance.
3895          I don't like this at all, this should be dealt with in the
3896          back-end */
3897       if (ic->op == IPUSH || ic->op == IPOP) {
3898         return 0;
3899       }
3900
3901       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3902         {
3903           return count;
3904         }
3905     }
3906
3907   return 0;
3908 }
3909
3910 /*-----------------------------------------------------------------*/
3911 /* genPlusIncr :- does addition with increment if possible         */
3912 /*-----------------------------------------------------------------*/
3913 static bool
3914 genPlusIncr (iCode * ic)
3915 {
3916   unsigned int icount;
3917   unsigned int size = getDataSize (IC_RESULT (ic));
3918
3919   /* will try to generate an increment */
3920   /* if the right side is not a literal
3921      we cannot */
3922   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3923     return FALSE;
3924
3925   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3926
3927   D(emitcode (";     genPlusIncr",""));
3928
3929   /* if increment >=16 bits in register or direct space */
3930   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3931       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3932       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
3933       (size > 1) &&
3934       (icount == 1))
3935     {
3936       symbol *tlbl;
3937       int emitTlbl;
3938       int labelRange;
3939
3940       /* If the next instruction is a goto and the goto target
3941        * is < 10 instructions previous to this, we can generate
3942        * jumps straight to that target.
3943        */
3944       if (ic->next && ic->next->op == GOTO
3945           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3946           && labelRange <= 10)
3947         {
3948           emitcode (";", "tail increment optimized");
3949           tlbl = IC_LABEL (ic->next);
3950           emitTlbl = 0;
3951         }
3952       else
3953         {
3954           tlbl = newiTempLabel (NULL);
3955           emitTlbl = 1;
3956         }
3957       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3958       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3959           IS_AOP_PREG (IC_RESULT (ic)))
3960         emitcode ("cjne", "%s,#0x00,%05d$",
3961                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3962                   tlbl->key + 100);
3963       else
3964         {
3965           emitcode ("clr", "a");
3966           emitcode ("cjne", "a,%s,%05d$",
3967                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3968                     tlbl->key + 100);
3969         }
3970
3971       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
3972       if (size > 2)
3973         {
3974           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3975               IS_AOP_PREG (IC_RESULT (ic)))
3976             emitcode ("cjne", "%s,#0x00,%05d$",
3977                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3978                       tlbl->key + 100);
3979           else
3980             emitcode ("cjne", "a,%s,%05d$",
3981                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
3982                       tlbl->key + 100);
3983
3984           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
3985         }
3986       if (size > 3)
3987         {
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), MSB24, FALSE, FALSE),
3992                       tlbl->key + 100);
3993           else
3994             {
3995               emitcode ("cjne", "a,%s,%05d$",
3996                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
3997                         tlbl->key + 100);
3998             }
3999           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4000         }
4001
4002       if (emitTlbl)
4003         {
4004           emitcode ("", "%05d$:", tlbl->key + 100);
4005         }
4006       return TRUE;
4007     }
4008
4009   /* if result is dptr */
4010   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4011       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4012       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4013       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4014     {
4015       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4016         return FALSE;
4017
4018       if (icount > 9)
4019         return FALSE;
4020
4021       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4022         return FALSE;
4023
4024       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
4025       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
4026       while (icount--)
4027         emitcode ("inc", "dptr");
4028
4029       return TRUE;
4030     }
4031
4032   /* if the literal value of the right hand side
4033      is greater than 4 then it is not worth it */
4034   if (icount > 4)
4035     return FALSE;
4036
4037   /* if the sizes are greater than 1 then we cannot */
4038   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4039       AOP_SIZE (IC_LEFT (ic)) > 1)
4040     return FALSE;
4041
4042   /* we can if the aops of the left & result match or
4043      if they are in registers and the registers are the
4044      same */
4045   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4046     {
4047
4048       if (icount > 3)
4049         {
4050           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4051           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4052           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4053         }
4054       else
4055         {
4056
4057           while (icount--)
4058             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4059         }
4060
4061       return TRUE;
4062     }
4063
4064   return FALSE;
4065 }
4066
4067 /*-----------------------------------------------------------------*/
4068 /* outBitAcc - output a bit in acc                                 */
4069 /*-----------------------------------------------------------------*/
4070 static void
4071 outBitAcc (operand * result)
4072 {
4073   symbol *tlbl = newiTempLabel (NULL);
4074   /* if the result is a bit */
4075   if (AOP_TYPE (result) == AOP_CRY)
4076     {
4077       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4078     }
4079   else
4080     {
4081       emitcode ("jz", "%05d$", tlbl->key + 100);
4082       emitcode ("mov", "a,%s", one);
4083       emitcode ("", "%05d$:", tlbl->key + 100);
4084       outAcc (result);
4085     }
4086 }
4087
4088 /*-----------------------------------------------------------------*/
4089 /* genPlusBits - generates code for addition of two bits           */
4090 /*-----------------------------------------------------------------*/
4091 static void
4092 genPlusBits (iCode * ic)
4093 {
4094   D(emitcode (";     genPlusBits",""));
4095
4096   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4097     {
4098       symbol *lbl = newiTempLabel (NULL);
4099       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4100       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4101       emitcode ("cpl", "c");
4102       emitcode ("", "%05d$:", (lbl->key + 100));
4103       outBitC (IC_RESULT (ic));
4104     }
4105   else
4106     {
4107       emitcode ("clr", "a");
4108       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4109       emitcode ("rlc", "a");
4110       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4111       emitcode ("addc", "a,#0x00");
4112       outAcc (IC_RESULT (ic));
4113     }
4114 }
4115
4116 #if 0
4117 /* This is the original version of this code.
4118
4119  * This is being kept around for reference,
4120  * because I am not entirely sure I got it right...
4121  */
4122 static void
4123 adjustArithmeticResult (iCode * ic)
4124 {
4125   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4126       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4127       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4128     aopPut (IC_RESULT (ic),
4129             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4130             2,
4131             isOperandVolatile (IC_RESULT (ic), FALSE));
4132
4133   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4134       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4135       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4136     aopPut (IC_RESULT (ic),
4137             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4138             2,
4139             isOperandVolatile (IC_RESULT (ic), FALSE));
4140
4141   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4142       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4143       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4144       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4145       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4146     {
4147       char buffer[5];
4148       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4149       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
4150     }
4151 }
4152 #else
4153 /* This is the pure and virtuous version of this code.
4154  * I'm pretty certain it's right, but not enough to toss the old
4155  * code just yet...
4156  */
4157 static void
4158 adjustArithmeticResult (iCode * ic)
4159 {
4160   if (opIsGptr (IC_RESULT (ic)) &&
4161       opIsGptr (IC_LEFT (ic)) &&
4162       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4163     {
4164       aopPut (IC_RESULT (ic),
4165               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4166               GPTRSIZE - 1,
4167               isOperandVolatile (IC_RESULT (ic), FALSE));
4168     }
4169
4170   if (opIsGptr (IC_RESULT (ic)) &&
4171       opIsGptr (IC_RIGHT (ic)) &&
4172       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4173     {
4174       aopPut (IC_RESULT (ic),
4175               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4176               GPTRSIZE - 1,
4177               isOperandVolatile (IC_RESULT (ic), FALSE));
4178     }
4179
4180   if (opIsGptr (IC_RESULT (ic)) &&
4181       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4182       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4183       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4184       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4185     {
4186       char buffer[5];
4187       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4188       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4189     }
4190 }
4191 #endif
4192
4193 /*-----------------------------------------------------------------*/
4194 /* genPlus - generates code for addition                           */
4195 /*-----------------------------------------------------------------*/
4196 static void
4197 genPlus (iCode * ic)
4198 {
4199   int size, offset = 0;
4200   int skip_bytes = 0;
4201   char *add = "add";
4202   operand *leftOp, *rightOp;
4203   operand * op;
4204
4205   /* special cases :- */
4206
4207   D(emitcode (";     genPlus",""));
4208
4209   aopOp (IC_LEFT (ic), ic, FALSE);
4210   aopOp (IC_RIGHT (ic), ic, FALSE);
4211   aopOp (IC_RESULT (ic), ic, TRUE);
4212
4213   /* if literal, literal on the right or
4214      if left requires ACC or right is already
4215      in ACC */
4216   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4217       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4218       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4219     {
4220       operand *t = IC_RIGHT (ic);
4221       IC_RIGHT (ic) = IC_LEFT (ic);
4222       IC_LEFT (ic) = t;
4223     }
4224
4225   /* if both left & right are in bit
4226      space */
4227   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4228       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4229     {
4230       genPlusBits (ic);
4231       goto release;
4232     }
4233
4234   /* if left in bit space & right literal */
4235   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4236       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4237     {
4238       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4239       /* if result in bit space */
4240       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4241         {
4242           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4243             emitcode ("cpl", "c");
4244           outBitC (IC_RESULT (ic));
4245         }
4246       else
4247         {
4248           size = getDataSize (IC_RESULT (ic));
4249           while (size--)
4250             {
4251               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4252               emitcode ("addc", "a,#00");
4253               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4254             }
4255         }
4256       goto release;
4257     }
4258
4259   /* if I can do an increment instead
4260      of add then GOOD for ME */
4261   if (genPlusIncr (ic) == TRUE)
4262     goto release;
4263
4264   size = getDataSize (IC_RESULT (ic));
4265   leftOp = IC_LEFT(ic);
4266   rightOp = IC_RIGHT(ic);
4267   op=IC_LEFT(ic);
4268
4269   /* if this is an add for an array access
4270      at a 256 byte boundary */
4271   if ( 2 == size
4272        && AOP_TYPE (op) == AOP_IMMD
4273        && IS_SYMOP (op)
4274        && IS_SPEC (OP_SYM_ETYPE (op))
4275        && SPEC_ABSA (OP_SYM_ETYPE (op))
4276        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4277      )
4278     {
4279       D(emitcode (";     genPlus aligned array",""));
4280       aopPut (IC_RESULT (ic),
4281               aopGet (rightOp, 0, FALSE, FALSE),
4282               0,
4283               isOperandVolatile (IC_RESULT (ic), FALSE));
4284
4285       if( 1 == getDataSize (IC_RIGHT (ic)) )
4286         {
4287           aopPut (IC_RESULT (ic),
4288                   aopGet (leftOp, 1, FALSE, FALSE),
4289                   1,
4290                   isOperandVolatile (IC_RESULT (ic), FALSE));
4291         }
4292       else
4293         {
4294           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4295           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4296           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4297         }
4298       goto release;
4299     }
4300
4301   /* if the lower bytes of a literal are zero skip the addition */
4302   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4303     {
4304        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4305               (skip_bytes+1 < size))
4306          {
4307            skip_bytes++;
4308          }
4309        if (skip_bytes)
4310          D(emitcode (";     genPlus shortcut",""));
4311     }
4312
4313   while (size--)
4314     {
4315       if( offset >= skip_bytes )
4316         {
4317           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4318             {
4319               bool pushedB;
4320               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4321               pushedB = pushB ();
4322               emitcode("xch", "a,b");
4323               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4324               emitcode (add, "a,b");
4325               popB (pushedB);
4326             }
4327           else if (aopGetUsesAcc (leftOp, offset))
4328             {
4329               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4330               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4331             }
4332           else
4333             {
4334               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4335               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4336             }
4337           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4338           add = "addc";  /* further adds must propagate carry */
4339         }
4340       else
4341         {
4342           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4343               isOperandVolatile (IC_RESULT (ic), FALSE))
4344             {
4345               /* just move */
4346               aopPut (IC_RESULT (ic),
4347                       aopGet (leftOp, offset, FALSE, FALSE),
4348                       offset,
4349                       isOperandVolatile (IC_RESULT (ic), FALSE));
4350             }
4351         }
4352       offset++;
4353     }
4354
4355   adjustArithmeticResult (ic);
4356
4357 release:
4358   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4359   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4360   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4361 }
4362
4363 /*-----------------------------------------------------------------*/
4364 /* genMinusDec :- does subtraction with decrement if possible      */
4365 /*-----------------------------------------------------------------*/
4366 static bool
4367 genMinusDec (iCode * ic)
4368 {
4369   unsigned int icount;
4370   unsigned int size = getDataSize (IC_RESULT (ic));
4371
4372   /* will try to generate an increment */
4373   /* if the right side is not a literal
4374      we cannot */
4375   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4376     return FALSE;
4377
4378   /* if the literal value of the right hand side
4379      is greater than 4 then it is not worth it */
4380   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4381     return FALSE;
4382
4383   D(emitcode (";     genMinusDec",""));
4384
4385   /* if decrement >=16 bits in register or direct space */
4386   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
4387       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4388       (size > 1) &&
4389       (icount == 1))
4390     {
4391       symbol *tlbl;
4392       int emitTlbl;
4393       int labelRange;
4394
4395       /* If the next instruction is a goto and the goto target
4396        * is <= 10 instructions previous to this, we can generate
4397        * jumps straight to that target.
4398        */
4399       if (ic->next && ic->next->op == GOTO
4400           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4401           && labelRange <= 10)
4402         {
4403           emitcode (";", "tail decrement optimized");
4404           tlbl = IC_LABEL (ic->next);
4405           emitTlbl = 0;
4406         }
4407       else
4408         {
4409           tlbl = newiTempLabel (NULL);
4410           emitTlbl = 1;
4411         }
4412
4413       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4414       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4415           IS_AOP_PREG (IC_RESULT (ic)))
4416         emitcode ("cjne", "%s,#0xff,%05d$"
4417                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4418                   ,tlbl->key + 100);
4419       else
4420         {
4421           emitcode ("mov", "a,#0xff");
4422           emitcode ("cjne", "a,%s,%05d$"
4423                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4424                     ,tlbl->key + 100);
4425         }
4426       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4427       if (size > 2)
4428         {
4429           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4430               IS_AOP_PREG (IC_RESULT (ic)))
4431             emitcode ("cjne", "%s,#0xff,%05d$"
4432                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4433                       ,tlbl->key + 100);
4434           else
4435             {
4436               emitcode ("cjne", "a,%s,%05d$"
4437                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4438                         ,tlbl->key + 100);
4439             }
4440           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4441         }
4442       if (size > 3)
4443         {
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), MSB24, FALSE, FALSE)
4448                       ,tlbl->key + 100);
4449           else
4450             {
4451               emitcode ("cjne", "a,%s,%05d$"
4452                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4453                         ,tlbl->key + 100);
4454             }
4455           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4456         }
4457       if (emitTlbl)
4458         {
4459           emitcode ("", "%05d$:", tlbl->key + 100);
4460         }
4461       return TRUE;
4462     }
4463
4464   /* if the sizes are greater than 1 then we cannot */
4465   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4466       AOP_SIZE (IC_LEFT (ic)) > 1)
4467     return FALSE;
4468
4469   /* we can if the aops of the left & result match or
4470      if they are in registers and the registers are the
4471      same */
4472   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4473     {
4474
4475       while (icount--)
4476         emitcode ("dec", "%s", aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4477
4478       if (AOP_NEEDSACC (IC_RESULT (ic)))
4479         aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4480
4481       return TRUE;
4482     }
4483
4484   return FALSE;
4485 }
4486
4487 /*-----------------------------------------------------------------*/
4488 /* addSign - complete with sign                                    */
4489 /*-----------------------------------------------------------------*/
4490 static void
4491 addSign (operand * result, int offset, int sign)
4492 {
4493   int size = (getDataSize (result) - offset);
4494   if (size > 0)
4495     {
4496       if (sign)
4497         {
4498           emitcode ("rlc", "a");
4499           emitcode ("subb", "a,acc");
4500           while (size--)
4501             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4502         }
4503       else
4504         while (size--)
4505           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4506     }
4507 }
4508
4509 /*-----------------------------------------------------------------*/
4510 /* genMinusBits - generates code for subtraction  of two bits      */
4511 /*-----------------------------------------------------------------*/
4512 static void
4513 genMinusBits (iCode * ic)
4514 {
4515   symbol *lbl = newiTempLabel (NULL);
4516
4517   D(emitcode (";     genMinusBits",""));
4518
4519   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4520     {
4521       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4522       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4523       emitcode ("cpl", "c");
4524       emitcode ("", "%05d$:", (lbl->key + 100));
4525       outBitC (IC_RESULT (ic));
4526     }
4527   else
4528     {
4529       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4530       emitcode ("subb", "a,acc");
4531       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4532       emitcode ("inc", "a");
4533       emitcode ("", "%05d$:", (lbl->key + 100));
4534       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4535       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4536     }
4537 }
4538
4539 /*-----------------------------------------------------------------*/
4540 /* genMinus - generates code for subtraction                       */
4541 /*-----------------------------------------------------------------*/
4542 static void
4543 genMinus (iCode * ic)
4544 {
4545   int size, offset = 0;
4546
4547   D(emitcode (";     genMinus",""));
4548
4549   aopOp (IC_LEFT (ic), ic, FALSE);
4550   aopOp (IC_RIGHT (ic), ic, FALSE);
4551   aopOp (IC_RESULT (ic), ic, TRUE);
4552
4553   /* special cases :- */
4554   /* if both left & right are in bit space */
4555   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4556       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4557     {
4558       genMinusBits (ic);
4559       goto release;
4560     }
4561
4562   /* if I can do an decrement instead
4563      of subtract then GOOD for ME */
4564   if (genMinusDec (ic) == TRUE)
4565     goto release;
4566
4567   size = getDataSize (IC_RESULT (ic));
4568
4569   /* if literal, add a,#-lit, else normal subb */
4570   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4571     {
4572       unsigned long lit = 0L;
4573       bool useCarry = FALSE;
4574
4575       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4576       lit = -(long) lit;
4577
4578       while (size--)
4579         {
4580           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4581             {
4582             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4583               if (!offset && !size && lit== (unsigned long) -1)
4584                 {
4585                   emitcode ("dec", "a");
4586                 }
4587               else if (!useCarry)
4588                 {
4589                   /* first add without previous c */
4590                   emitcode ("add", "a,#0x%02x",
4591                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4592                   useCarry = TRUE;
4593                 }
4594               else
4595                 {
4596                   emitcode ("addc", "a,#0x%02x",
4597                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4598                 }
4599               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4600             }
4601           else
4602             {
4603               /* no need to add zeroes */
4604               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4605                 {
4606                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4607                           offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4608                 }
4609               offset++;
4610             }
4611         }
4612     }
4613   else
4614     {
4615       operand *leftOp, *rightOp;
4616
4617       leftOp = IC_LEFT(ic);
4618       rightOp = IC_RIGHT(ic);
4619
4620       while (size--)
4621         {
4622           if (aopGetUsesAcc(rightOp, offset)) {
4623             if (aopGetUsesAcc(leftOp, offset)) {
4624               bool pushedB;
4625
4626               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4627               pushedB = pushB ();
4628               emitcode ("mov", "b,a");
4629               if (offset == 0)
4630                 CLRC;
4631               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4632               emitcode ("subb", "a,b");
4633               popB (pushedB);
4634             } else {
4635               /* reverse subtraction with 2's complement */
4636               if (offset == 0)
4637                 emitcode( "setb", "c");
4638                else
4639                 emitcode( "cpl", "c");
4640               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4641               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4642               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4643               emitcode("cpl", "a");
4644               if (size) /* skip if last byte */
4645                 emitcode( "cpl", "c");
4646             }
4647           } else {
4648             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4649             if (offset == 0)
4650               CLRC;
4651             emitcode ("subb", "a,%s",
4652                       aopGet(rightOp, offset, FALSE, TRUE));
4653           }
4654
4655           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4656         }
4657     }
4658
4659
4660   adjustArithmeticResult (ic);
4661
4662 release:
4663   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4664   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4665   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4666 }
4667
4668
4669 /*-----------------------------------------------------------------*/
4670 /* genMultbits :- multiplication of bits                           */
4671 /*-----------------------------------------------------------------*/
4672 static void
4673 genMultbits (operand * left,
4674              operand * right,
4675              operand * result)
4676 {
4677   D(emitcode (";     genMultbits",""));
4678
4679   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4680   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4681   outBitC (result);
4682 }
4683
4684 /*-----------------------------------------------------------------*/
4685 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4686 /*-----------------------------------------------------------------*/
4687 static void
4688 genMultOneByte (operand * left,
4689                 operand * right,
4690                 operand * result)
4691 {
4692   symbol *lbl;
4693   int size = AOP_SIZE (result);
4694   bool runtimeSign, compiletimeSign;
4695   bool lUnsigned, rUnsigned, pushedB;
4696
4697   D(emitcode (";     genMultOneByte",""));
4698
4699   if (size < 1 || size > 2)
4700     {
4701       /* this should never happen */
4702       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4703                AOP_SIZE(result), __FILE__, lineno);
4704       exit (1);
4705     }
4706
4707   /* (if two literals: the value is computed before) */
4708   /* if one literal, literal on the right */
4709   if (AOP_TYPE (left) == AOP_LIT)
4710     {
4711       operand *t = right;
4712       right = left;
4713       left = t;
4714       /* emitcode (";", "swapped left and right"); */
4715     }
4716   /* if no literal, unsigned on the right: shorter code */
4717   if (   AOP_TYPE (right) != AOP_LIT
4718       && SPEC_USIGN (getSpec (operandType (left))))
4719     {
4720       operand *t = right;
4721       right = left;
4722       left = t;
4723     }
4724
4725   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4726   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4727
4728   pushedB = pushB ();
4729
4730   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4731                    no need to take care about the signedness! */
4732       || (lUnsigned && rUnsigned))
4733     {
4734       /* just an unsigned 8 * 8 = 8 multiply
4735          or 8u * 8u = 16u */
4736       /* emitcode (";","unsigned"); */
4737       /* TODO: check for accumulator clash between left & right aops? */
4738
4739       if (AOP_TYPE (right) == AOP_LIT)
4740         {
4741           /* moving to accumulator first helps peepholes */
4742           MOVA (aopGet (left, 0, FALSE, FALSE));
4743           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4744         }
4745       else
4746         {
4747           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4748           MOVA (aopGet (left, 0, FALSE, FALSE));
4749         }
4750
4751       emitcode ("mul", "ab");
4752       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4753       if (size == 2)
4754         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4755
4756       popB (pushedB);
4757       return;
4758     }
4759
4760   /* we have to do a signed multiply */
4761   /* emitcode (";", "signed"); */
4762
4763   /* now sign adjust for both left & right */
4764
4765   /* let's see what's needed: */
4766   /* apply negative sign during runtime */
4767   runtimeSign = FALSE;
4768   /* negative sign from literals */
4769   compiletimeSign = FALSE;
4770
4771   if (!lUnsigned)
4772     {
4773       if (AOP_TYPE(left) == AOP_LIT)
4774         {
4775           /* signed literal */
4776           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4777           if (val < 0)
4778             compiletimeSign = TRUE;
4779         }
4780       else
4781         /* signed but not literal */
4782         runtimeSign = TRUE;
4783     }
4784
4785   if (!rUnsigned)
4786     {
4787       if (AOP_TYPE(right) == AOP_LIT)
4788         {
4789           /* signed literal */
4790           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4791           if (val < 0)
4792             compiletimeSign ^= TRUE;
4793         }
4794       else
4795         /* signed but not literal */
4796         runtimeSign = TRUE;
4797     }
4798
4799   /* initialize F0, which stores the runtime sign */
4800   if (runtimeSign)
4801     {
4802       if (compiletimeSign)
4803         emitcode ("setb", "F0"); /* set sign flag */
4804       else
4805         emitcode ("clr", "F0"); /* reset sign flag */
4806     }
4807
4808   /* save the signs of the operands */
4809   if (AOP_TYPE(right) == AOP_LIT)
4810     {
4811       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4812
4813       if (!rUnsigned && val < 0)
4814         emitcode ("mov", "b,#0x%02x", -val);
4815       else
4816         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4817     }
4818   else /* ! literal */
4819     {
4820       if (rUnsigned)  /* emitcode (";", "signed"); */
4821
4822         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4823       else
4824         {
4825           MOVA (aopGet (right, 0, FALSE, FALSE));
4826           lbl = newiTempLabel (NULL);
4827           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4828           emitcode ("cpl", "F0"); /* complement sign flag */
4829           emitcode ("cpl", "a");  /* 2's complement */
4830           emitcode ("inc", "a");
4831           emitcode ("", "%05d$:", (lbl->key + 100));
4832           emitcode ("mov", "b,a");
4833         }
4834     }
4835
4836   if (AOP_TYPE(left) == AOP_LIT)
4837     {
4838       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4839
4840       if (!lUnsigned && val < 0)
4841         emitcode ("mov", "a,#0x%02x", -val);
4842       else
4843         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4844     }
4845   else /* ! literal */
4846     {
4847       MOVA (aopGet (left, 0, FALSE, FALSE));
4848
4849       if (!lUnsigned)
4850         {
4851           lbl = newiTempLabel (NULL);
4852           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4853           emitcode ("cpl", "F0"); /* complement sign flag */
4854           emitcode ("cpl", "a"); /* 2's complement */
4855           emitcode ("inc", "a");
4856           emitcode ("", "%05d$:", (lbl->key + 100));
4857         }
4858     }
4859
4860   /* now the multiplication */
4861   emitcode ("mul", "ab");
4862   if (runtimeSign || compiletimeSign)
4863     {
4864       lbl = newiTempLabel (NULL);
4865       if (runtimeSign)
4866         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4867       emitcode ("cpl", "a"); /* lsb 2's complement */
4868       if (size != 2)
4869         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4870       else
4871         {
4872           emitcode ("add", "a,#1"); /* this sets carry flag */
4873           emitcode ("xch", "a,b");
4874           emitcode ("cpl", "a"); /* msb 2's complement */
4875           emitcode ("addc", "a,#0");
4876           emitcode ("xch", "a,b");
4877         }
4878       emitcode ("", "%05d$:", (lbl->key + 100));
4879     }
4880   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4881   if (size == 2)
4882     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4883
4884   popB (pushedB);
4885 }
4886
4887 /*-----------------------------------------------------------------*/
4888 /* genMult - generates code for multiplication                     */
4889 /*-----------------------------------------------------------------*/
4890 static void
4891 genMult (iCode * ic)
4892 {
4893   operand *left = IC_LEFT (ic);
4894   operand *right = IC_RIGHT (ic);
4895   operand *result = IC_RESULT (ic);
4896
4897   D(emitcode (";     genMult",""));
4898
4899   /* assign the asmops */
4900   aopOp (left, ic, FALSE);
4901   aopOp (right, ic, FALSE);
4902   aopOp (result, ic, TRUE);
4903
4904   /* special cases first */
4905   /* both are bits */
4906   if (AOP_TYPE (left) == AOP_CRY &&
4907       AOP_TYPE (right) == AOP_CRY)
4908     {
4909       genMultbits (left, right, result);
4910       goto release;
4911     }
4912
4913   /* if both are of size == 1 */
4914 #if 0 // one of them can be a sloc shared with the result
4915     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4916 #else
4917   if (getSize(operandType(left)) == 1 &&
4918       getSize(operandType(right)) == 1)
4919 #endif
4920     {
4921       genMultOneByte (left, right, result);
4922       goto release;
4923     }
4924
4925   /* should have been converted to function call */
4926     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4927              getSize(OP_SYMBOL(right)->type));
4928   assert (0);
4929
4930 release:
4931   freeAsmop (result, NULL, ic, TRUE);
4932   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4933   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4934 }
4935
4936 /*-----------------------------------------------------------------*/
4937 /* genDivbits :- division of bits                                  */
4938 /*-----------------------------------------------------------------*/
4939 static void
4940 genDivbits (operand * left,
4941             operand * right,
4942             operand * result)
4943 {
4944   char *l;
4945   bool pushedB;
4946
4947   D(emitcode (";     genDivbits",""));
4948
4949   pushedB = pushB ();
4950
4951   /* the result must be bit */
4952   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4953   l = aopGet (left, 0, FALSE, FALSE);
4954
4955   MOVA (l);
4956
4957   emitcode ("div", "ab");
4958   emitcode ("rrc", "a");
4959
4960   popB (pushedB);
4961
4962   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4963 }
4964
4965 /*-----------------------------------------------------------------*/
4966 /* genDivOneByte : 8 bit division                                  */
4967 /*-----------------------------------------------------------------*/
4968 static void
4969 genDivOneByte (operand * left,
4970                operand * right,
4971                operand * result)
4972 {
4973   bool lUnsigned, rUnsigned, pushedB;
4974   bool runtimeSign, compiletimeSign;
4975   bool accuse = FALSE;
4976   bool pushedA = FALSE;
4977   symbol *lbl;
4978   int size, offset;
4979
4980   D(emitcode (";     genDivOneByte",""));
4981
4982   /* Why is it necessary that genDivOneByte() can return an int result?
4983      Have a look at:
4984
4985         volatile unsigned char uc;
4986         volatile signed char sc1, sc2;
4987         volatile int i;
4988
4989         uc  = 255;
4990         sc1 = -1;
4991         i = uc / sc1;
4992
4993      Or:
4994
4995         sc1 = -128;
4996         sc2 = -1;
4997         i = sc1 / sc2;
4998
4999      In all cases a one byte result would overflow, the following cast to int
5000      would return the wrong result.
5001
5002      Two possible solution:
5003         a) cast operands to int, if ((unsigned) / (signed)) or
5004            ((signed) / (signed))
5005         b) return an 16 bit signed int; this is what we're doing here!
5006   */
5007
5008   size = AOP_SIZE (result) - 1;
5009   offset = 1;
5010   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5011   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5012
5013   pushedB = pushB ();
5014
5015   /* signed or unsigned */
5016   if (lUnsigned && rUnsigned)
5017     {
5018       /* unsigned is easy */
5019       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5020       MOVA (aopGet (left, 0, FALSE, FALSE));
5021       emitcode ("div", "ab");
5022       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5023       while (size--)
5024         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5025
5026       popB (pushedB);
5027       return;
5028     }
5029
5030   /* signed is a little bit more difficult */
5031
5032   /* now sign adjust for both left & right */
5033
5034   /* let's see what's needed: */
5035   /* apply negative sign during runtime */
5036   runtimeSign = FALSE;
5037   /* negative sign from literals */
5038   compiletimeSign = FALSE;
5039
5040   if (!lUnsigned)
5041     {
5042       if (AOP_TYPE(left) == AOP_LIT)
5043         {
5044           /* signed literal */
5045           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5046           if (val < 0)
5047             compiletimeSign = TRUE;
5048         }
5049       else
5050         /* signed but not literal */
5051         runtimeSign = TRUE;
5052     }
5053
5054   if (!rUnsigned)
5055     {
5056       if (AOP_TYPE(right) == AOP_LIT)
5057         {
5058           /* signed literal */
5059           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5060           if (val < 0)
5061             compiletimeSign ^= TRUE;
5062         }
5063       else
5064         /* signed but not literal */
5065         runtimeSign = TRUE;
5066     }
5067
5068   /* initialize F0, which stores the runtime sign */
5069   if (runtimeSign)
5070     {
5071       if (compiletimeSign)
5072         emitcode ("setb", "F0"); /* set sign flag */
5073       else
5074         emitcode ("clr", "F0"); /* reset sign flag */
5075     }
5076
5077   /* save the signs of the operands */
5078   if (AOP_TYPE(right) == AOP_LIT)
5079     {
5080       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5081
5082       if (!rUnsigned && val < 0)
5083         emitcode ("mov", "b,#0x%02x", -val);
5084       else
5085         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5086     }
5087   else /* ! literal */
5088     {
5089       if (rUnsigned)
5090         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5091       else
5092         {
5093           MOVA (aopGet (right, 0, FALSE, FALSE));
5094           lbl = newiTempLabel (NULL);
5095           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5096           emitcode ("cpl", "F0"); /* complement sign flag */
5097           emitcode ("cpl", "a");  /* 2's complement */
5098           emitcode ("inc", "a");
5099           emitcode ("", "%05d$:", (lbl->key + 100));
5100           emitcode ("mov", "b,a");
5101         }
5102     }
5103
5104   if (AOP_TYPE(left) == AOP_LIT)
5105     {
5106       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5107
5108       if (!lUnsigned && val < 0)
5109         emitcode ("mov", "a,#0x%02x", -val);
5110       else
5111         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5112     }
5113   else /* ! literal */
5114     {
5115       MOVA (aopGet (left, 0, FALSE, FALSE));
5116
5117       if (!lUnsigned)
5118         {
5119           lbl = newiTempLabel (NULL);
5120           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5121           emitcode ("cpl", "F0"); /* complement sign flag */
5122           emitcode ("cpl", "a");  /* 2's complement */
5123           emitcode ("inc", "a");
5124           emitcode ("", "%05d$:", (lbl->key + 100));
5125         }
5126     }
5127
5128   /* now the division */
5129   emitcode ("div", "ab");
5130
5131   if (runtimeSign || compiletimeSign)
5132     {
5133       lbl = newiTempLabel (NULL);
5134       if (runtimeSign)
5135         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5136       emitcode ("cpl", "a"); /* lsb 2's complement */
5137       emitcode ("inc", "a");
5138       emitcode ("", "%05d$:", (lbl->key + 100));
5139
5140       accuse = aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5141       if (size > 0)
5142         {
5143           /* msb is 0x00 or 0xff depending on the sign */
5144           if (runtimeSign)
5145             {
5146               if (accuse)
5147                 {
5148                   emitcode ("push", "acc");
5149                   pushedA = TRUE;
5150                 }
5151               emitcode ("mov", "c,F0");
5152               emitcode ("subb", "a,acc");
5153               while (size--)
5154                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5155             }
5156           else /* compiletimeSign */
5157             {
5158               if (aopPutUsesAcc (result, "#0xFF", offset))
5159                 {
5160                   emitcode ("push", "acc");
5161                   pushedA = TRUE;
5162                 }
5163               while (size--)
5164                 aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5165             }
5166         }
5167     }
5168   else
5169     {
5170       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5171       while (size--)
5172         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5173     }
5174
5175   if (pushedA)
5176     emitcode ("pop", "acc");
5177   popB (pushedB);
5178 }
5179
5180 /*-----------------------------------------------------------------*/
5181 /* genDiv - generates code for division                            */
5182 /*-----------------------------------------------------------------*/
5183 static void
5184 genDiv (iCode * ic)
5185 {
5186   operand *left = IC_LEFT (ic);
5187   operand *right = IC_RIGHT (ic);
5188   operand *result = IC_RESULT (ic);
5189
5190   D(emitcode (";     genDiv",""));
5191
5192   /* assign the amsops */
5193   aopOp (left, ic, FALSE);
5194   aopOp (right, ic, FALSE);
5195   aopOp (result, ic, TRUE);
5196
5197   /* special cases first */
5198   /* both are bits */
5199   if (AOP_TYPE (left) == AOP_CRY &&
5200       AOP_TYPE (right) == AOP_CRY)
5201     {
5202       genDivbits (left, right, result);
5203       goto release;
5204     }
5205
5206   /* if both are of size == 1 */
5207   if (AOP_SIZE (left) == 1 &&
5208       AOP_SIZE (right) == 1)
5209     {
5210       genDivOneByte (left, right, result);
5211       goto release;
5212     }
5213
5214   /* should have been converted to function call */
5215   assert (0);
5216 release:
5217   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5218   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5219   freeAsmop (result, NULL, ic, TRUE);
5220 }
5221
5222 /*-----------------------------------------------------------------*/
5223 /* genModbits :- modulus of bits                                   */
5224 /*-----------------------------------------------------------------*/
5225 static void
5226 genModbits (operand * left,
5227             operand * right,
5228             operand * result)
5229 {
5230   char *l;
5231   bool pushedB;
5232
5233   D(emitcode (";     genModbits",""));
5234
5235   pushedB = pushB ();
5236
5237   /* the result must be bit */
5238   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5239   l = aopGet (left, 0, FALSE, FALSE);
5240
5241   MOVA (l);
5242
5243   emitcode ("div", "ab");
5244   emitcode ("mov", "a,b");
5245   emitcode ("rrc", "a");
5246
5247   popB (pushedB);
5248
5249   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5250 }
5251
5252 /*-----------------------------------------------------------------*/
5253 /* genModOneByte : 8 bit modulus                                   */
5254 /*-----------------------------------------------------------------*/
5255 static void
5256 genModOneByte (operand * left,
5257                operand * right,
5258                operand * result)
5259 {
5260   bool lUnsigned, rUnsigned, pushedB;
5261   bool runtimeSign, compiletimeSign;
5262   symbol *lbl;
5263   int size, offset;
5264
5265   D(emitcode (";     genModOneByte",""));
5266
5267   size = AOP_SIZE (result) - 1;
5268   offset = 1;
5269   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5270   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5271
5272   /* if right is a literal, check it for 2^n */
5273   if (AOP_TYPE(right) == AOP_LIT)
5274     {
5275       unsigned char val = abs((int) operandLitValue(right));
5276       symbol *lbl2 = NULL;
5277
5278       switch (val)
5279         {
5280           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5281           case 2:
5282           case 4:
5283           case 8:
5284           case 16:
5285           case 32:
5286           case 64:
5287           case 128:
5288             if (lUnsigned)
5289               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5290                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5291               /* because iCode should have been changed to genAnd  */
5292               /* see file "SDCCopt.c", function "convertToFcall()" */
5293
5294             MOVA (aopGet (left, 0, FALSE, FALSE));
5295             emitcode ("mov", "c,acc.7");
5296             emitcode ("anl", "a,#0x%02x", val - 1);
5297             lbl = newiTempLabel (NULL);
5298             emitcode ("jz", "%05d$", (lbl->key + 100));
5299             emitcode ("jnc", "%05d$", (lbl->key + 100));
5300             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5301             if (size)
5302               {
5303                 int size2 = size;
5304                 int offs2 = offset;
5305
5306                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5307                 while (size2--)
5308                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
5309                 lbl2 = newiTempLabel (NULL);
5310                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5311               }
5312             emitcode ("", "%05d$:", (lbl->key + 100));
5313             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5314             while (size--)
5315               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5316             if (lbl2)
5317               {
5318                 emitcode ("", "%05d$:", (lbl2->key + 100));
5319               }
5320             return;
5321
5322           default:
5323             break;
5324         }
5325     }
5326
5327   pushedB = pushB ();
5328
5329   /* signed or unsigned */
5330   if (lUnsigned && rUnsigned)
5331     {
5332       /* unsigned is easy */
5333       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5334       MOVA (aopGet (left, 0, FALSE, FALSE));
5335       emitcode ("div", "ab");
5336       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5337       while (size--)
5338         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5339
5340       popB (pushedB);
5341       return;
5342     }
5343
5344   /* signed is a little bit more difficult */
5345
5346   /* now sign adjust for both left & right */
5347
5348   /* modulus: sign of the right operand has no influence on the result! */
5349   if (AOP_TYPE(right) == AOP_LIT)
5350     {
5351       signed char val = (char) operandLitValue(right);
5352
5353       if (!rUnsigned && val < 0)
5354         emitcode ("mov", "b,#0x%02x", -val);
5355       else
5356         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5357     }
5358   else /* not literal */
5359     {
5360       if (rUnsigned)
5361         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5362       else
5363         {
5364           MOVA (aopGet (right, 0, FALSE, FALSE));
5365           lbl = newiTempLabel (NULL);
5366           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5367           emitcode ("cpl", "a"); /* 2's complement */
5368           emitcode ("inc", "a");
5369           emitcode ("", "%05d$:", (lbl->key + 100));
5370           emitcode ("mov", "b,a");
5371         }
5372     }
5373
5374   /* let's see what's needed: */
5375   /* apply negative sign during runtime */
5376   runtimeSign = FALSE;
5377   /* negative sign from literals */
5378   compiletimeSign = FALSE;
5379
5380   /* sign adjust left side */
5381   if (AOP_TYPE(left) == AOP_LIT)
5382     {
5383       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5384
5385       if (!lUnsigned && val < 0)
5386         {
5387           compiletimeSign = TRUE; /* set sign flag */
5388           emitcode ("mov", "a,#0x%02x", -val);
5389         }
5390       else
5391         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5392     }
5393   else /* ! literal */
5394     {
5395       MOVA (aopGet (left, 0, FALSE, FALSE));
5396
5397       if (!lUnsigned)
5398         {
5399           runtimeSign = TRUE;
5400           emitcode ("clr", "F0"); /* clear sign flag */
5401
5402           lbl = newiTempLabel (NULL);
5403           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5404           emitcode ("setb", "F0"); /* set sign flag */
5405           emitcode ("cpl", "a");   /* 2's complement */
5406           emitcode ("inc", "a");
5407           emitcode ("", "%05d$:", (lbl->key + 100));
5408         }
5409     }
5410
5411   /* now the modulus */
5412   emitcode ("div", "ab");
5413
5414   if (runtimeSign || compiletimeSign)
5415     {
5416       emitcode ("mov", "a,b");
5417       lbl = newiTempLabel (NULL);
5418       if (runtimeSign)
5419         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5420       emitcode ("cpl", "a"); /* 2's complement */
5421       emitcode ("inc", "a");
5422       emitcode ("", "%05d$:", (lbl->key + 100));
5423
5424       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5425       if (size > 0)
5426         {
5427           /* msb is 0x00 or 0xff depending on the sign */
5428           if (runtimeSign)
5429             {
5430               emitcode ("mov", "c,F0");
5431               emitcode ("subb", "a,acc");
5432               while (size--)
5433                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5434             }
5435           else /* compiletimeSign */
5436             while (size--)
5437               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5438         }
5439     }
5440   else
5441     {
5442       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5443       while (size--)
5444         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5445     }
5446
5447   popB (pushedB);
5448 }
5449
5450 /*-----------------------------------------------------------------*/
5451 /* genMod - generates code for division                            */
5452 /*-----------------------------------------------------------------*/
5453 static void
5454 genMod (iCode * ic)
5455 {
5456   operand *left = IC_LEFT (ic);
5457   operand *right = IC_RIGHT (ic);
5458   operand *result = IC_RESULT (ic);
5459
5460   D(emitcode (";     genMod",""));
5461
5462   /* assign the asmops */
5463   aopOp (left, ic, FALSE);
5464   aopOp (right, ic, FALSE);
5465   aopOp (result, ic, TRUE);
5466
5467   /* special cases first */
5468   /* both are bits */
5469   if (AOP_TYPE (left) == AOP_CRY &&
5470       AOP_TYPE (right) == AOP_CRY)
5471     {
5472       genModbits (left, right, result);
5473       goto release;
5474     }
5475
5476   /* if both are of size == 1 */
5477   if (AOP_SIZE (left) == 1 &&
5478       AOP_SIZE (right) == 1)
5479     {
5480       genModOneByte (left, right, result);
5481       goto release;
5482     }
5483
5484   /* should have been converted to function call */
5485   assert (0);
5486
5487 release:
5488   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5489   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5490   freeAsmop (result, NULL, ic, TRUE);
5491 }
5492
5493 /*-----------------------------------------------------------------*/
5494 /* genIfxJump :- will create a jump depending on the ifx           */
5495 /*-----------------------------------------------------------------*/
5496 static void
5497 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5498 {
5499   symbol *jlbl;
5500   symbol *tlbl = newiTempLabel (NULL);
5501   char *inst;
5502
5503   D(emitcode (";     genIfxJump",""));
5504
5505   /* if true label then we jump if condition
5506      supplied is true */
5507   if (IC_TRUE (ic))
5508     {
5509       jlbl = IC_TRUE (ic);
5510       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5511                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5512     }
5513   else
5514     {
5515       /* false label is present */
5516       jlbl = IC_FALSE (ic);
5517       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5518                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5519     }
5520   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5521     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5522   else
5523     emitcode (inst, "%05d$", tlbl->key + 100);
5524   freeForBranchAsmop (result);
5525   freeForBranchAsmop (right);
5526   freeForBranchAsmop (left);
5527   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5528   emitcode ("", "%05d$:", tlbl->key + 100);
5529
5530   /* mark the icode as generated */
5531   ic->generated = 1;
5532 }
5533
5534 /*-----------------------------------------------------------------*/
5535 /* genCmp :- greater or less than comparison                       */
5536 /*-----------------------------------------------------------------*/
5537 static void
5538 genCmp (operand * left, operand * right,
5539         operand * result, iCode * ifx, int sign, iCode *ic)
5540 {
5541   int size, offset = 0;
5542   unsigned long lit = 0L;
5543   bool rightInB;
5544
5545   D(emitcode (";     genCmp",""));
5546
5547   /* if left & right are bit variables */
5548   if (AOP_TYPE (left) == AOP_CRY &&
5549       AOP_TYPE (right) == AOP_CRY)
5550     {
5551       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5552       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5553     }
5554   else
5555     {
5556       /* subtract right from left if at the
5557          end the carry flag is set then we know that
5558          left is greater than right */
5559       size = max (AOP_SIZE (left), AOP_SIZE (right));
5560
5561       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5562       if ((size == 1) && !sign &&
5563           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5564         {
5565           symbol *lbl = newiTempLabel (NULL);
5566           emitcode ("cjne", "%s,%s,%05d$",
5567                     aopGet (left, offset, FALSE, FALSE),
5568                     aopGet (right, offset, FALSE, FALSE),
5569                     lbl->key + 100);
5570           emitcode ("", "%05d$:", lbl->key + 100);
5571         }
5572       else
5573         {
5574           if (AOP_TYPE (right) == AOP_LIT)
5575             {
5576               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5577               /* optimize if(x < 0) or if(x >= 0) */
5578               if (lit == 0L)
5579                 {
5580                   if (!sign)
5581                     {
5582                       CLRC;
5583                     }
5584                   else
5585                     {
5586                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5587                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5588                         {
5589                           genIfxJump (ifx, "acc.7", left, right, result);
5590                           freeAsmop (right, NULL, ic, TRUE);
5591                           freeAsmop (left, NULL, ic, TRUE);
5592
5593                           return;
5594                         }
5595                       else
5596                         emitcode ("rlc", "a");
5597                     }
5598                   goto release;
5599                 }
5600             }
5601           CLRC;
5602           while (size--)
5603             {
5604               bool pushedB = FALSE;
5605               rightInB = aopGetUsesAcc(right, offset);
5606               if (rightInB)
5607                 {
5608                   pushedB = pushB ();
5609                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5610                 }
5611               MOVA (aopGet (left, offset, FALSE, FALSE));
5612               if (sign && size == 0)
5613                 {
5614                   emitcode ("xrl", "a,#0x80");
5615                   if (AOP_TYPE (right) == AOP_LIT)
5616                     {
5617                       unsigned long lit = (unsigned long)
5618                       floatFromVal (AOP (right)->aopu.aop_lit);
5619                       emitcode ("subb", "a,#0x%02x",
5620                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5621                     }
5622                   else
5623                     {
5624                       if (!rightInB)
5625                         {
5626                           pushedB = pushB ();
5627                           rightInB++;
5628                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5629                         }
5630                       emitcode ("xrl", "b,#0x80");
5631                       emitcode ("subb", "a,b");
5632                     }
5633                 }
5634               else
5635                 {
5636                   if (rightInB)
5637                     emitcode ("subb", "a,b");
5638                   else
5639                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5640                 }
5641               if (rightInB)
5642                 popB (pushedB);
5643               offset++;
5644             }
5645         }
5646     }
5647
5648 release:
5649   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5650   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5651   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5652     {
5653       outBitC (result);
5654     }
5655   else
5656     {
5657       /* if the result is used in the next
5658          ifx conditional branch then generate
5659          code a little differently */
5660       if (ifx)
5661         genIfxJump (ifx, "c", NULL, NULL, result);
5662       else
5663         outBitC (result);
5664       /* leave the result in acc */
5665     }
5666 }
5667
5668 /*-----------------------------------------------------------------*/
5669 /* genCmpGt :- greater than comparison                             */
5670 /*-----------------------------------------------------------------*/
5671 static void
5672 genCmpGt (iCode * ic, iCode * ifx)
5673 {
5674   operand *left, *right, *result;
5675   sym_link *letype, *retype;
5676   int sign;
5677
5678   D(emitcode (";     genCmpGt",""));
5679
5680   left = IC_LEFT (ic);
5681   right = IC_RIGHT (ic);
5682   result = IC_RESULT (ic);
5683
5684   letype = getSpec (operandType (left));
5685   retype = getSpec (operandType (right));
5686   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5687            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5688   /* assign the amsops */
5689   aopOp (left, ic, FALSE);
5690   aopOp (right, ic, FALSE);
5691   aopOp (result, ic, TRUE);
5692
5693   genCmp (right, left, result, ifx, sign, ic);
5694
5695   freeAsmop (result, NULL, ic, TRUE);
5696 }
5697
5698 /*-----------------------------------------------------------------*/
5699 /* genCmpLt - less than comparisons                                */
5700 /*-----------------------------------------------------------------*/
5701 static void
5702 genCmpLt (iCode * ic, iCode * ifx)
5703 {
5704   operand *left, *right, *result;
5705   sym_link *letype, *retype;
5706   int sign;
5707
5708   D(emitcode (";     genCmpLt",""));
5709
5710   left = IC_LEFT (ic);
5711   right = IC_RIGHT (ic);
5712   result = IC_RESULT (ic);
5713
5714   letype = getSpec (operandType (left));
5715   retype = getSpec (operandType (right));
5716   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5717            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5718   /* assign the amsops */
5719   aopOp (left, ic, FALSE);
5720   aopOp (right, ic, FALSE);
5721   aopOp (result, ic, TRUE);
5722
5723   genCmp (left, right, result, ifx, sign, ic);
5724
5725   freeAsmop (result, NULL, ic, TRUE);
5726 }
5727
5728 /*-----------------------------------------------------------------*/
5729 /* gencjneshort - compare and jump if not equal                    */
5730 /*-----------------------------------------------------------------*/
5731 static void
5732 gencjneshort (operand * left, operand * right, symbol * lbl)
5733 {
5734   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5735   int offset = 0;
5736   unsigned long lit = 0L;
5737
5738   /* if the left side is a literal or
5739      if the right is in a pointer register and left
5740      is not */
5741   if ((AOP_TYPE (left) == AOP_LIT) ||
5742       (AOP_TYPE (left) == AOP_IMMD) ||
5743       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5744     {
5745       operand *t = right;
5746       right = left;
5747       left = t;
5748     }
5749
5750   if (AOP_TYPE (right) == AOP_LIT)
5751     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5752
5753   /* if the right side is a literal then anything goes */
5754   if (AOP_TYPE (right) == AOP_LIT &&
5755       AOP_TYPE (left) != AOP_DIR  &&
5756       AOP_TYPE (left) != AOP_IMMD)
5757     {
5758       while (size--)
5759         {
5760           emitcode ("cjne", "%s,%s,%05d$",
5761                     aopGet (left, offset, FALSE, FALSE),
5762                     aopGet (right, offset, FALSE, FALSE),
5763                     lbl->key + 100);
5764           offset++;
5765         }
5766     }
5767
5768   /* if the right side is in a register or in direct space or
5769      if the left is a pointer register & right is not */
5770   else if (AOP_TYPE (right) == AOP_REG ||
5771            AOP_TYPE (right) == AOP_DIR ||
5772            AOP_TYPE (right) == AOP_LIT ||
5773            AOP_TYPE (right) == AOP_IMMD ||
5774            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5775            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5776     {
5777       while (size--)
5778         {
5779           MOVA (aopGet (left, offset, FALSE, FALSE));
5780           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5781               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5782             emitcode ("jnz", "%05d$", lbl->key + 100);
5783           else
5784             emitcode ("cjne", "a,%s,%05d$",
5785                       aopGet (right, offset, FALSE, TRUE),
5786                       lbl->key + 100);
5787           offset++;
5788         }
5789     }
5790   else
5791     {
5792       /* right is a pointer reg need both a & b */
5793       while (size--)
5794         {
5795           char *l;
5796           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5797           wassertl(!BINUSE, "B was in use");
5798           l = aopGet (left, offset, FALSE, FALSE);
5799           if (strcmp (l, "b"))
5800             emitcode ("mov", "b,%s", l);
5801           MOVA (aopGet (right, offset, FALSE, FALSE));
5802           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5803           offset++;
5804         }
5805     }
5806 }
5807
5808 /*-----------------------------------------------------------------*/
5809 /* gencjne - compare and jump if not equal                         */
5810 /*-----------------------------------------------------------------*/
5811 static void
5812 gencjne (operand * left, operand * right, symbol * lbl)
5813 {
5814   symbol *tlbl = newiTempLabel (NULL);
5815
5816   gencjneshort (left, right, lbl);
5817
5818   emitcode ("mov", "a,%s", one);
5819   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5820   emitcode ("", "%05d$:", lbl->key + 100);
5821   emitcode ("clr", "a");
5822   emitcode ("", "%05d$:", tlbl->key + 100);
5823 }
5824
5825 /*-----------------------------------------------------------------*/
5826 /* genCmpEq - generates code for equal to                          */
5827 /*-----------------------------------------------------------------*/
5828 static void
5829 genCmpEq (iCode * ic, iCode * ifx)
5830 {
5831   operand *left, *right, *result;
5832
5833   D(emitcode (";     genCmpEq",""));
5834
5835   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5836   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5837   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5838
5839   /* if literal, literal on the right or
5840      if the right is in a pointer register and left
5841      is not */
5842   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5843       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5844     {
5845       operand *t = IC_RIGHT (ic);
5846       IC_RIGHT (ic) = IC_LEFT (ic);
5847       IC_LEFT (ic) = t;
5848     }
5849
5850   if (ifx && !AOP_SIZE (result))
5851     {
5852       symbol *tlbl;
5853       /* if they are both bit variables */
5854       if (AOP_TYPE (left) == AOP_CRY &&
5855           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5856         {
5857           if (AOP_TYPE (right) == AOP_LIT)
5858             {
5859               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5860               if (lit == 0L)
5861                 {
5862                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5863                   emitcode ("cpl", "c");
5864                 }
5865               else if (lit == 1L)
5866                 {
5867                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5868                 }
5869               else
5870                 {
5871                   emitcode ("clr", "c");
5872                 }
5873               /* AOP_TYPE(right) == AOP_CRY */
5874             }
5875           else
5876             {
5877               symbol *lbl = newiTempLabel (NULL);
5878               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5879               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5880               emitcode ("cpl", "c");
5881               emitcode ("", "%05d$:", (lbl->key + 100));
5882             }
5883           /* if true label then we jump if condition
5884              supplied is true */
5885           tlbl = newiTempLabel (NULL);
5886           if (IC_TRUE (ifx))
5887             {
5888               emitcode ("jnc", "%05d$", tlbl->key + 100);
5889               freeForBranchAsmop (result);
5890               freeForBranchAsmop (right);
5891               freeForBranchAsmop (left);
5892               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5893             }
5894           else
5895             {
5896               emitcode ("jc", "%05d$", tlbl->key + 100);
5897               freeForBranchAsmop (result);
5898               freeForBranchAsmop (right);
5899               freeForBranchAsmop (left);
5900               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5901             }
5902           emitcode ("", "%05d$:", tlbl->key + 100);
5903         }
5904       else
5905         {
5906           tlbl = newiTempLabel (NULL);
5907           gencjneshort (left, right, tlbl);
5908           if (IC_TRUE (ifx))
5909             {
5910               freeForBranchAsmop (result);
5911               freeForBranchAsmop (right);
5912               freeForBranchAsmop (left);
5913               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5914               emitcode ("", "%05d$:", tlbl->key + 100);
5915             }
5916           else
5917             {
5918               symbol *lbl = newiTempLabel (NULL);
5919               emitcode ("sjmp", "%05d$", lbl->key + 100);
5920               emitcode ("", "%05d$:", tlbl->key + 100);
5921               freeForBranchAsmop (result);
5922               freeForBranchAsmop (right);
5923               freeForBranchAsmop (left);
5924               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5925               emitcode ("", "%05d$:", lbl->key + 100);
5926             }
5927         }
5928       /* mark the icode as generated */
5929       ifx->generated = 1;
5930       goto release;
5931     }
5932
5933   /* if they are both bit variables */
5934   if (AOP_TYPE (left) == AOP_CRY &&
5935       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5936     {
5937       if (AOP_TYPE (right) == AOP_LIT)
5938         {
5939           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5940           if (lit == 0L)
5941             {
5942               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5943               emitcode ("cpl", "c");
5944             }
5945           else if (lit == 1L)
5946             {
5947               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5948             }
5949           else
5950             {
5951               emitcode ("clr", "c");
5952             }
5953           /* AOP_TYPE(right) == AOP_CRY */
5954         }
5955       else
5956         {
5957           symbol *lbl = newiTempLabel (NULL);
5958           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5959           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5960           emitcode ("cpl", "c");
5961           emitcode ("", "%05d$:", (lbl->key + 100));
5962         }
5963       /* c = 1 if egal */
5964       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5965         {
5966           outBitC (result);
5967           goto release;
5968         }
5969       if (ifx)
5970         {
5971           genIfxJump (ifx, "c", left, right, result);
5972           goto release;
5973         }
5974       /* if the result is used in an arithmetic operation
5975          then put the result in place */
5976       outBitC (result);
5977     }
5978   else
5979     {
5980       gencjne (left, right, newiTempLabel (NULL));
5981       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5982         {
5983           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5984           goto release;
5985         }
5986       if (ifx)
5987         {
5988           genIfxJump (ifx, "a", left, right, result);
5989           goto release;
5990         }
5991       /* if the result is used in an arithmetic operation
5992          then put the result in place */
5993       if (AOP_TYPE (result) != AOP_CRY)
5994         outAcc (result);
5995       /* leave the result in acc */
5996     }
5997
5998 release:
5999   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6000   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6001   freeAsmop (result, NULL, ic, TRUE);
6002 }
6003
6004 /*-----------------------------------------------------------------*/
6005 /* ifxForOp - returns the icode containing the ifx for operand     */
6006 /*-----------------------------------------------------------------*/
6007 static iCode *
6008 ifxForOp (operand * op, iCode * ic)
6009 {
6010   /* if true symbol then needs to be assigned */
6011   if (IS_TRUE_SYMOP (op))
6012     return NULL;
6013
6014   /* if this has register type condition and
6015      the next instruction is ifx with the same operand
6016      and live to of the operand is upto the ifx only then */
6017   if (ic->next &&
6018       ic->next->op == IFX &&
6019       IC_COND (ic->next)->key == op->key &&
6020       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6021     return ic->next;
6022
6023   return NULL;
6024 }
6025
6026 /*-----------------------------------------------------------------*/
6027 /* hasInc - operand is incremented before any other use            */
6028 /*-----------------------------------------------------------------*/
6029 static iCode *
6030 hasInc (operand *op, iCode *ic,int osize)
6031 {
6032   sym_link *type = operandType(op);
6033   sym_link *retype = getSpec (type);
6034   iCode *lic = ic->next;
6035   int isize ;
6036
6037   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6038   if (!IS_SYMOP(op)) return NULL;
6039
6040   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6041   if (IS_AGGREGATE(type->next)) return NULL;
6042   if (osize != (isize = getSize(type->next))) return NULL;
6043
6044   while (lic) {
6045     /* if operand of the form op = op + <sizeof *op> */
6046     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6047         isOperandEqual(IC_RESULT(lic),op) &&
6048         isOperandLiteral(IC_RIGHT(lic)) &&
6049         operandLitValue(IC_RIGHT(lic)) == isize) {
6050       return lic;
6051     }
6052     /* if the operand used or deffed */
6053     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6054       return NULL;
6055     }
6056     /* if GOTO or IFX */
6057     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6058     lic = lic->next;
6059   }
6060   return NULL;
6061 }
6062
6063 /*-----------------------------------------------------------------*/
6064 /* genAndOp - for && operation                                     */
6065 /*-----------------------------------------------------------------*/
6066 static void
6067 genAndOp (iCode * ic)
6068 {
6069   operand *left, *right, *result;
6070   symbol *tlbl;
6071
6072   D(emitcode (";     genAndOp",""));
6073
6074   /* note here that && operations that are in an
6075      if statement are taken away by backPatchLabels
6076      only those used in arthmetic operations remain */
6077   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6078   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6079   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6080
6081   /* if both are bit variables */
6082   if (AOP_TYPE (left) == AOP_CRY &&
6083       AOP_TYPE (right) == AOP_CRY)
6084     {
6085       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6086       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6087       outBitC (result);
6088     }
6089   else
6090     {
6091       tlbl = newiTempLabel (NULL);
6092       toBoolean (left);
6093       emitcode ("jz", "%05d$", tlbl->key + 100);
6094       toBoolean (right);
6095       emitcode ("", "%05d$:", tlbl->key + 100);
6096       outBitAcc (result);
6097     }
6098
6099   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6100   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6101   freeAsmop (result, NULL, ic, TRUE);
6102 }
6103
6104
6105 /*-----------------------------------------------------------------*/
6106 /* genOrOp - for || operation                                      */
6107 /*-----------------------------------------------------------------*/
6108 static void
6109 genOrOp (iCode * ic)
6110 {
6111   operand *left, *right, *result;
6112   symbol *tlbl;
6113
6114   D(emitcode (";     genOrOp",""));
6115
6116   /* note here that || operations that are in an
6117      if statement are taken away by backPatchLabels
6118      only those used in arthmetic operations remain */
6119   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6120   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6121   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6122
6123   /* if both are bit variables */
6124   if (AOP_TYPE (left) == AOP_CRY &&
6125       AOP_TYPE (right) == AOP_CRY)
6126     {
6127       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6128       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6129       outBitC (result);
6130     }
6131   else
6132     {
6133       tlbl = newiTempLabel (NULL);
6134       toBoolean (left);
6135       emitcode ("jnz", "%05d$", tlbl->key + 100);
6136       toBoolean (right);
6137       emitcode ("", "%05d$:", tlbl->key + 100);
6138       outBitAcc (result);
6139     }
6140
6141   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6142   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6143   freeAsmop (result, NULL, ic, TRUE);
6144 }
6145
6146 /*-----------------------------------------------------------------*/
6147 /* isLiteralBit - test if lit == 2^n                               */
6148 /*-----------------------------------------------------------------*/
6149 static int
6150 isLiteralBit (unsigned long lit)
6151 {
6152   unsigned long pw[32] =
6153   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6154    0x100L, 0x200L, 0x400L, 0x800L,
6155    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6156    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6157    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6158    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6159    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6160   int idx;
6161
6162   for (idx = 0; idx < 32; idx++)
6163     if (lit == pw[idx])
6164       return idx + 1;
6165   return 0;
6166 }
6167
6168 /*-----------------------------------------------------------------*/
6169 /* continueIfTrue -                                                */
6170 /*-----------------------------------------------------------------*/
6171 static void
6172 continueIfTrue (iCode * ic)
6173 {
6174   if (IC_TRUE (ic))
6175     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6176   ic->generated = 1;
6177 }
6178
6179 /*-----------------------------------------------------------------*/
6180 /* jmpIfTrue -                                                     */
6181 /*-----------------------------------------------------------------*/
6182 static void
6183 jumpIfTrue (iCode * ic)
6184 {
6185   if (!IC_TRUE (ic))
6186     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6187   ic->generated = 1;
6188 }
6189
6190 /*-----------------------------------------------------------------*/
6191 /* jmpTrueOrFalse -                                                */
6192 /*-----------------------------------------------------------------*/
6193 static void
6194 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6195 {
6196   // ugly but optimized by peephole
6197   if (IC_TRUE (ic))
6198     {
6199       symbol *nlbl = newiTempLabel (NULL);
6200       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6201       emitcode ("", "%05d$:", tlbl->key + 100);
6202       freeForBranchAsmop (result);
6203       freeForBranchAsmop (right);
6204       freeForBranchAsmop (left);
6205       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6206       emitcode ("", "%05d$:", nlbl->key + 100);
6207     }
6208   else
6209     {
6210       freeForBranchAsmop (result);
6211       freeForBranchAsmop (right);
6212       freeForBranchAsmop (left);
6213       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6214       emitcode ("", "%05d$:", tlbl->key + 100);
6215     }
6216   ic->generated = 1;
6217 }
6218
6219 /*-----------------------------------------------------------------*/
6220 /* genAnd  - code for and                                          */
6221 /*-----------------------------------------------------------------*/
6222 static void
6223 genAnd (iCode * ic, iCode * ifx)
6224 {
6225   operand *left, *right, *result;
6226   int size, offset = 0;
6227   unsigned long lit = 0L;
6228   int bytelit = 0;
6229   char buffer[10];
6230
6231   D(emitcode (";     genAnd",""));
6232
6233   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6234   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6235   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6236
6237 #ifdef DEBUG_TYPE
6238   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6239             AOP_TYPE (result),
6240             AOP_TYPE (left), AOP_TYPE (right));
6241   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6242             AOP_SIZE (result),
6243             AOP_SIZE (left), AOP_SIZE (right));
6244 #endif
6245
6246   /* if left is a literal & right is not then exchange them */
6247   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6248       AOP_NEEDSACC (left))
6249     {
6250       operand *tmp = right;
6251       right = left;
6252       left = tmp;
6253     }
6254
6255   /* if result = right then exchange left and right */
6256   if (sameRegs (AOP (result), AOP (right)))
6257     {
6258       operand *tmp = right;
6259       right = left;
6260       left = tmp;
6261     }
6262
6263   /* if right is bit then exchange them */
6264   if (AOP_TYPE (right) == AOP_CRY &&
6265       AOP_TYPE (left) != AOP_CRY)
6266     {
6267       operand *tmp = right;
6268       right = left;
6269       left = tmp;
6270     }
6271   if (AOP_TYPE (right) == AOP_LIT)
6272     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6273
6274   size = AOP_SIZE (result);
6275
6276   // if(bit & yy)
6277   // result = bit & yy;
6278   if (AOP_TYPE (left) == AOP_CRY)
6279     {
6280       // c = bit & literal;
6281       if (AOP_TYPE (right) == AOP_LIT)
6282         {
6283           if (lit & 1)
6284             {
6285               if (size && sameRegs (AOP (result), AOP (left)))
6286                 // no change
6287                 goto release;
6288               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6289             }
6290           else
6291             {
6292               // bit(result) = 0;
6293               if (size && (AOP_TYPE (result) == AOP_CRY))
6294                 {
6295                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6296                   goto release;
6297                 }
6298               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6299                 {
6300                   jumpIfTrue (ifx);
6301                   goto release;
6302                 }
6303               emitcode ("clr", "c");
6304             }
6305         }
6306       else
6307         {
6308           if (AOP_TYPE (right) == AOP_CRY)
6309             {
6310               // c = bit & bit;
6311               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6312               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6313             }
6314           else
6315             {
6316               // c = bit & val;
6317               MOVA (aopGet (right, 0, FALSE, FALSE));
6318               // c = lsb
6319               emitcode ("rrc", "a");
6320               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6321             }
6322         }
6323       // bit = c
6324       // val = c
6325       if (size)
6326         outBitC (result);
6327       // if(bit & ...)
6328       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6329         genIfxJump (ifx, "c", left, right, result);
6330       goto release;
6331     }
6332
6333   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6334   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6335   if ((AOP_TYPE (right) == AOP_LIT) &&
6336       (AOP_TYPE (result) == AOP_CRY) &&
6337       (AOP_TYPE (left) != AOP_CRY))
6338     {
6339       int posbit = isLiteralBit (lit);
6340       /* left &  2^n */
6341       if (posbit)
6342         {
6343           posbit--;
6344           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6345           // bit = left & 2^n
6346           if (size)
6347             {
6348               switch (posbit & 0x07)
6349                 {
6350                   case 0: emitcode ("rrc", "a");
6351                           break;
6352                   case 7: emitcode ("rlc", "a");
6353                           break;
6354                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6355                           break;
6356                 }
6357             }
6358           // if(left &  2^n)
6359           else
6360             {
6361               if (ifx)
6362                 {
6363                   SNPRINTF (buffer, sizeof(buffer),
6364                             "acc.%d", posbit & 0x07);
6365                   genIfxJump (ifx, buffer, left, right, result);
6366                 }
6367               else
6368                 {// what is this case? just found it in ds390/gen.c
6369                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6370                 }
6371               goto release;
6372             }
6373         }
6374       else
6375         {
6376           symbol *tlbl = newiTempLabel (NULL);
6377           int sizel = AOP_SIZE (left);
6378           if (size)
6379             emitcode ("setb", "c");
6380           while (sizel--)
6381             {
6382               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6383                 {
6384                   MOVA (aopGet (left, offset, FALSE, FALSE));
6385                   // byte ==  2^n ?
6386                   if ((posbit = isLiteralBit (bytelit)) != 0)
6387                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6388                   else
6389                     {
6390                       if (bytelit != 0x0FFL)
6391                         emitcode ("anl", "a,%s",
6392                                   aopGet (right, offset, FALSE, TRUE));
6393                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6394                     }
6395                 }
6396               offset++;
6397             }
6398           // bit = left & literal
6399           if (size)
6400             {
6401               emitcode ("clr", "c");
6402               emitcode ("", "%05d$:", tlbl->key + 100);
6403             }
6404           // if(left & literal)
6405           else
6406             {
6407               if (ifx)
6408                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6409               else
6410                 emitcode ("", "%05d$:", tlbl->key + 100);
6411               goto release;
6412             }
6413         }
6414       outBitC (result);
6415       goto release;
6416     }
6417
6418   /* if left is same as result */
6419   if (sameRegs (AOP (result), AOP (left)))
6420     {
6421       for (; size--; offset++)
6422         {
6423           if (AOP_TYPE (right) == AOP_LIT)
6424             {
6425               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6426               if (bytelit == 0x0FF)
6427                 {
6428                   /* dummy read of volatile operand */
6429                   if (isOperandVolatile (left, FALSE))
6430                     MOVA (aopGet (left, offset, FALSE, FALSE));
6431                   else
6432                     continue;
6433                 }
6434               else if (bytelit == 0)
6435                 {
6436                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6437                 }
6438               else if (IS_AOP_PREG (result))
6439                 {
6440                   MOVA (aopGet (left, offset, FALSE, TRUE));
6441                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6442                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6443                 }
6444               else
6445                 emitcode ("anl", "%s,%s",
6446                           aopGet (left, offset, FALSE, TRUE),
6447                           aopGet (right, offset, FALSE, FALSE));
6448             }
6449           else
6450             {
6451               if (AOP_TYPE (left) == AOP_ACC)
6452                 {
6453                   if (offset)
6454                     emitcode("mov", "a,b");
6455                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6456                 }
6457               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6458                 {
6459                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6460                   MOVA (aopGet (right, offset, FALSE, FALSE));
6461                   emitcode ("anl", "a,b");
6462                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6463                 }
6464               else if (aopGetUsesAcc (left, offset))
6465                 {
6466                   MOVA (aopGet (left, offset, FALSE, FALSE));
6467                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6468                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6469                 }
6470               else
6471                 {
6472                   MOVA (aopGet (right, offset, FALSE, FALSE));
6473                   if (IS_AOP_PREG (result))
6474                     {
6475                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6476                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6477                     }
6478                   else
6479                     emitcode ("anl", "%s,a",
6480                               aopGet (left, offset, FALSE, TRUE));
6481                 }
6482             }
6483         }
6484     }
6485   else
6486     {
6487       // left & result in different registers
6488       if (AOP_TYPE (result) == AOP_CRY)
6489         {
6490           // result = bit
6491           // if(size), result in bit
6492           // if(!size && ifx), conditional oper: if(left & right)
6493           symbol *tlbl = newiTempLabel (NULL);
6494           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6495           if (size)
6496             emitcode ("setb", "c");
6497           while (sizer--)
6498             {
6499               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6500                   && AOP_TYPE(left)==AOP_ACC)
6501                 {
6502                   if (offset)
6503                     emitcode("mov", "a,b");
6504                   emitcode ("anl", "a,%s",
6505                             aopGet (right, offset, FALSE, FALSE));
6506                 } else {
6507                   if (AOP_TYPE(left)==AOP_ACC)
6508                     {
6509                       if (!offset)
6510                         {
6511                           bool pushedB = pushB ();
6512                           emitcode("mov", "b,a");
6513                           MOVA (aopGet (right, offset, FALSE, FALSE));
6514                           emitcode("anl", "a,b");
6515                           popB (pushedB);
6516                         }
6517                       else
6518                         {
6519                           MOVA (aopGet (right, offset, FALSE, FALSE));
6520                           emitcode("anl", "a,b");
6521                         }
6522                     } else {
6523                       MOVA (aopGet (right, offset, FALSE, FALSE));
6524                       emitcode ("anl", "a,%s",
6525                                 aopGet (left, offset, FALSE, FALSE));
6526                     }
6527                 }
6528               emitcode ("jnz", "%05d$", tlbl->key + 100);
6529               offset++;
6530             }
6531           if (size)
6532             {
6533               CLRC;
6534               emitcode ("", "%05d$:", tlbl->key + 100);
6535               outBitC (result);
6536             }
6537           else if (ifx)
6538             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6539           else
6540             emitcode ("", "%05d$:", tlbl->key + 100);
6541         }
6542       else
6543         {
6544           for (; (size--); offset++)
6545             {
6546               // normal case
6547               // result = left & right
6548               if (AOP_TYPE (right) == AOP_LIT)
6549                 {
6550                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6551                   if (bytelit == 0x0FF)
6552                     {
6553                       aopPut (result,
6554                               aopGet (left, offset, FALSE, FALSE),
6555                               offset,
6556                               isOperandVolatile (result, FALSE));
6557                       continue;
6558                     }
6559                   else if (bytelit == 0)
6560                     {
6561                       /* dummy read of volatile operand */
6562                       if (isOperandVolatile (left, FALSE))
6563                         MOVA (aopGet (left, offset, FALSE, FALSE));
6564                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6565                       continue;
6566                     }
6567                   else if (AOP_TYPE (left) == AOP_ACC)
6568                     {
6569                       if (!offset)
6570                         {
6571                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6572                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6573                           continue;
6574                         }
6575                       else
6576                         {
6577                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6578                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6579                           continue;
6580                         }
6581                     }
6582                 }
6583               // faster than result <- left, anl result,right
6584               // and better if result is SFR
6585               if (AOP_TYPE (left) == AOP_ACC)
6586                 {
6587                   if (offset)
6588                     emitcode("mov", "a,b");
6589                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6590                 }
6591               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6592                 {
6593                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6594                   MOVA (aopGet (right, offset, FALSE, FALSE));
6595                   emitcode ("anl", "a,b");
6596                 }
6597               else if (aopGetUsesAcc (left, offset))
6598                 {
6599                   MOVA (aopGet (left, offset, FALSE, FALSE));
6600                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6601                 }
6602               else
6603                 {
6604                   MOVA (aopGet (right, offset, FALSE, FALSE));
6605                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6606                 }
6607               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6608             }
6609         }
6610     }
6611
6612 release:
6613   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6614   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6615   freeAsmop (result, NULL, ic, TRUE);
6616 }
6617
6618 /*-----------------------------------------------------------------*/
6619 /* genOr  - code for or                                            */
6620 /*-----------------------------------------------------------------*/
6621 static void
6622 genOr (iCode * ic, iCode * ifx)
6623 {
6624   operand *left, *right, *result;
6625   int size, offset = 0;
6626   unsigned long lit = 0L;
6627   int bytelit = 0;
6628
6629   D(emitcode (";     genOr",""));
6630
6631   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6632   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6633   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6634
6635 #ifdef DEBUG_TYPE
6636   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6637             AOP_TYPE (result),
6638             AOP_TYPE (left), AOP_TYPE (right));
6639   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6640             AOP_SIZE (result),
6641             AOP_SIZE (left), AOP_SIZE (right));
6642 #endif
6643
6644   /* if left is a literal & right is not then exchange them */
6645   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6646       AOP_NEEDSACC (left))
6647     {
6648       operand *tmp = right;
6649       right = left;
6650       left = tmp;
6651     }
6652
6653   /* if result = right then exchange them */
6654   if (sameRegs (AOP (result), AOP (right)))
6655     {
6656       operand *tmp = right;
6657       right = left;
6658       left = tmp;
6659     }
6660
6661   /* if right is bit then exchange them */
6662   if (AOP_TYPE (right) == AOP_CRY &&
6663       AOP_TYPE (left) != AOP_CRY)
6664     {
6665       operand *tmp = right;
6666       right = left;
6667       left = tmp;
6668     }
6669   if (AOP_TYPE (right) == AOP_LIT)
6670     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6671
6672   size = AOP_SIZE (result);
6673
6674   // if(bit | yy)
6675   // xx = bit | yy;
6676   if (AOP_TYPE (left) == AOP_CRY)
6677     {
6678       if (AOP_TYPE (right) == AOP_LIT)
6679         {
6680           // c = bit | literal;
6681           if (lit)
6682             {
6683               // lit != 0 => result = 1
6684               if (AOP_TYPE (result) == AOP_CRY)
6685                 {
6686                   if (size)
6687                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6688                   else if (ifx)
6689                     continueIfTrue (ifx);
6690                   goto release;
6691                 }
6692               emitcode ("setb", "c");
6693             }
6694           else
6695             {
6696               // lit == 0 => result = left
6697               if (size && sameRegs (AOP (result), AOP (left)))
6698                 goto release;
6699               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6700             }
6701         }
6702       else
6703         {
6704           if (AOP_TYPE (right) == AOP_CRY)
6705             {
6706               // c = bit | bit;
6707               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6708               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6709             }
6710           else
6711             {
6712               // c = bit | val;
6713               symbol *tlbl = newiTempLabel (NULL);
6714               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6715                 emitcode ("setb", "c");
6716               emitcode ("jb", "%s,%05d$",
6717                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6718               toBoolean (right);
6719               emitcode ("jnz", "%05d$", tlbl->key + 100);
6720               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6721                 {
6722                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6723                   goto release;
6724                 }
6725               else
6726                 {
6727                   CLRC;
6728                   emitcode ("", "%05d$:", tlbl->key + 100);
6729                 }
6730             }
6731         }
6732       // bit = c
6733       // val = c
6734       if (size)
6735         outBitC (result);
6736       // if(bit | ...)
6737       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6738         genIfxJump (ifx, "c", left, right, result);
6739       goto release;
6740     }
6741
6742   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6743   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6744   if ((AOP_TYPE (right) == AOP_LIT) &&
6745       (AOP_TYPE (result) == AOP_CRY) &&
6746       (AOP_TYPE (left) != AOP_CRY))
6747     {
6748       if (lit)
6749         {
6750           // result = 1
6751           if (size)
6752             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6753           else
6754             continueIfTrue (ifx);
6755           goto release;
6756         }
6757       else
6758         {
6759           // lit = 0, result = boolean(left)
6760           if (size)
6761             emitcode ("setb", "c");
6762           toBoolean (right);
6763           if (size)
6764             {
6765               symbol *tlbl = newiTempLabel (NULL);
6766               emitcode ("jnz", "%05d$", tlbl->key + 100);
6767               CLRC;
6768               emitcode ("", "%05d$:", tlbl->key + 100);
6769             }
6770           else
6771             {
6772               genIfxJump (ifx, "a", left, right, result);
6773               goto release;
6774             }
6775         }
6776       outBitC (result);
6777       goto release;
6778     }
6779
6780   /* if left is same as result */
6781   if (sameRegs (AOP (result), AOP (left)))
6782     {
6783       for (; size--; offset++)
6784         {
6785           if (AOP_TYPE (right) == AOP_LIT)
6786             {
6787               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6788               if (bytelit == 0)
6789                 {
6790                   /* dummy read of volatile operand */
6791                   if (isOperandVolatile (left, FALSE))
6792                     MOVA (aopGet (left, offset, FALSE, FALSE));
6793                   else
6794                     continue;
6795                 }
6796               else if (bytelit == 0x0FF)
6797                 {
6798                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6799                 }
6800               else if (IS_AOP_PREG (left))
6801                 {
6802                   MOVA (aopGet (left, offset, FALSE, TRUE));
6803                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6804                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6805                 }
6806               else
6807                 {
6808                   emitcode ("orl", "%s,%s",
6809                             aopGet (left, offset, FALSE, TRUE),
6810                             aopGet (right, offset, FALSE, FALSE));
6811                 }
6812             }
6813           else
6814             {
6815               if (AOP_TYPE (left) == AOP_ACC)
6816                 {
6817                   if (offset)
6818                     emitcode("mov", "a,b");
6819                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6820                 }
6821               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6822                 {
6823                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6824                   MOVA (aopGet (right, offset, FALSE, FALSE));
6825                   emitcode ("orl", "a,b");
6826                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6827                 }
6828               else if (aopGetUsesAcc (left, offset))
6829                 {
6830                   MOVA (aopGet (left, offset, FALSE, FALSE));
6831                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6832                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6833                 }
6834               else
6835                 {
6836                   MOVA (aopGet (right, offset, FALSE, FALSE));
6837                   if (IS_AOP_PREG (left))
6838                     {
6839                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6840                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6841                     }
6842                   else
6843                     {
6844                       emitcode ("orl", "%s,a",
6845                                 aopGet (left, offset, FALSE, TRUE));
6846                     }
6847                 }
6848             }
6849         }
6850     }
6851   else
6852     {
6853       // left & result in different registers
6854       if (AOP_TYPE (result) == AOP_CRY)
6855         {
6856           // result = bit
6857           // if(size), result in bit
6858           // if(!size && ifx), conditional oper: if(left | right)
6859           symbol *tlbl = newiTempLabel (NULL);
6860           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6861           if (size)
6862             emitcode ("setb", "c");
6863           while (sizer--)
6864             {
6865               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6866                 if (offset)
6867                   emitcode("mov", "a,b");
6868                 emitcode ("orl", "a,%s",
6869                           aopGet (right, offset, FALSE, FALSE));
6870               } else {
6871                 MOVA (aopGet (right, offset, FALSE, FALSE));
6872                 emitcode ("orl", "a,%s",
6873                           aopGet (left, offset, FALSE, FALSE));
6874               }
6875               emitcode ("jnz", "%05d$", tlbl->key + 100);
6876               offset++;
6877             }
6878           if (size)
6879             {
6880               CLRC;
6881               emitcode ("", "%05d$:", tlbl->key + 100);
6882               outBitC (result);
6883             }
6884           else if (ifx)
6885             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6886           else
6887             emitcode ("", "%05d$:", tlbl->key + 100);
6888         }
6889       else
6890         {
6891           for (; (size--); offset++)
6892             {
6893               // normal case
6894               // result = left | right
6895               if (AOP_TYPE (right) == AOP_LIT)
6896                 {
6897                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6898                   if (bytelit == 0)
6899                     {
6900                       aopPut (result,
6901                               aopGet (left, offset, FALSE, FALSE),
6902                               offset,
6903                               isOperandVolatile (result, FALSE));
6904                       continue;
6905                     }
6906                   else if (bytelit == 0x0FF)
6907                     {
6908                       /* dummy read of volatile operand */
6909                       if (isOperandVolatile (left, FALSE))
6910                         MOVA (aopGet (left, offset, FALSE, FALSE));
6911                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6912                       continue;
6913                     }
6914                 }
6915               // faster than result <- left, anl result,right
6916               // and better if result is SFR
6917               if (AOP_TYPE (left) == AOP_ACC)
6918                 {
6919                   if (offset)
6920                     emitcode("mov", "a,b");
6921                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6922                 }
6923               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6924                 {
6925                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6926                   MOVA (aopGet (right, offset, FALSE, FALSE));
6927                   emitcode ("orl", "a,b");
6928                 }
6929               else if (aopGetUsesAcc (left, offset))
6930                 {
6931                   MOVA (aopGet (left, offset, FALSE, FALSE));
6932                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6933                 }
6934               else
6935                 {
6936                   MOVA (aopGet (right, offset, FALSE, FALSE));
6937                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6938                 }
6939               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6940             }
6941         }
6942     }
6943
6944 release:
6945   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6946   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6947   freeAsmop (result, NULL, ic, TRUE);
6948 }
6949
6950 /*-----------------------------------------------------------------*/
6951 /* genXor - code for xclusive or                                   */
6952 /*-----------------------------------------------------------------*/
6953 static void
6954 genXor (iCode * ic, iCode * ifx)
6955 {
6956   operand *left, *right, *result;
6957   int size, offset = 0;
6958   unsigned long lit = 0L;
6959   int bytelit = 0;
6960
6961   D(emitcode (";     genXor",""));
6962
6963   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6964   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6965   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6966
6967 #ifdef DEBUG_TYPE
6968   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6969             AOP_TYPE (result),
6970             AOP_TYPE (left), AOP_TYPE (right));
6971   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6972             AOP_SIZE (result),
6973             AOP_SIZE (left), AOP_SIZE (right));
6974 #endif
6975
6976   /* if left is a literal & right is not ||
6977      if left needs acc & right does not */
6978   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6979       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6980     {
6981       operand *tmp = right;
6982       right = left;
6983       left = tmp;
6984     }
6985
6986   /* if result = right then exchange them */
6987   if (sameRegs (AOP (result), AOP (right)))
6988     {
6989       operand *tmp = right;
6990       right = left;
6991       left = tmp;
6992     }
6993
6994   /* if right is bit then exchange them */
6995   if (AOP_TYPE (right) == AOP_CRY &&
6996       AOP_TYPE (left) != AOP_CRY)
6997     {
6998       operand *tmp = right;
6999       right = left;
7000       left = tmp;
7001     }
7002   if (AOP_TYPE (right) == AOP_LIT)
7003     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7004
7005   size = AOP_SIZE (result);
7006
7007   // if(bit ^ yy)
7008   // xx = bit ^ yy;
7009   if (AOP_TYPE (left) == AOP_CRY)
7010     {
7011       if (AOP_TYPE (right) == AOP_LIT)
7012         {
7013           // c = bit & literal;
7014           if (lit >> 1)
7015             {
7016               // lit>>1  != 0 => result = 1
7017               if (AOP_TYPE (result) == AOP_CRY)
7018                 {
7019                   if (size)
7020                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7021                   else if (ifx)
7022                     continueIfTrue (ifx);
7023                   goto release;
7024                 }
7025               emitcode ("setb", "c");
7026             }
7027           else
7028             {
7029               // lit == (0 or 1)
7030               if (lit == 0)
7031                 {
7032                   // lit == 0, result = left
7033                   if (size && sameRegs (AOP (result), AOP (left)))
7034                     goto release;
7035                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7036                 }
7037               else
7038                 {
7039                   // lit == 1, result = not(left)
7040                   if (size && sameRegs (AOP (result), AOP (left)))
7041                     {
7042                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7043                       goto release;
7044                     }
7045                   else
7046                     {
7047                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7048                       emitcode ("cpl", "c");
7049                     }
7050                 }
7051             }
7052
7053         }
7054       else
7055         {
7056           // right != literal
7057           symbol *tlbl = newiTempLabel (NULL);
7058           if (AOP_TYPE (right) == AOP_CRY)
7059             {
7060               // c = bit ^ bit;
7061               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7062             }
7063           else
7064             {
7065               int sizer = AOP_SIZE (right);
7066               // c = bit ^ val
7067               // if val>>1 != 0, result = 1
7068               emitcode ("setb", "c");
7069               while (sizer)
7070                 {
7071                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7072                   if (sizer == 1)
7073                     // test the msb of the lsb
7074                     emitcode ("anl", "a,#0xfe");
7075                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7076                   sizer--;
7077                 }
7078               // val = (0,1)
7079               emitcode ("rrc", "a");
7080             }
7081           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7082           emitcode ("cpl", "c");
7083           emitcode ("", "%05d$:", (tlbl->key + 100));
7084         }
7085       // bit = c
7086       // val = c
7087       if (size)
7088         outBitC (result);
7089       // if(bit | ...)
7090       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7091         genIfxJump (ifx, "c", left, right, result);
7092       goto release;
7093     }
7094
7095   /* if left is same as result */
7096   if (sameRegs (AOP (result), AOP (left)))
7097     {
7098       for (; size--; offset++)
7099         {
7100           if (AOP_TYPE (right) == AOP_LIT)
7101             {
7102               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7103               if (bytelit == 0)
7104                 {
7105                   /* dummy read of volatile operand */
7106                   if (isOperandVolatile (left, FALSE))
7107                     MOVA (aopGet (left, offset, FALSE, FALSE));
7108                   else
7109                     continue;
7110                 }
7111               else if (IS_AOP_PREG (left))
7112                 {
7113                   MOVA (aopGet (left, offset, FALSE, TRUE));
7114                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7115                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7116                 }
7117               else
7118                 {
7119                   emitcode ("xrl", "%s,%s",
7120                             aopGet (left, offset, FALSE, TRUE),
7121                             aopGet (right, offset, FALSE, FALSE));
7122                 }
7123             }
7124           else
7125             {
7126               if (AOP_TYPE (left) == AOP_ACC)
7127                 {
7128                   if (offset)
7129                     emitcode("mov", "a,b");
7130                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7131                 }
7132               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7133                 {
7134                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7135                   MOVA (aopGet (right, offset, FALSE, FALSE));
7136                   emitcode ("xrl", "a,b");
7137                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7138                 }
7139               else if (aopGetUsesAcc (left, offset))
7140                 {
7141                   MOVA (aopGet (left, offset, FALSE, FALSE));
7142                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7143                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7144                 }
7145               else
7146                 {
7147                   MOVA (aopGet (right, offset, FALSE, FALSE));
7148                   if (IS_AOP_PREG (left))
7149                     {
7150                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7151                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7152                     }
7153                   else
7154                     emitcode ("xrl", "%s,a",
7155                               aopGet (left, offset, FALSE, TRUE));
7156                 }
7157             }
7158         }
7159     }
7160   else
7161     {
7162       // left & result in different registers
7163       if (AOP_TYPE (result) == AOP_CRY)
7164         {
7165           // result = bit
7166           // if(size), result in bit
7167           // if(!size && ifx), conditional oper: if(left ^ right)
7168           symbol *tlbl = newiTempLabel (NULL);
7169           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7170           if (size)
7171             emitcode ("setb", "c");
7172           while (sizer--)
7173             {
7174               if ((AOP_TYPE (right) == AOP_LIT) &&
7175                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7176                 {
7177                   MOVA (aopGet (left, offset, FALSE, FALSE));
7178                 }
7179               else
7180                 {
7181                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7182                     if (offset)
7183                       emitcode("mov", "a,b");
7184                     emitcode ("xrl", "a,%s",
7185                               aopGet (right, offset, FALSE, FALSE));
7186                   } else {
7187                     MOVA (aopGet (right, offset, FALSE, FALSE));
7188                     emitcode ("xrl", "a,%s",
7189                               aopGet (left, offset, FALSE, FALSE));
7190                   }
7191                 }
7192               emitcode ("jnz", "%05d$", tlbl->key + 100);
7193               offset++;
7194             }
7195           if (size)
7196             {
7197               CLRC;
7198               emitcode ("", "%05d$:", tlbl->key + 100);
7199               outBitC (result);
7200             }
7201           else if (ifx)
7202             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7203         }
7204       else
7205         {
7206           for (; (size--); offset++)
7207             {
7208               // normal case
7209               // result = left & right
7210               if (AOP_TYPE (right) == AOP_LIT)
7211                 {
7212                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7213                   if (bytelit == 0)
7214                     {
7215                       aopPut (result,
7216                               aopGet (left, offset, FALSE, FALSE),
7217                               offset,
7218                               isOperandVolatile (result, FALSE));
7219                       continue;
7220                     }
7221                 }
7222               // faster than result <- left, anl result,right
7223               // and better if result is SFR
7224               if (AOP_TYPE (left) == AOP_ACC)
7225                 {
7226                   if (offset)
7227                     emitcode("mov", "a,b");
7228                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7229                 }
7230               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7231                 {
7232                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7233                   MOVA (aopGet (right, offset, FALSE, FALSE));
7234                   emitcode ("xrl", "a,b");
7235                 }
7236               else if (aopGetUsesAcc (left, offset))
7237                 {
7238                   MOVA (aopGet (left, offset, FALSE, FALSE));
7239                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7240                 }
7241               else
7242                 {
7243                   MOVA (aopGet (right, offset, FALSE, FALSE));
7244                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7245                 }
7246               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7247             }
7248         }
7249     }
7250
7251 release:
7252   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7253   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7254   freeAsmop (result, NULL, ic, TRUE);
7255 }
7256
7257 /*-----------------------------------------------------------------*/
7258 /* genInline - write the inline code out                           */
7259 /*-----------------------------------------------------------------*/
7260 static void
7261 genInline (iCode * ic)
7262 {
7263   char *buffer, *bp, *bp1;
7264
7265   D(emitcode (";     genInline",""));
7266
7267   _G.inLine += (!options.asmpeep);
7268
7269   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
7270   strcpy (buffer, IC_INLINE (ic));
7271
7272   /* emit each line as a code */
7273   while (*bp)
7274     {
7275       if (*bp == '\n')
7276         {
7277           *bp++ = '\0';
7278           emitcode (bp1, "");
7279           bp1 = bp;
7280         }
7281       else
7282         {
7283           /* Add \n for labels, not dirs such as c:\mydir */
7284           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7285             {
7286               bp++;
7287               *bp = '\0';
7288               bp++;
7289               emitcode (bp1, "");
7290               bp1 = bp;
7291             }
7292           else
7293             bp++;
7294         }
7295     }
7296   if (bp1 != bp)
7297     emitcode (bp1, "");
7298   /*     emitcode("",buffer); */
7299   _G.inLine -= (!options.asmpeep);
7300 }
7301
7302 /*-----------------------------------------------------------------*/
7303 /* genRRC - rotate right with carry                                */
7304 /*-----------------------------------------------------------------*/
7305 static void
7306 genRRC (iCode * ic)
7307 {
7308   operand *left, *result;
7309   int size, offset = 0;
7310   char *l;
7311
7312   D(emitcode (";     genRRC",""));
7313
7314   /* rotate right with carry */
7315   left = IC_LEFT (ic);
7316   result = IC_RESULT (ic);
7317   aopOp (left, ic, FALSE);
7318   aopOp (result, ic, FALSE);
7319
7320   /* move it to the result */
7321   size = AOP_SIZE (result);
7322   offset = size - 1;
7323   if (size == 1) { /* special case for 1 byte */
7324       l = aopGet (left, offset, FALSE, FALSE);
7325       MOVA (l);
7326       emitcode ("rr", "a");
7327       goto release;
7328   }
7329   /* no need to clear carry, bit7 will be written later */
7330   while (size--)
7331     {
7332       l = aopGet (left, offset, FALSE, FALSE);
7333       MOVA (l);
7334       emitcode ("rrc", "a");
7335       if (AOP_SIZE (result) > 1)
7336         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
7337     }
7338   /* now we need to put the carry into the
7339      highest order byte of the result */
7340   if (AOP_SIZE (result) > 1)
7341     {
7342       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7343       MOVA (l);
7344     }
7345   emitcode ("mov", "acc.7,c");
7346  release:
7347   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
7348   freeAsmop (left, NULL, ic, TRUE);
7349   freeAsmop (result, NULL, ic, TRUE);
7350 }
7351
7352 /*-----------------------------------------------------------------*/
7353 /* genRLC - generate code for rotate left with carry               */
7354 /*-----------------------------------------------------------------*/
7355 static void
7356 genRLC (iCode * ic)
7357 {
7358   operand *left, *result;
7359   int size, offset = 0;
7360   char *l;
7361
7362   D(emitcode (";     genRLC",""));
7363
7364   /* rotate right with carry */
7365   left = IC_LEFT (ic);
7366   result = IC_RESULT (ic);
7367   aopOp (left, ic, FALSE);
7368   aopOp (result, ic, FALSE);
7369
7370   /* move it to the result */
7371   size = AOP_SIZE (result);
7372   offset = 0;
7373   if (size--)
7374     {
7375       l = aopGet (left, offset, FALSE, FALSE);
7376       MOVA (l);
7377       if (size == 0) { /* special case for 1 byte */
7378               emitcode("rl","a");
7379               goto release;
7380       }
7381       emitcode("rlc","a"); /* bit0 will be written later */
7382       if (AOP_SIZE (result) > 1)
7383         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7384       while (size--)
7385         {
7386           l = aopGet (left, offset, FALSE, FALSE);
7387           MOVA (l);
7388           emitcode ("rlc", "a");
7389           if (AOP_SIZE (result) > 1)
7390             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7391         }
7392     }
7393   /* now we need to put the carry into the
7394      highest order byte of the result */
7395   if (AOP_SIZE (result) > 1)
7396     {
7397       l = aopGet (result, 0, FALSE, FALSE);
7398       MOVA (l);
7399     }
7400   emitcode ("mov", "acc.0,c");
7401  release:
7402   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7403   freeAsmop (left, NULL, ic, TRUE);
7404   freeAsmop (result, NULL, ic, TRUE);
7405 }
7406
7407 /*-----------------------------------------------------------------*/
7408 /* genGetHbit - generates code get highest order bit               */
7409 /*-----------------------------------------------------------------*/
7410 static void
7411 genGetHbit (iCode * ic)
7412 {
7413   operand *left, *result;
7414
7415   D(emitcode (";     genGetHbit",""));
7416
7417   left = IC_LEFT (ic);
7418   result = IC_RESULT (ic);
7419   aopOp (left, ic, FALSE);
7420   aopOp (result, ic, FALSE);
7421
7422   /* get the highest order byte into a */
7423   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7424   if (AOP_TYPE (result) == AOP_CRY)
7425     {
7426       emitcode ("rlc", "a");
7427       outBitC (result);
7428     }
7429   else
7430     {
7431       emitcode ("rl", "a");
7432       emitcode ("anl", "a,#0x01");
7433       outAcc (result);
7434     }
7435
7436
7437   freeAsmop (left, NULL, ic, TRUE);
7438   freeAsmop (result, NULL, ic, TRUE);
7439 }
7440
7441 /*-----------------------------------------------------------------*/
7442 /* genGetAbit - generates code get a single bit                    */
7443 /*-----------------------------------------------------------------*/
7444 static void
7445 genGetAbit (iCode * ic)
7446 {
7447   operand *left, *right, *result;
7448   int shCount;
7449
7450   D(emitcode (";     genGetAbit",""));
7451
7452   left = IC_LEFT (ic);
7453   right = IC_RIGHT (ic);
7454   result = IC_RESULT (ic);
7455   aopOp (left, ic, FALSE);
7456   aopOp (right, ic, FALSE);
7457   aopOp (result, ic, FALSE);
7458
7459   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7460
7461   /* get the needed byte into a */
7462   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7463   shCount %= 8;
7464   if (AOP_TYPE (result) == AOP_CRY)
7465     {
7466       if ((shCount) == 7)
7467           emitcode ("rlc", "a");
7468       else if ((shCount) == 0)
7469           emitcode ("rrc", "a");
7470       else
7471           emitcode ("mov", "c,acc[%d]", shCount);
7472       outBitC (result);
7473     }
7474   else
7475     {
7476       switch (shCount)
7477         {
7478         case 2:
7479           emitcode ("rr", "a");
7480           //fallthrough
7481         case 1:
7482           emitcode ("rr", "a");
7483           //fallthrough
7484         case 0:
7485           emitcode ("anl", "a,#0x01");
7486           break;
7487         case 3:
7488         case 5:
7489           emitcode ("mov", "c,acc[%d]", shCount);
7490           emitcode ("clr", "a");
7491           emitcode ("rlc", "a");
7492           break;
7493         case 4:
7494           emitcode ("swap", "a");
7495           emitcode ("anl", "a,#0x01");
7496           break;
7497         case 6:
7498           emitcode ("rl", "a");
7499           //fallthrough
7500         case 7:
7501           emitcode ("rl", "a");
7502           emitcode ("anl", "a,#0x01");
7503           break;
7504         }
7505       outAcc (result);
7506     }
7507
7508   freeAsmop (left, NULL, ic, TRUE);
7509   freeAsmop (right, NULL, ic, TRUE);
7510   freeAsmop (result, NULL, ic, TRUE);
7511 }
7512
7513 /*-----------------------------------------------------------------*/
7514 /* genGetByte - generates code get a single byte                   */
7515 /*-----------------------------------------------------------------*/
7516 static void
7517 genGetByte (iCode * ic)
7518 {
7519   operand *left, *right, *result;
7520   int offset;
7521
7522   D(emitcode (";     genGetByte",""));
7523
7524   left = IC_LEFT (ic);
7525   right = IC_RIGHT (ic);
7526   result = IC_RESULT (ic);
7527   aopOp (left, ic, FALSE);
7528   aopOp (right, ic, FALSE);
7529   aopOp (result, ic, FALSE);
7530
7531   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7532   aopPut (result,
7533           aopGet (left, offset, FALSE, FALSE),
7534           0,
7535           isOperandVolatile (result, FALSE));
7536
7537   freeAsmop (left, NULL, ic, TRUE);
7538   freeAsmop (right, NULL, ic, TRUE);
7539   freeAsmop (result, NULL, ic, TRUE);
7540 }
7541
7542 /*-----------------------------------------------------------------*/
7543 /* genGetWord - generates code get two bytes                       */
7544 /*-----------------------------------------------------------------*/
7545 static void
7546 genGetWord (iCode * ic)
7547 {
7548   operand *left, *right, *result;
7549   int offset;
7550
7551   D(emitcode (";     genGetWord",""));
7552
7553   left = IC_LEFT (ic);
7554   right = IC_RIGHT (ic);
7555   result = IC_RESULT (ic);
7556   aopOp (left, ic, FALSE);
7557   aopOp (right, ic, FALSE);
7558   aopOp (result, ic, FALSE);
7559
7560   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7561   aopPut (result,
7562           aopGet (left, offset, FALSE, FALSE),
7563           0,
7564           isOperandVolatile (result, FALSE));
7565   aopPut (result,
7566           aopGet (left, offset+1, FALSE, FALSE),
7567           1,
7568           isOperandVolatile (result, FALSE));
7569
7570   freeAsmop (left, NULL, ic, TRUE);
7571   freeAsmop (right, NULL, ic, TRUE);
7572   freeAsmop (result, NULL, ic, TRUE);
7573 }
7574
7575 /*-----------------------------------------------------------------*/
7576 /* genSwap - generates code to swap nibbles or bytes               */
7577 /*-----------------------------------------------------------------*/
7578 static void
7579 genSwap (iCode * ic)
7580 {
7581   operand *left, *result;
7582
7583   D(emitcode (";     genSwap",""));
7584
7585   left = IC_LEFT (ic);
7586   result = IC_RESULT (ic);
7587   aopOp (left, ic, FALSE);
7588   aopOp (result, ic, FALSE);
7589
7590   switch (AOP_SIZE (left))
7591     {
7592     case 1: /* swap nibbles in byte */
7593       MOVA (aopGet (left, 0, FALSE, FALSE));
7594       emitcode ("swap", "a");
7595       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7596       break;
7597     case 2: /* swap bytes in word */
7598       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7599         {
7600           MOVA (aopGet (left, 0, FALSE, FALSE));
7601           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7602                   0, isOperandVolatile (result, FALSE));
7603           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7604         }
7605       else if (operandsEqu (left, result))
7606         {
7607           char * reg = "a";
7608           bool pushedB = FALSE, leftInB = FALSE;
7609
7610           MOVA (aopGet (left, 0, FALSE, FALSE));
7611           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7612             {
7613               pushedB = pushB ();
7614               emitcode ("mov", "b,a");
7615               reg = "b";
7616               leftInB = TRUE;
7617             }
7618           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7619                   0, isOperandVolatile (result, FALSE));
7620           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7621
7622           if (leftInB)
7623             popB (pushedB);
7624         }
7625       else
7626         {
7627           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7628                   0, isOperandVolatile (result, FALSE));
7629           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7630                   1, isOperandVolatile (result, FALSE));
7631         }
7632       break;
7633     default:
7634       wassertl(FALSE, "unsupported SWAP operand size");
7635     }
7636
7637   freeAsmop (left, NULL, ic, TRUE);
7638   freeAsmop (result, NULL, ic, TRUE);
7639 }
7640
7641
7642 /*-----------------------------------------------------------------*/
7643 /* AccRol - rotate left accumulator by known count                 */
7644 /*-----------------------------------------------------------------*/
7645 static void
7646 AccRol (int shCount)
7647 {
7648   shCount &= 0x0007;            // shCount : 0..7
7649
7650   switch (shCount)
7651     {
7652     case 0:
7653       break;
7654     case 1:
7655       emitcode ("rl", "a");
7656       break;
7657     case 2:
7658       emitcode ("rl", "a");
7659       emitcode ("rl", "a");
7660       break;
7661     case 3:
7662       emitcode ("swap", "a");
7663       emitcode ("rr", "a");
7664       break;
7665     case 4:
7666       emitcode ("swap", "a");
7667       break;
7668     case 5:
7669       emitcode ("swap", "a");
7670       emitcode ("rl", "a");
7671       break;
7672     case 6:
7673       emitcode ("rr", "a");
7674       emitcode ("rr", "a");
7675       break;
7676     case 7:
7677       emitcode ("rr", "a");
7678       break;
7679     }
7680 }
7681
7682 /*-----------------------------------------------------------------*/
7683 /* AccLsh - left shift accumulator by known count                  */
7684 /*-----------------------------------------------------------------*/
7685 static void
7686 AccLsh (int shCount)
7687 {
7688   if (shCount != 0)
7689     {
7690       if (shCount == 1)
7691         emitcode ("add", "a,acc");
7692       else if (shCount == 2)
7693         {
7694           emitcode ("add", "a,acc");
7695           emitcode ("add", "a,acc");
7696         }
7697       else
7698         {
7699           /* rotate left accumulator */
7700           AccRol (shCount);
7701           /* and kill the lower order bits */
7702           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7703         }
7704     }
7705 }
7706
7707 /*-----------------------------------------------------------------*/
7708 /* AccRsh - right shift accumulator by known count                 */
7709 /*-----------------------------------------------------------------*/
7710 static void
7711 AccRsh (int shCount)
7712 {
7713   if (shCount != 0)
7714     {
7715       if (shCount == 1)
7716         {
7717           CLRC;
7718           emitcode ("rrc", "a");
7719         }
7720       else
7721         {
7722           /* rotate right accumulator */
7723           AccRol (8 - shCount);
7724           /* and kill the higher order bits */
7725           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7726         }
7727     }
7728 }
7729
7730 /*-----------------------------------------------------------------*/
7731 /* AccSRsh - signed right shift accumulator by known count                 */
7732 /*-----------------------------------------------------------------*/
7733 static void
7734 AccSRsh (int shCount)
7735 {
7736   symbol *tlbl;
7737   if (shCount != 0)
7738     {
7739       if (shCount == 1)
7740         {
7741           emitcode ("mov", "c,acc.7");
7742           emitcode ("rrc", "a");
7743         }
7744       else if (shCount == 2)
7745         {
7746           emitcode ("mov", "c,acc.7");
7747           emitcode ("rrc", "a");
7748           emitcode ("mov", "c,acc.7");
7749           emitcode ("rrc", "a");
7750         }
7751       else
7752         {
7753           tlbl = newiTempLabel (NULL);
7754           /* rotate right accumulator */
7755           AccRol (8 - shCount);
7756           /* and kill the higher order bits */
7757           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7758           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7759           emitcode ("orl", "a,#0x%02x",
7760                     (unsigned char) ~SRMask[shCount]);
7761           emitcode ("", "%05d$:", tlbl->key + 100);
7762         }
7763     }
7764 }
7765
7766 /*-----------------------------------------------------------------*/
7767 /* shiftR1Left2Result - shift right one byte from left to result   */
7768 /*-----------------------------------------------------------------*/
7769 static void
7770 shiftR1Left2Result (operand * left, int offl,
7771                     operand * result, int offr,
7772                     int shCount, int sign)
7773 {
7774   MOVA (aopGet (left, offl, FALSE, FALSE));
7775   /* shift right accumulator */
7776   if (sign)
7777     AccSRsh (shCount);
7778   else
7779     AccRsh (shCount);
7780   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7781 }
7782
7783 /*-----------------------------------------------------------------*/
7784 /* shiftL1Left2Result - shift left one byte from left to result    */
7785 /*-----------------------------------------------------------------*/
7786 static void
7787 shiftL1Left2Result (operand * left, int offl,
7788                     operand * result, int offr, int shCount)
7789 {
7790   char *l;
7791   l = aopGet (left, offl, FALSE, FALSE);
7792   MOVA (l);
7793   /* shift left accumulator */
7794   AccLsh (shCount);
7795   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7796 }
7797
7798 /*-----------------------------------------------------------------*/
7799 /* movLeft2Result - move byte from left to result                  */
7800 /*-----------------------------------------------------------------*/
7801 static void
7802 movLeft2Result (operand * left, int offl,
7803                 operand * result, int offr, int sign)
7804 {
7805   char *l;
7806   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7807     {
7808       l = aopGet (left, offl, FALSE, FALSE);
7809
7810       if (*l == '@' && (IS_AOP_PREG (result)))
7811         {
7812           emitcode ("mov", "a,%s", l);
7813           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7814         }
7815       else
7816         {
7817           if (!sign)
7818             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7819           else
7820             {
7821               /* MSB sign in acc.7 ! */
7822               if (getDataSize (left) == offl + 1)
7823                 {
7824                   MOVA (l);
7825                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7826                 }
7827             }
7828         }
7829     }
7830 }
7831
7832 /*-----------------------------------------------------------------*/
7833 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7834 /*-----------------------------------------------------------------*/
7835 static void
7836 AccAXRrl1 (char *x)
7837 {
7838   emitcode ("rrc", "a");
7839   emitcode ("xch", "a,%s", x);
7840   emitcode ("rrc", "a");
7841   emitcode ("xch", "a,%s", x);
7842 }
7843
7844 /*-----------------------------------------------------------------*/
7845 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7846 /*-----------------------------------------------------------------*/
7847 static void
7848 AccAXLrl1 (char *x)
7849 {
7850   emitcode ("xch", "a,%s", x);
7851   emitcode ("rlc", "a");
7852   emitcode ("xch", "a,%s", x);
7853   emitcode ("rlc", "a");
7854 }
7855
7856 /*-----------------------------------------------------------------*/
7857 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7858 /*-----------------------------------------------------------------*/
7859 static void
7860 AccAXLsh1 (char *x)
7861 {
7862   emitcode ("xch", "a,%s", x);
7863   emitcode ("add", "a,acc");
7864   emitcode ("xch", "a,%s", x);
7865   emitcode ("rlc", "a");
7866 }
7867
7868 /*-----------------------------------------------------------------*/
7869 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7870 /*-----------------------------------------------------------------*/
7871 static void
7872 AccAXLsh (char *x, int shCount)
7873 {
7874   switch (shCount)
7875     {
7876     case 0:
7877       break;
7878     case 1:
7879       AccAXLsh1 (x);
7880       break;
7881     case 2:
7882       AccAXLsh1 (x);
7883       AccAXLsh1 (x);
7884       break;
7885     case 3:
7886     case 4:
7887     case 5:                     // AAAAABBB:CCCCCDDD
7888
7889       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7890
7891       emitcode ("anl", "a,#0x%02x",
7892                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7893
7894       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7895
7896       AccRol (shCount);         // DDDCCCCC:BBB00000
7897
7898       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7899
7900       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7901
7902       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7903
7904       emitcode ("anl", "a,#0x%02x",
7905                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7906
7907       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7908
7909       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7910
7911       break;
7912     case 6:                     // AAAAAABB:CCCCCCDD
7913       emitcode ("anl", "a,#0x%02x",
7914                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7915       emitcode ("mov", "c,acc.0");      // c = B
7916       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7917 #if 0 // REMOVE ME
7918       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7919       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7920 #else
7921       emitcode("rrc","a");
7922       emitcode("xch","a,%s", x);
7923       emitcode("rrc","a");
7924       emitcode("mov","c,acc.0"); //<< get correct bit
7925       emitcode("xch","a,%s", x);
7926
7927       emitcode("rrc","a");
7928       emitcode("xch","a,%s", x);
7929       emitcode("rrc","a");
7930       emitcode("xch","a,%s", x);
7931 #endif
7932       break;
7933     case 7:                     // a:x <<= 7
7934
7935       emitcode ("anl", "a,#0x%02x",
7936                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7937
7938       emitcode ("mov", "c,acc.0");      // c = B
7939
7940       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7941
7942       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7943
7944       break;
7945     default:
7946       break;
7947     }
7948 }
7949
7950 /*-----------------------------------------------------------------*/
7951 /* AccAXRsh - right shift a:x known count (0..7)                   */
7952 /*-----------------------------------------------------------------*/
7953 static void
7954 AccAXRsh (char *x, int shCount)
7955 {
7956   switch (shCount)
7957     {
7958     case 0:
7959       break;
7960     case 1:
7961       CLRC;
7962       AccAXRrl1 (x);            // 0->a:x
7963
7964       break;
7965     case 2:
7966       CLRC;
7967       AccAXRrl1 (x);            // 0->a:x
7968
7969       CLRC;
7970       AccAXRrl1 (x);            // 0->a:x
7971
7972       break;
7973     case 3:
7974     case 4:
7975     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7976
7977       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7978
7979       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7980
7981       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7982
7983       emitcode ("anl", "a,#0x%02x",
7984                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7985
7986       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7987
7988       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7989
7990       emitcode ("anl", "a,#0x%02x",
7991                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7992
7993       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7994
7995       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7996
7997       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7998
7999       break;
8000     case 6:                     // AABBBBBB:CCDDDDDD
8001
8002       emitcode ("mov", "c,acc.7");
8003       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8004
8005       emitcode ("mov", "c,acc.7");
8006       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8007
8008       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8009
8010       emitcode ("anl", "a,#0x%02x",
8011                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8012
8013       break;
8014     case 7:                     // ABBBBBBB:CDDDDDDD
8015
8016       emitcode ("mov", "c,acc.7");      // c = A
8017
8018       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8019
8020       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8021
8022       emitcode ("anl", "a,#0x%02x",
8023                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8024
8025       break;
8026     default:
8027       break;
8028     }
8029 }
8030
8031 /*-----------------------------------------------------------------*/
8032 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8033 /*-----------------------------------------------------------------*/
8034 static void
8035 AccAXRshS (char *x, int shCount)
8036 {
8037   symbol *tlbl;
8038   switch (shCount)
8039     {
8040     case 0:
8041       break;
8042     case 1:
8043       emitcode ("mov", "c,acc.7");
8044       AccAXRrl1 (x);            // s->a:x
8045
8046       break;
8047     case 2:
8048       emitcode ("mov", "c,acc.7");
8049       AccAXRrl1 (x);            // s->a:x
8050
8051       emitcode ("mov", "c,acc.7");
8052       AccAXRrl1 (x);            // s->a:x
8053
8054       break;
8055     case 3:
8056     case 4:
8057     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8058
8059       tlbl = newiTempLabel (NULL);
8060       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8061
8062       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8063
8064       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8065
8066       emitcode ("anl", "a,#0x%02x",
8067                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8068
8069       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8070
8071       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8072
8073       emitcode ("anl", "a,#0x%02x",
8074                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8075
8076       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8077
8078       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8079
8080       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8081
8082       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8083       emitcode ("orl", "a,#0x%02x",
8084                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8085
8086       emitcode ("", "%05d$:", tlbl->key + 100);
8087       break;                    // SSSSAAAA:BBBCCCCC
8088
8089     case 6:                     // AABBBBBB:CCDDDDDD
8090
8091       tlbl = newiTempLabel (NULL);
8092       emitcode ("mov", "c,acc.7");
8093       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8094
8095       emitcode ("mov", "c,acc.7");
8096       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8097
8098       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8099
8100       emitcode ("anl", "a,#0x%02x",
8101                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8102
8103       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8104       emitcode ("orl", "a,#0x%02x",
8105                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8106
8107       emitcode ("", "%05d$:", tlbl->key + 100);
8108       break;
8109     case 7:                     // ABBBBBBB:CDDDDDDD
8110
8111       tlbl = newiTempLabel (NULL);
8112       emitcode ("mov", "c,acc.7");      // c = A
8113
8114       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8115
8116       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8117
8118       emitcode ("anl", "a,#0x%02x",
8119                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8120
8121       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8122       emitcode ("orl", "a,#0x%02x",
8123                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8124
8125       emitcode ("", "%05d$:", tlbl->key + 100);
8126       break;
8127     default:
8128       break;
8129     }
8130 }
8131
8132 /*-----------------------------------------------------------------*/
8133 /* shiftL2Left2Result - shift left two bytes from left to result   */
8134 /*-----------------------------------------------------------------*/
8135 static void
8136 shiftL2Left2Result (operand * left, int offl,
8137                     operand * result, int offr, int shCount)
8138 {
8139   char * x;
8140   bool pushedB = FALSE;
8141   bool usedB = FALSE;
8142
8143   if (sameRegs (AOP (result), AOP (left)) &&
8144       ((offl + MSB16) == offr))
8145     {
8146       /* don't crash result[offr] */
8147       MOVA (aopGet (left, offl, FALSE, FALSE));
8148       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8149       x = aopGet (result, offr, FALSE, FALSE);
8150     }
8151   else if (aopGetUsesAcc (result, offr))
8152     {
8153       movLeft2Result (left, offl, result, offr, 0);
8154       pushedB = pushB ();
8155       usedB = TRUE;
8156       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8157       MOVA (aopGet (result, offr, FALSE, FALSE));
8158       emitcode ("xch", "a,b");
8159       x = "b";
8160     }
8161   else
8162     {
8163       movLeft2Result (left, offl, result, offr, 0);
8164       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8165       x = aopGet (result, offr, FALSE, FALSE);
8166     }
8167   /* ax << shCount (x = lsb(result)) */
8168   AccAXLsh (x, shCount);
8169   if (usedB)
8170     {
8171       emitcode ("xch", "a,b");
8172       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8173       aopPut (result, "b", offr + MSB16, isOperandVolatile (result, FALSE));
8174       popB (pushedB);
8175     }
8176   else
8177     {
8178       aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8179     }
8180 }
8181
8182
8183 /*-----------------------------------------------------------------*/
8184 /* shiftR2Left2Result - shift right two bytes from left to result  */
8185 /*-----------------------------------------------------------------*/
8186 static void
8187 shiftR2Left2Result (operand * left, int offl,
8188                     operand * result, int offr,
8189                     int shCount, int sign)
8190 {
8191   char * x;
8192   bool pushedB = FALSE;
8193   bool usedB = FALSE;
8194
8195   if (sameRegs (AOP (result), AOP (left)) &&
8196       ((offl + MSB16) == offr))
8197     {
8198       /* don't crash result[offr] */
8199       MOVA (aopGet (left, offl, FALSE, FALSE));
8200       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8201       x = aopGet (result, offr, FALSE, FALSE);
8202     }
8203   else if (aopGetUsesAcc (result, offr))
8204     {
8205       movLeft2Result (left, offl, result, offr, 0);
8206       pushedB = pushB ();
8207       usedB = TRUE;
8208       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8209       MOVA (aopGet (result, offr, FALSE, FALSE));
8210       emitcode ("xch", "a,b");
8211       x = "b";
8212     }
8213   else
8214     {
8215       movLeft2Result (left, offl, result, offr, 0);
8216       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8217       x = aopGet (result, offr, FALSE, FALSE);
8218     }
8219   /* a:x >> shCount (x = lsb(result)) */
8220   if (sign)
8221     AccAXRshS (x, shCount);
8222   else
8223     AccAXRsh (x, shCount);
8224   if (usedB)
8225     {
8226       aopPut (result, "b", offr, isOperandVolatile (result, FALSE));
8227       popB (pushedB);
8228     }
8229   if (getDataSize (result) > 1)
8230     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8231 }
8232
8233 /*-----------------------------------------------------------------*/
8234 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8235 /*-----------------------------------------------------------------*/
8236 static void
8237 shiftLLeftOrResult (operand * left, int offl,
8238                     operand * result, int offr, int shCount)
8239 {
8240   MOVA (aopGet (left, offl, FALSE, FALSE));
8241   /* shift left accumulator */
8242   AccLsh (shCount);
8243   /* or with result */
8244   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8245   /* back to result */
8246   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8247 }
8248
8249 /*-----------------------------------------------------------------*/
8250 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8251 /*-----------------------------------------------------------------*/
8252 static void
8253 shiftRLeftOrResult (operand * left, int offl,
8254                     operand * result, int offr, int shCount)
8255 {
8256   MOVA (aopGet (left, offl, FALSE, FALSE));
8257   /* shift right accumulator */
8258   AccRsh (shCount);
8259   /* or with result */
8260   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8261   /* back to result */
8262   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8263 }
8264
8265 /*-----------------------------------------------------------------*/
8266 /* genlshOne - left shift a one byte quantity by known count       */
8267 /*-----------------------------------------------------------------*/
8268 static void
8269 genlshOne (operand * result, operand * left, int shCount)
8270 {
8271   D(emitcode (";     genlshOne",""));
8272
8273   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8274 }
8275
8276 /*-----------------------------------------------------------------*/
8277 /* genlshTwo - left shift two bytes by known amount != 0           */
8278 /*-----------------------------------------------------------------*/
8279 static void
8280 genlshTwo (operand * result, operand * left, int shCount)
8281 {
8282   int size;
8283
8284   D(emitcode (";     genlshTwo",""));
8285
8286   size = getDataSize (result);
8287
8288   /* if shCount >= 8 */
8289   if (shCount >= 8)
8290     {
8291       shCount -= 8;
8292
8293       if (size > 1)
8294         {
8295           if (shCount)
8296             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8297           else
8298             movLeft2Result (left, LSB, result, MSB16, 0);
8299         }
8300       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8301     }
8302
8303   /*  1 <= shCount <= 7 */
8304   else
8305     {
8306       if (size == 1)
8307         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8308       else
8309         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8310     }
8311 }
8312
8313 /*-----------------------------------------------------------------*/
8314 /* shiftLLong - shift left one long from left to result            */
8315 /* offl = LSB or MSB16                                             */
8316 /*-----------------------------------------------------------------*/
8317 static void
8318 shiftLLong (operand * left, operand * result, int offr)
8319 {
8320   char *l;
8321   int size = AOP_SIZE (result);
8322
8323   if (size >= LSB + offr)
8324     {
8325       l = aopGet (left, LSB, FALSE, FALSE);
8326       MOVA (l);
8327       emitcode ("add", "a,acc");
8328       if (sameRegs (AOP (left), AOP (result)) &&
8329           size >= MSB16 + offr && offr != LSB)
8330         emitcode ("xch", "a,%s",
8331                   aopGet (left, LSB + offr, FALSE, FALSE));
8332       else
8333         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
8334     }
8335
8336   if (size >= MSB16 + offr)
8337     {
8338       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8339         {
8340           l = aopGet (left, MSB16, FALSE, FALSE);
8341           MOVA (l);
8342         }
8343       emitcode ("rlc", "a");
8344       if (sameRegs (AOP (left), AOP (result)) &&
8345           size >= MSB24 + offr && offr != LSB)
8346         emitcode ("xch", "a,%s",
8347                   aopGet (left, MSB16 + offr, FALSE, FALSE));
8348       else
8349         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
8350     }
8351
8352   if (size >= MSB24 + offr)
8353     {
8354       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8355         {
8356           l = aopGet (left, MSB24, FALSE, FALSE);
8357           MOVA (l);
8358         }
8359       emitcode ("rlc", "a");
8360       if (sameRegs (AOP (left), AOP (result)) &&
8361           size >= MSB32 + offr && offr != LSB)
8362         emitcode ("xch", "a,%s",
8363                   aopGet (left, MSB24 + offr, FALSE, FALSE));
8364       else
8365         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
8366     }
8367
8368   if (size > MSB32 + offr)
8369     {
8370       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8371         {
8372           l = aopGet (left, MSB32, FALSE, FALSE);
8373           MOVA (l);
8374         }
8375       emitcode ("rlc", "a");
8376       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
8377     }
8378   if (offr != LSB)
8379     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8380 }
8381
8382 /*-----------------------------------------------------------------*/
8383 /* genlshFour - shift four byte by a known amount != 0             */
8384 /*-----------------------------------------------------------------*/
8385 static void
8386 genlshFour (operand * result, operand * left, int shCount)
8387 {
8388   int size;
8389
8390   D(emitcode (";     genlshFour",""));
8391
8392   size = AOP_SIZE (result);
8393
8394   /* if shifting more that 3 bytes */
8395   if (shCount >= 24)
8396     {
8397       shCount -= 24;
8398       if (shCount)
8399         /* lowest order of left goes to the highest
8400            order of the destination */
8401         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8402       else
8403         movLeft2Result (left, LSB, result, MSB32, 0);
8404       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8405       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8406       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
8407       return;
8408     }
8409
8410   /* more than two bytes */
8411   else if (shCount >= 16)
8412     {
8413       /* lower order two bytes goes to higher order two bytes */
8414       shCount -= 16;
8415       /* if some more remaining */
8416       if (shCount)
8417         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8418       else
8419         {
8420           movLeft2Result (left, MSB16, result, MSB32, 0);
8421           movLeft2Result (left, LSB, result, MSB24, 0);
8422         }
8423       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8424       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8425       return;
8426     }
8427
8428   /* if more than 1 byte */
8429   else if (shCount >= 8)
8430     {
8431       /* lower order three bytes goes to higher order  three bytes */
8432       shCount -= 8;
8433       if (size == 2)
8434         {
8435           if (shCount)
8436             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8437           else
8438             movLeft2Result (left, LSB, result, MSB16, 0);
8439         }
8440       else
8441         {                       /* size = 4 */
8442           if (shCount == 0)
8443             {
8444               movLeft2Result (left, MSB24, result, MSB32, 0);
8445               movLeft2Result (left, MSB16, result, MSB24, 0);
8446               movLeft2Result (left, LSB, result, MSB16, 0);
8447               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8448             }
8449           else if (shCount == 1)
8450             shiftLLong (left, result, MSB16);
8451           else
8452             {
8453               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8454               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8455               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8456               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8457             }
8458         }
8459     }
8460
8461   /* 1 <= shCount <= 7 */
8462   else if (shCount <= 2)
8463     {
8464       shiftLLong (left, result, LSB);
8465       if (shCount == 2)
8466         shiftLLong (result, result, LSB);
8467     }
8468   /* 3 <= shCount <= 7, optimize */
8469   else
8470     {
8471       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8472       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8473       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8474     }
8475 }
8476
8477 /*-----------------------------------------------------------------*/
8478 /* genLeftShiftLiteral - left shifting by known count              */
8479 /*-----------------------------------------------------------------*/
8480 static void
8481 genLeftShiftLiteral (operand * left,
8482                      operand * right,
8483                      operand * result,
8484                      iCode * ic)
8485 {
8486   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8487   int size;
8488
8489   D(emitcode (";     genLeftShiftLiteral",""));
8490
8491   freeAsmop (right, NULL, ic, TRUE);
8492
8493   aopOp (left, ic, FALSE);
8494   aopOp (result, ic, FALSE);
8495
8496   size = getSize (operandType (result));
8497
8498 #if VIEW_SIZE
8499   emitcode ("; shift left ", "result %d, left %d", size,
8500             AOP_SIZE (left));
8501 #endif
8502
8503   /* I suppose that the left size >= result size */
8504   if (shCount == 0)
8505     {
8506       while (size--)
8507         {
8508           movLeft2Result (left, size, result, size, 0);
8509         }
8510     }
8511
8512   else if (shCount >= (size * 8))
8513     while (size--)
8514       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
8515   else
8516     {
8517       switch (size)
8518         {
8519         case 1:
8520           genlshOne (result, left, shCount);
8521           break;
8522
8523         case 2:
8524           genlshTwo (result, left, shCount);
8525           break;
8526
8527         case 4:
8528           genlshFour (result, left, shCount);
8529           break;
8530         default:
8531           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8532                   "*** ack! mystery literal shift!\n");
8533           break;
8534         }
8535     }
8536   freeAsmop (left, NULL, ic, TRUE);
8537   freeAsmop (result, NULL, ic, TRUE);
8538 }
8539
8540 /*-----------------------------------------------------------------*/
8541 /* genLeftShift - generates code for left shifting                 */
8542 /*-----------------------------------------------------------------*/
8543 static void
8544 genLeftShift (iCode * ic)
8545 {
8546   operand *left, *right, *result;
8547   int size, offset;
8548   char *l;
8549   symbol *tlbl, *tlbl1;
8550   bool pushedB;
8551
8552   D(emitcode (";     genLeftShift",""));
8553
8554   right = IC_RIGHT (ic);
8555   left = IC_LEFT (ic);
8556   result = IC_RESULT (ic);
8557
8558   aopOp (right, ic, FALSE);
8559
8560   /* if the shift count is known then do it
8561      as efficiently as possible */
8562   if (AOP_TYPE (right) == AOP_LIT)
8563     {
8564       genLeftShiftLiteral (left, right, result, ic);
8565       return;
8566     }
8567
8568   /* shift count is unknown then we have to form
8569      a loop get the loop count in B : Note: we take
8570      only the lower order byte since shifting
8571      more that 32 bits make no sense anyway, ( the
8572      largest size of an object can be only 32 bits ) */
8573
8574   pushedB = pushB ();
8575   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8576   emitcode ("inc", "b");
8577   freeAsmop (right, NULL, ic, TRUE);
8578   aopOp (left, ic, FALSE);
8579   aopOp (result, ic, FALSE);
8580
8581   /* now move the left to the result if they are not the same */
8582   if (!sameRegs (AOP (left), AOP (result)) &&
8583       AOP_SIZE (result) > 1)
8584     {
8585
8586       size = AOP_SIZE (result);
8587       offset = 0;
8588       while (size--)
8589         {
8590           l = aopGet (left, offset, FALSE, TRUE);
8591           if (*l == '@' && (IS_AOP_PREG (result)))
8592             {
8593
8594               emitcode ("mov", "a,%s", l);
8595               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8596             }
8597           else
8598             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8599           offset++;
8600         }
8601     }
8602
8603   tlbl = newiTempLabel (NULL);
8604   size = AOP_SIZE (result);
8605   offset = 0;
8606   tlbl1 = newiTempLabel (NULL);
8607
8608   /* if it is only one byte then */
8609   if (size == 1)
8610     {
8611       symbol *tlbl1 = newiTempLabel (NULL);
8612
8613       l = aopGet (left, 0, FALSE, FALSE);
8614       MOVA (l);
8615       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8616       emitcode ("", "%05d$:", tlbl->key + 100);
8617       emitcode ("add", "a,acc");
8618       emitcode ("", "%05d$:", tlbl1->key + 100);
8619       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8620       popB (pushedB);
8621       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8622       goto release;
8623     }
8624
8625   reAdjustPreg (AOP (result));
8626
8627   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8628   emitcode ("", "%05d$:", tlbl->key + 100);
8629   l = aopGet (result, offset, FALSE, FALSE);
8630   MOVA (l);
8631   emitcode ("add", "a,acc");
8632   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8633   while (--size)
8634     {
8635       l = aopGet (result, offset, FALSE, FALSE);
8636       MOVA (l);
8637       emitcode ("rlc", "a");
8638       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8639     }
8640   reAdjustPreg (AOP (result));
8641
8642   emitcode ("", "%05d$:", tlbl1->key + 100);
8643   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8644   popB (pushedB);
8645 release:
8646   freeAsmop (left, NULL, ic, TRUE);
8647   freeAsmop (result, NULL, ic, TRUE);
8648 }
8649
8650 /*-----------------------------------------------------------------*/
8651 /* genrshOne - right shift a one byte quantity by known count      */
8652 /*-----------------------------------------------------------------*/
8653 static void
8654 genrshOne (operand * result, operand * left,
8655            int shCount, int sign)
8656 {
8657   D(emitcode (";     genrshOne",""));
8658
8659   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8660 }
8661
8662 /*-----------------------------------------------------------------*/
8663 /* genrshTwo - right shift two bytes by known amount != 0          */
8664 /*-----------------------------------------------------------------*/
8665 static void
8666 genrshTwo (operand * result, operand * left,
8667            int shCount, int sign)
8668 {
8669   D(emitcode (";     genrshTwo",""));
8670
8671   /* if shCount >= 8 */
8672   if (shCount >= 8)
8673     {
8674       shCount -= 8;
8675       if (shCount)
8676         shiftR1Left2Result (left, MSB16, result, LSB,
8677                             shCount, sign);
8678       else
8679         movLeft2Result (left, MSB16, result, LSB, sign);
8680       addSign (result, MSB16, sign);
8681     }
8682
8683   /*  1 <= shCount <= 7 */
8684   else
8685     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8686 }
8687
8688 /*-----------------------------------------------------------------*/
8689 /* shiftRLong - shift right one long from left to result           */
8690 /* offl = LSB or MSB16                                             */
8691 /*-----------------------------------------------------------------*/
8692 static void
8693 shiftRLong (operand * left, int offl,
8694             operand * result, int sign)
8695 {
8696   int isSameRegs=sameRegs(AOP(left),AOP(result));
8697
8698   if (isSameRegs && offl>1) {
8699     // we are in big trouble, but this shouldn't happen
8700     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8701   }
8702
8703   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8704
8705   if (offl==MSB16) {
8706     // shift is > 8
8707     if (sign) {
8708       emitcode ("rlc", "a");
8709       emitcode ("subb", "a,acc");
8710       if (isSameRegs)
8711         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8712       else {
8713         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8714         MOVA (aopGet (left, MSB32, FALSE, FALSE));
8715       }
8716     } else {
8717       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8718     }
8719   }
8720
8721   if (!sign) {
8722     emitcode ("clr", "c");
8723   } else {
8724     emitcode ("mov", "c,acc.7");
8725   }
8726
8727   emitcode ("rrc", "a");
8728
8729   if (isSameRegs && offl==MSB16) {
8730     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8731   } else {
8732     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8733     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8734   }
8735
8736   emitcode ("rrc", "a");
8737   if (isSameRegs && offl==1) {
8738     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8739   } else {
8740     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8741     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8742   }
8743   emitcode ("rrc", "a");
8744   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8745
8746   if (offl == LSB)
8747     {
8748       MOVA (aopGet (left, LSB, FALSE, FALSE));
8749       emitcode ("rrc", "a");
8750       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8751     }
8752 }
8753
8754 /*-----------------------------------------------------------------*/
8755 /* genrshFour - shift four byte by a known amount != 0             */
8756 /*-----------------------------------------------------------------*/
8757 static void
8758 genrshFour (operand * result, operand * left,
8759             int shCount, int sign)
8760 {
8761   D(emitcode (";     genrshFour",""));
8762
8763   /* if shifting more that 3 bytes */
8764   if (shCount >= 24)
8765     {
8766       shCount -= 24;
8767       if (shCount)
8768         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8769       else
8770         movLeft2Result (left, MSB32, result, LSB, sign);
8771       addSign (result, MSB16, sign);
8772     }
8773   else if (shCount >= 16)
8774     {
8775       shCount -= 16;
8776       if (shCount)
8777         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8778       else
8779         {
8780           movLeft2Result (left, MSB24, result, LSB, 0);
8781           movLeft2Result (left, MSB32, result, MSB16, sign);
8782         }
8783       addSign (result, MSB24, sign);
8784     }
8785   else if (shCount >= 8)
8786     {
8787       shCount -= 8;
8788       if (shCount == 1)
8789         shiftRLong (left, MSB16, result, sign);
8790       else if (shCount == 0)
8791         {
8792           movLeft2Result (left, MSB16, result, LSB, 0);
8793           movLeft2Result (left, MSB24, result, MSB16, 0);
8794           movLeft2Result (left, MSB32, result, MSB24, sign);
8795           addSign (result, MSB32, sign);
8796         }
8797       else
8798         {
8799           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8800           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8801           /* the last shift is signed */
8802           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8803           addSign (result, MSB32, sign);
8804         }
8805     }
8806   else
8807     {                           /* 1 <= shCount <= 7 */
8808       if (shCount <= 2)
8809         {
8810           shiftRLong (left, LSB, result, sign);
8811           if (shCount == 2)
8812             shiftRLong (result, LSB, result, sign);
8813         }
8814       else
8815         {
8816           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8817           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8818           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8819         }
8820     }
8821 }
8822
8823 /*-----------------------------------------------------------------*/
8824 /* genRightShiftLiteral - right shifting by known count            */
8825 /*-----------------------------------------------------------------*/
8826 static void
8827 genRightShiftLiteral (operand * left,
8828                       operand * right,
8829                       operand * result,
8830                       iCode * ic,
8831                       int sign)
8832 {
8833   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8834   int size;
8835
8836   D(emitcode (";     genRightShiftLiteral",""));
8837
8838   freeAsmop (right, NULL, ic, TRUE);
8839
8840   aopOp (left, ic, FALSE);
8841   aopOp (result, ic, FALSE);
8842
8843 #if VIEW_SIZE
8844   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8845             AOP_SIZE (left));
8846 #endif
8847
8848   size = getDataSize (left);
8849   /* test the LEFT size !!! */
8850
8851   /* I suppose that the left size >= result size */
8852   if (shCount == 0)
8853     {
8854       size = getDataSize (result);
8855       while (size--)
8856         movLeft2Result (left, size, result, size, 0);
8857     }
8858
8859   else if (shCount >= (size * 8))
8860     {
8861       if (sign) {
8862         /* get sign in acc.7 */
8863         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8864       }
8865       addSign (result, LSB, sign);
8866     }
8867   else
8868     {
8869       switch (size)
8870         {
8871         case 1:
8872           genrshOne (result, left, shCount, sign);
8873           break;
8874
8875         case 2:
8876           genrshTwo (result, left, shCount, sign);
8877           break;
8878
8879         case 4:
8880           genrshFour (result, left, shCount, sign);
8881           break;
8882         default:
8883           break;
8884         }
8885     }
8886   freeAsmop (left, NULL, ic, TRUE);
8887   freeAsmop (result, NULL, ic, TRUE);
8888 }
8889
8890 /*-----------------------------------------------------------------*/
8891 /* genSignedRightShift - right shift of signed number              */
8892 /*-----------------------------------------------------------------*/
8893 static void
8894 genSignedRightShift (iCode * ic)
8895 {
8896   operand *right, *left, *result;
8897   int size, offset;
8898   char *l;
8899   symbol *tlbl, *tlbl1;
8900   bool pushedB;
8901
8902   D(emitcode (";     genSignedRightShift",""));
8903
8904   /* we do it the hard way put the shift count in b
8905      and loop thru preserving the sign */
8906
8907   right = IC_RIGHT (ic);
8908   left = IC_LEFT (ic);
8909   result = IC_RESULT (ic);
8910
8911   aopOp (right, ic, FALSE);
8912
8913
8914   if (AOP_TYPE (right) == AOP_LIT)
8915     {
8916       genRightShiftLiteral (left, right, result, ic, 1);
8917       return;
8918     }
8919   /* shift count is unknown then we have to form
8920      a loop get the loop count in B : Note: we take
8921      only the lower order byte since shifting
8922      more that 32 bits make no sense anyway, ( the
8923      largest size of an object can be only 32 bits ) */
8924
8925   pushedB = pushB ();
8926   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8927   emitcode ("inc", "b");
8928   freeAsmop (right, NULL, ic, TRUE);
8929   aopOp (left, ic, FALSE);
8930   aopOp (result, ic, FALSE);
8931
8932   /* now move the left to the result if they are not the
8933      same */
8934   if (!sameRegs (AOP (left), AOP (result)) &&
8935       AOP_SIZE (result) > 1)
8936     {
8937
8938       size = AOP_SIZE (result);
8939       offset = 0;
8940       while (size--)
8941         {
8942           l = aopGet (left, offset, FALSE, TRUE);
8943           if (*l == '@' && IS_AOP_PREG (result))
8944             {
8945
8946               emitcode ("mov", "a,%s", l);
8947               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8948             }
8949           else
8950             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8951           offset++;
8952         }
8953     }
8954
8955   /* mov the highest order bit to OVR */
8956   tlbl = newiTempLabel (NULL);
8957   tlbl1 = newiTempLabel (NULL);
8958
8959   size = AOP_SIZE (result);
8960   offset = size - 1;
8961   MOVA (aopGet (left, offset, FALSE, FALSE));
8962   emitcode ("rlc", "a");
8963   emitcode ("mov", "ov,c");
8964   /* if it is only one byte then */
8965   if (size == 1)
8966     {
8967       l = aopGet (left, 0, FALSE, FALSE);
8968       MOVA (l);
8969       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8970       emitcode ("", "%05d$:", tlbl->key + 100);
8971       emitcode ("mov", "c,ov");
8972       emitcode ("rrc", "a");
8973       emitcode ("", "%05d$:", tlbl1->key + 100);
8974       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8975       popB (pushedB);
8976       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8977       goto release;
8978     }
8979
8980   reAdjustPreg (AOP (result));
8981   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8982   emitcode ("", "%05d$:", tlbl->key + 100);
8983   emitcode ("mov", "c,ov");
8984   while (size--)
8985     {
8986       l = aopGet (result, offset, FALSE, FALSE);
8987       MOVA (l);
8988       emitcode ("rrc", "a");
8989       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8990     }
8991   reAdjustPreg (AOP (result));
8992   emitcode ("", "%05d$:", tlbl1->key + 100);
8993   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8994   popB (pushedB);
8995
8996 release:
8997   freeAsmop (left, NULL, ic, TRUE);
8998   freeAsmop (result, NULL, ic, TRUE);
8999 }
9000
9001 /*-----------------------------------------------------------------*/
9002 /* genRightShift - generate code for right shifting                */
9003 /*-----------------------------------------------------------------*/
9004 static void
9005 genRightShift (iCode * ic)
9006 {
9007   operand *right, *left, *result;
9008   sym_link *letype;
9009   int size, offset;
9010   char *l;
9011   symbol *tlbl, *tlbl1;
9012   bool pushedB;
9013
9014   D(emitcode (";     genRightShift",""));
9015
9016   /* if signed then we do it the hard way preserve the
9017      sign bit moving it inwards */
9018   letype = getSpec (operandType (IC_LEFT (ic)));
9019
9020   if (!SPEC_USIGN (letype))
9021     {
9022       genSignedRightShift (ic);
9023       return;
9024     }
9025
9026   /* signed & unsigned types are treated the same : i.e. the
9027      signed is NOT propagated inwards : quoting from the
9028      ANSI - standard : "for E1 >> E2, is equivalent to division
9029      by 2**E2 if unsigned or if it has a non-negative value,
9030      otherwise the result is implementation defined ", MY definition
9031      is that the sign does not get propagated */
9032
9033   right = IC_RIGHT (ic);
9034   left = IC_LEFT (ic);
9035   result = IC_RESULT (ic);
9036
9037   aopOp (right, ic, FALSE);
9038
9039   /* if the shift count is known then do it
9040      as efficiently as possible */
9041   if (AOP_TYPE (right) == AOP_LIT)
9042     {
9043       genRightShiftLiteral (left, right, result, ic, 0);
9044       return;
9045     }
9046
9047   /* shift count is unknown then we have to form
9048      a loop get the loop count in B : Note: we take
9049      only the lower order byte since shifting
9050      more that 32 bits make no sense anyway, ( the
9051      largest size of an object can be only 32 bits ) */
9052
9053   pushedB = pushB ();
9054   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
9055   emitcode ("inc", "b");
9056   freeAsmop (right, NULL, ic, TRUE);
9057   aopOp (left, ic, FALSE);
9058   aopOp (result, ic, FALSE);
9059
9060   /* now move the left to the result if they are not the
9061      same */
9062   if (!sameRegs (AOP (left), AOP (result)) &&
9063       AOP_SIZE (result) > 1)
9064     {
9065
9066       size = AOP_SIZE (result);
9067       offset = 0;
9068       while (size--)
9069         {
9070           l = aopGet (left, offset, FALSE, TRUE);
9071           if (*l == '@' && IS_AOP_PREG (result))
9072             {
9073
9074               emitcode ("mov", "a,%s", l);
9075               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9076             }
9077           else
9078             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
9079           offset++;
9080         }
9081     }
9082
9083   tlbl = newiTempLabel (NULL);
9084   tlbl1 = newiTempLabel (NULL);
9085   size = AOP_SIZE (result);
9086   offset = size - 1;
9087
9088   /* if it is only one byte then */
9089   if (size == 1)
9090     {
9091       l = aopGet (left, 0, FALSE, FALSE);
9092       MOVA (l);
9093       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9094       emitcode ("", "%05d$:", tlbl->key + 100);
9095       CLRC;
9096       emitcode ("rrc", "a");
9097       emitcode ("", "%05d$:", tlbl1->key + 100);
9098       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9099       popB (pushedB);
9100       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9101       goto release;
9102     }
9103
9104   reAdjustPreg (AOP (result));
9105   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9106   emitcode ("", "%05d$:", tlbl->key + 100);
9107   CLRC;
9108   while (size--)
9109     {
9110       l = aopGet (result, offset, FALSE, FALSE);
9111       MOVA (l);
9112       emitcode ("rrc", "a");
9113       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9114     }
9115   reAdjustPreg (AOP (result));
9116
9117   emitcode ("", "%05d$:", tlbl1->key + 100);
9118   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9119   popB (pushedB);
9120
9121 release:
9122   freeAsmop (left, NULL, ic, TRUE);
9123   freeAsmop (result, NULL, ic, TRUE);
9124 }
9125
9126 /*-----------------------------------------------------------------*/
9127 /* emitPtrByteGet - emits code to get a byte into A through a      */
9128 /*                  pointer register (R0, R1, or DPTR). The        */
9129 /*                  original value of A can be preserved in B.     */
9130 /*-----------------------------------------------------------------*/
9131 static void
9132 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9133 {
9134   switch (p_type)
9135     {
9136     case IPOINTER:
9137     case POINTER:
9138       if (preserveAinB)
9139         emitcode ("mov", "b,a");
9140       emitcode ("mov", "a,@%s", rname);
9141       break;
9142
9143     case PPOINTER:
9144       if (preserveAinB)
9145         emitcode ("mov", "b,a");
9146       emitcode ("movx", "a,@%s", rname);
9147       break;
9148
9149     case FPOINTER:
9150       if (preserveAinB)
9151         emitcode ("mov", "b,a");
9152       emitcode ("movx", "a,@dptr");
9153       break;
9154
9155     case CPOINTER:
9156       if (preserveAinB)
9157         emitcode ("mov", "b,a");
9158       emitcode ("clr", "a");
9159       emitcode ("movc", "a,@a+dptr");
9160       break;
9161
9162     case GPOINTER:
9163       if (preserveAinB)
9164         {
9165           emitcode ("push", "b");
9166           emitcode ("push", "acc");
9167         }
9168       emitcode ("lcall", "__gptrget");
9169       if (preserveAinB)
9170         emitcode ("pop", "b");
9171       break;
9172     }
9173 }
9174
9175 /*-----------------------------------------------------------------*/
9176 /* emitPtrByteSet - emits code to set a byte from src through a    */
9177 /*                  pointer register (R0, R1, or DPTR).            */
9178 /*-----------------------------------------------------------------*/
9179 static void
9180 emitPtrByteSet (char *rname, int p_type, char *src)
9181 {
9182   switch (p_type)
9183     {
9184     case IPOINTER:
9185     case POINTER:
9186       if (*src=='@')
9187         {
9188           MOVA (src);
9189           emitcode ("mov", "@%s,a", rname);
9190         }
9191       else
9192         emitcode ("mov", "@%s,%s", rname, src);
9193       break;
9194
9195     case PPOINTER:
9196       MOVA (src);
9197       emitcode ("movx", "@%s,a", rname);
9198       break;
9199
9200     case FPOINTER:
9201       MOVA (src);
9202       emitcode ("movx", "@dptr,a");
9203       break;
9204
9205     case GPOINTER:
9206       MOVA (src);
9207       emitcode ("lcall", "__gptrput");
9208       break;
9209     }
9210 }
9211
9212 /*-----------------------------------------------------------------*/
9213 /* genUnpackBits - generates code for unpacking bits               */
9214 /*-----------------------------------------------------------------*/
9215 static void
9216 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9217 {
9218   int offset = 0;       /* result byte offset */
9219   int rsize;            /* result size */
9220   int rlen = 0;         /* remaining bitfield length */
9221   sym_link *etype;      /* bitfield type information */
9222   int blen;             /* bitfield length */
9223   int bstr;             /* bitfield starting bit within byte */
9224   char buffer[10];
9225
9226   D(emitcode (";     genUnpackBits",""));
9227
9228   etype = getSpec (operandType (result));
9229   rsize = getSize (operandType (result));
9230   blen = SPEC_BLEN (etype);
9231   bstr = SPEC_BSTR (etype);
9232
9233   if (ifx && blen <= 8)
9234     {
9235       emitPtrByteGet (rname, ptype, FALSE);
9236       if (blen == 1)
9237         {
9238           SNPRINTF (buffer, sizeof(buffer),
9239                     "acc.%d", bstr);
9240           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9241         }
9242       else
9243         {
9244           if (blen < 8)
9245             emitcode ("anl", "a,#0x%02x",
9246                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9247           genIfxJump (ifx, "a", NULL, NULL, NULL);
9248         }
9249       return;
9250     }
9251   wassert (!ifx);
9252
9253   /* If the bitfield length is less than a byte */
9254   if (blen < 8)
9255     {
9256       emitPtrByteGet (rname, ptype, FALSE);
9257       AccRsh (bstr);
9258       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9259       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9260       goto finish;
9261     }
9262
9263   /* Bit field did not fit in a byte. Copy all
9264      but the partial byte at the end.  */
9265   for (rlen=blen;rlen>=8;rlen-=8)
9266     {
9267       emitPtrByteGet (rname, ptype, FALSE);
9268       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9269       if (rlen>8)
9270         emitcode ("inc", "%s", rname);
9271     }
9272
9273   /* Handle the partial byte at the end */
9274   if (rlen)
9275     {
9276       emitPtrByteGet (rname, ptype, FALSE);
9277       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9278       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9279     }
9280
9281 finish:
9282   if (offset < rsize)
9283     {
9284       rsize -= offset;
9285       while (rsize--)
9286         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
9287     }
9288 }
9289
9290
9291 /*-----------------------------------------------------------------*/
9292 /* genDataPointerGet - generates code when ptr offset is known     */
9293 /*-----------------------------------------------------------------*/
9294 static void
9295 genDataPointerGet (operand * left,
9296                    operand * result,
9297                    iCode * ic)
9298 {
9299   char *l;
9300   char buffer[256];
9301   int size, offset = 0;
9302
9303   D(emitcode (";     genDataPointerGet",""));
9304
9305   aopOp (result, ic, TRUE);
9306
9307   /* get the string representation of the name */
9308   l = aopGet (left, 0, FALSE, TRUE);
9309   size = AOP_SIZE (result);
9310   while (size--)
9311     {
9312       if (offset)
9313         sprintf (buffer, "(%s + %d)", l + 1, offset);
9314       else
9315         sprintf (buffer, "%s", l + 1);
9316       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
9317     }
9318
9319   freeAsmop (left, NULL, ic, TRUE);
9320   freeAsmop (result, NULL, ic, TRUE);
9321 }
9322
9323 /*-----------------------------------------------------------------*/
9324 /* genNearPointerGet - emitcode for near pointer fetch             */
9325 /*-----------------------------------------------------------------*/
9326 static void
9327 genNearPointerGet (operand * left,
9328                    operand * result,
9329                    iCode * ic,
9330                    iCode * pi,
9331                    iCode * ifx)
9332 {
9333   asmop *aop = NULL;
9334   regs *preg = NULL;
9335   char *rname;
9336   sym_link *rtype, *retype;
9337   sym_link *ltype = operandType (left);
9338   char buffer[80];
9339
9340   D(emitcode (";     genNearPointerGet",""));
9341
9342   rtype = operandType (result);
9343   retype = getSpec (rtype);
9344
9345   aopOp (left, ic, FALSE);
9346
9347   /* if left is rematerialisable and
9348      result is not bitfield variable type and
9349      the left is pointer to data space i.e
9350      lower 128 bytes of space */
9351   if (AOP_TYPE (left) == AOP_IMMD &&
9352       !IS_BITFIELD (retype) &&
9353       DCL_TYPE (ltype) == POINTER)
9354     {
9355       genDataPointerGet (left, result, ic);
9356       return;
9357     }
9358
9359  /* if the value is already in a pointer register
9360      then don't need anything more */
9361   if (!AOP_INPREG (AOP (left)))
9362     {
9363       if (IS_AOP_PREG (left))
9364         {
9365           // Aha, it is a pointer, just in disguise.
9366           rname = aopGet (left, 0, FALSE, FALSE);
9367           if (*rname != '@')
9368             {
9369               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9370                       __FILE__, __LINE__);
9371             }
9372           else
9373             {
9374               // Expected case.
9375               emitcode ("mov", "a%s,%s", rname + 1, rname);
9376               rname++;  // skip the '@'.
9377             }
9378         }
9379       else
9380         {
9381           /* otherwise get a free pointer register */
9382           aop = newAsmop (0);
9383           preg = getFreePtr (ic, &aop, FALSE);
9384           emitcode ("mov", "%s,%s",
9385                     preg->name,
9386                     aopGet (left, 0, FALSE, TRUE));
9387           rname = preg->name;
9388         }
9389     }
9390   else
9391     rname = aopGet (left, 0, FALSE, FALSE);
9392
9393   //aopOp (result, ic, FALSE);
9394   aopOp (result, ic, result?TRUE:FALSE);
9395
9396   /* if bitfield then unpack the bits */
9397   if (IS_BITFIELD (retype))
9398     genUnpackBits (result, rname, POINTER, ifx);
9399   else
9400     {
9401       /* we have can just get the values */
9402       int size = AOP_SIZE (result);
9403       int offset = 0;
9404
9405       while (size--)
9406         {
9407           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9408             {
9409
9410               emitcode ("mov", "a,@%s", rname);
9411               if (!ifx)
9412               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9413             }
9414           else
9415             {
9416               sprintf (buffer, "@%s", rname);
9417               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
9418             }
9419           offset++;
9420           if (size || pi)
9421             emitcode ("inc", "%s", rname);
9422         }
9423     }
9424
9425   /* now some housekeeping stuff */
9426   if (aop)       /* we had to allocate for this iCode */
9427     {
9428       if (pi) { /* post increment present */
9429         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9430       }
9431       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9432     }
9433   else
9434     {
9435       /* we did not allocate which means left
9436          already in a pointer register, then
9437          if size > 0 && this could be used again
9438          we have to point it back to where it
9439          belongs */
9440       if ((AOP_SIZE (result) > 1 &&
9441            !OP_SYMBOL (left)->remat &&
9442            (OP_SYMBOL (left)->liveTo > ic->seq ||
9443             ic->depth)) &&
9444           !pi)
9445         {
9446           int size = AOP_SIZE (result) - 1;
9447           while (size--)
9448             emitcode ("dec", "%s", rname);
9449         }
9450     }
9451
9452   if (ifx && !ifx->generated)
9453     {
9454       genIfxJump (ifx, "a", left, NULL, result);
9455     }
9456
9457   /* done */
9458   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9459   freeAsmop (left, NULL, ic, TRUE);
9460   if (pi) pi->generated = 1;
9461 }
9462
9463 /*-----------------------------------------------------------------*/
9464 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9465 /*-----------------------------------------------------------------*/
9466 static void
9467 genPagedPointerGet (operand * left,
9468                     operand * result,
9469                     iCode * ic,
9470                     iCode *pi,
9471                     iCode *ifx)
9472 {
9473   asmop *aop = NULL;
9474   regs *preg = NULL;
9475   char *rname;
9476   sym_link *rtype, *retype;
9477
9478   D(emitcode (";     genPagedPointerGet",""));
9479
9480   rtype = operandType (result);
9481   retype = getSpec (rtype);
9482
9483   aopOp (left, ic, FALSE);
9484
9485   /* if the value is already in a pointer register
9486      then don't need anything more */
9487   if (!AOP_INPREG (AOP (left)))
9488     {
9489       /* otherwise get a free pointer register */
9490       aop = newAsmop (0);
9491       preg = getFreePtr (ic, &aop, FALSE);
9492       emitcode ("mov", "%s,%s",
9493                 preg->name,
9494                 aopGet (left, 0, FALSE, TRUE));
9495       rname = preg->name;
9496     }
9497   else
9498     rname = aopGet (left, 0, FALSE, FALSE);
9499
9500   aopOp (result, ic, FALSE);
9501
9502   /* if bitfield then unpack the bits */
9503   if (IS_BITFIELD (retype))
9504     genUnpackBits (result, rname, PPOINTER, ifx);
9505   else
9506     {
9507       /* we have can just get the values */
9508       int size = AOP_SIZE (result);
9509       int offset = 0;
9510
9511       while (size--)
9512         {
9513
9514           emitcode ("movx", "a,@%s", rname);
9515           if (!ifx)
9516           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9517
9518           offset++;
9519
9520           if (size || pi)
9521             emitcode ("inc", "%s", rname);
9522         }
9523     }
9524
9525   /* now some housekeeping stuff */
9526   if (aop) /* we had to allocate for this iCode */
9527     {
9528       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9529       freeAsmop (NULL, aop, ic, TRUE);
9530     }
9531   else
9532     {
9533       /* we did not allocate which means left
9534          already in a pointer register, then
9535          if size > 0 && this could be used again
9536          we have to point it back to where it
9537          belongs */
9538       if ((AOP_SIZE (result) > 1 &&
9539            !OP_SYMBOL (left)->remat &&
9540            (OP_SYMBOL (left)->liveTo > ic->seq ||
9541             ic->depth)) &&
9542           !pi)
9543         {
9544           int size = AOP_SIZE (result) - 1;
9545           while (size--)
9546             emitcode ("dec", "%s", rname);
9547         }
9548     }
9549
9550   if (ifx && !ifx->generated)
9551     {
9552       genIfxJump (ifx, "a", left, NULL, result);
9553     }
9554
9555   /* done */
9556   freeAsmop (left, NULL, ic, TRUE);
9557   freeAsmop (result, NULL, ic, TRUE);
9558   if (pi) pi->generated = 1;
9559
9560 }
9561
9562 /*--------------------------------------------------------------------*/
9563 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
9564 /*--------------------------------------------------------------------*/
9565 static void
9566 loadDptrFromOperand (operand *op, bool loadBToo)
9567 {
9568   if (AOP_TYPE (op) != AOP_STR)
9569     {
9570       /* if this is rematerializable */
9571       if (AOP_TYPE (op) == AOP_IMMD)
9572         {
9573           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
9574           if (loadBToo)
9575             {
9576               if (AOP(op)->aopu.aop_immd.from_cast_remat)
9577                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
9578               else
9579                 {
9580                   wassertl(FALSE, "need pointerCode");
9581                   emitcode ("", "; mov b,???");
9582                   /* genPointerGet and genPointerSet originally did different
9583                   ** things for this case. Both seem wrong.
9584                   ** from genPointerGet:
9585                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
9586                   ** from genPointerSet:
9587                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
9588                   */
9589                 }
9590             }
9591         }
9592       else if (AOP_TYPE (op) == AOP_DPTR)
9593         {
9594           if (loadBToo)
9595             {
9596               MOVA (aopGet (op, 0, FALSE, FALSE));
9597               emitcode ("push", "acc");
9598               MOVA (aopGet (op, 1, FALSE, FALSE));
9599               emitcode ("push", "acc");
9600               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9601               emitcode ("pop", "dph");
9602               emitcode ("pop", "dpl");
9603             }
9604           else
9605             {
9606               MOVA (aopGet (op, 0, FALSE, FALSE));
9607               emitcode ("push", "acc");
9608               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9609               emitcode ("pop", "dpl");
9610             }
9611         }
9612       else
9613         {                       /* we need to get it byte by byte */
9614           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9615           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9616           if (loadBToo)
9617             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9618         }
9619     }
9620 }
9621
9622 /*-----------------------------------------------------------------*/
9623 /* genFarPointerGet - gget value from far space                    */
9624 /*-----------------------------------------------------------------*/
9625 static void
9626 genFarPointerGet (operand * left,
9627                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9628 {
9629   int size, offset;
9630   sym_link *retype = getSpec (operandType (result));
9631
9632   D(emitcode (";     genFarPointerGet",""));
9633
9634   aopOp (left, ic, FALSE);
9635   loadDptrFromOperand (left, FALSE);
9636
9637   /* so dptr now contains the address */
9638   aopOp (result, ic, FALSE);
9639
9640   /* if bit then unpack */
9641   if (IS_BITFIELD (retype))
9642     genUnpackBits (result, "dptr", FPOINTER, ifx);
9643   else
9644     {
9645       size = AOP_SIZE (result);
9646       offset = 0;
9647
9648       while (size--)
9649         {
9650           emitcode ("movx", "a,@dptr");
9651           if (!ifx)
9652             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9653           if (size || pi)
9654             emitcode ("inc", "dptr");
9655         }
9656     }
9657
9658   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9659     {
9660     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9661     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9662     pi->generated = 1;
9663   }
9664
9665   if (ifx && !ifx->generated)
9666     {
9667       genIfxJump (ifx, "a", left, NULL, result);
9668     }
9669
9670   freeAsmop (left, NULL, ic, TRUE);
9671   freeAsmop (result, NULL, ic, TRUE);
9672 }
9673
9674 /*-----------------------------------------------------------------*/
9675 /* genCodePointerGet - gget value from code space                  */
9676 /*-----------------------------------------------------------------*/
9677 static void
9678 genCodePointerGet (operand * left,
9679                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9680 {
9681   int size, offset;
9682   sym_link *retype = getSpec (operandType (result));
9683
9684   D(emitcode (";     genCodePointerGet",""));
9685
9686   aopOp (left, ic, FALSE);
9687   loadDptrFromOperand (left, FALSE);
9688
9689   /* so dptr now contains the address */
9690   aopOp (result, ic, FALSE);
9691
9692   /* if bit then unpack */
9693   if (IS_BITFIELD (retype))
9694     genUnpackBits (result, "dptr", CPOINTER, ifx);
9695   else
9696     {
9697       size = AOP_SIZE (result);
9698       offset = 0;
9699
9700       while (size--)
9701         {
9702           if (pi)
9703             {
9704               emitcode ("clr", "a");
9705               emitcode ("movc", "a,@a+dptr");
9706               if (!ifx)
9707               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9708               emitcode ("inc", "dptr");
9709             }
9710           else
9711             {
9712               emitcode ("mov", "a,#0x%02x", offset);
9713               emitcode ("movc", "a,@a+dptr");
9714               if (!ifx)
9715               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9716             }
9717         }
9718     }
9719
9720   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9721     {
9722     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9723     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9724     pi->generated = 1;
9725   }
9726
9727   if (ifx && !ifx->generated)
9728     {
9729       genIfxJump (ifx, "a", left, NULL, result);
9730     }
9731
9732   freeAsmop (left, NULL, ic, TRUE);
9733   freeAsmop (result, NULL, ic, TRUE);
9734 }
9735
9736 /*-----------------------------------------------------------------*/
9737 /* genGenPointerGet - gget value from generic pointer space        */
9738 /*-----------------------------------------------------------------*/
9739 static void
9740 genGenPointerGet (operand * left,
9741                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9742 {
9743   int size, offset;
9744   sym_link *retype = getSpec (operandType (result));
9745
9746   D(emitcode (";     genGenPointerGet",""));
9747
9748   aopOp (left, ic, FALSE);
9749   loadDptrFromOperand (left, TRUE);
9750
9751   /* so dptr know contains the address */
9752   aopOp (result, ic, FALSE);
9753
9754   /* if bit then unpack */
9755   if (IS_BITFIELD (retype))
9756     genUnpackBits (result, "dptr", GPOINTER, ifx);
9757   else
9758     {
9759       size = AOP_SIZE (result);
9760       offset = 0;
9761
9762       while (size--)
9763         {
9764           emitcode ("lcall", "__gptrget");
9765           if (!ifx)
9766           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9767           if (size || pi)
9768             emitcode ("inc", "dptr");
9769         }
9770     }
9771
9772   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9773     {
9774     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9775     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9776     pi->generated = 1;
9777   }
9778
9779   if (ifx && !ifx->generated)
9780     {
9781       genIfxJump (ifx, "a", left, NULL, result);
9782     }
9783
9784
9785   freeAsmop (left, NULL, ic, TRUE);
9786   freeAsmop (result, NULL, ic, TRUE);
9787 }
9788
9789 /*-----------------------------------------------------------------*/
9790 /* genPointerGet - generate code for pointer get                   */
9791 /*-----------------------------------------------------------------*/
9792 static void
9793 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9794 {
9795   operand *left, *result;
9796   sym_link *type, *etype;
9797   int p_type;
9798
9799   D(emitcode (";     genPointerGet",""));
9800
9801   left = IC_LEFT (ic);
9802   result = IC_RESULT (ic);
9803
9804   if (getSize (operandType (result))>1)
9805     ifx = NULL;
9806
9807   /* depending on the type of pointer we need to
9808      move it to the correct pointer register */
9809   type = operandType (left);
9810   etype = getSpec (type);
9811   /* if left is of type of pointer then it is simple */
9812   if (IS_PTR (type) && !IS_FUNC (type->next))
9813     p_type = DCL_TYPE (type);
9814   else
9815     {
9816       /* we have to go by the storage class */
9817       p_type = PTR_TYPE (SPEC_OCLS (etype));
9818     }
9819
9820   /* special case when cast remat */
9821   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9822       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9823           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9824           type = operandType (left);
9825           p_type = DCL_TYPE (type);
9826   }
9827   /* now that we have the pointer type we assign
9828      the pointer values */
9829   switch (p_type)
9830     {
9831
9832     case POINTER:
9833     case IPOINTER:
9834       genNearPointerGet (left, result, ic, pi, ifx);
9835       break;
9836
9837     case PPOINTER:
9838       genPagedPointerGet (left, result, ic, pi, ifx);
9839       break;
9840
9841     case FPOINTER:
9842       genFarPointerGet (left, result, ic, pi, ifx);
9843       break;
9844
9845     case CPOINTER:
9846       genCodePointerGet (left, result, ic, pi, ifx);
9847       break;
9848
9849     case GPOINTER:
9850       genGenPointerGet (left, result, ic, pi, ifx);
9851       break;
9852     }
9853
9854 }
9855
9856
9857
9858 /*-----------------------------------------------------------------*/
9859 /* genPackBits - generates code for packed bit storage             */
9860 /*-----------------------------------------------------------------*/
9861 static void
9862 genPackBits (sym_link * etype,
9863              operand * right,
9864              char *rname, int p_type)
9865 {
9866   int offset = 0;       /* source byte offset */
9867   int rlen = 0;         /* remaining bitfield length */
9868   int blen;             /* bitfield length */
9869   int bstr;             /* bitfield starting bit within byte */
9870   int litval;           /* source literal value (if AOP_LIT) */
9871   unsigned char mask;   /* bitmask within current byte */
9872
9873   D(emitcode (";     genPackBits",""));
9874
9875   blen = SPEC_BLEN (etype);
9876   bstr = SPEC_BSTR (etype);
9877
9878   /* If the bitfield length is less than a byte */
9879   if (blen < 8)
9880     {
9881       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9882               (unsigned char) (0xFF >> (8 - bstr)));
9883
9884       if (AOP_TYPE (right) == AOP_LIT)
9885         {
9886           /* Case with a bitfield length <8 and literal source
9887           */
9888           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9889           litval <<= bstr;
9890           litval &= (~mask) & 0xff;
9891           emitPtrByteGet (rname, p_type, FALSE);
9892           if ((mask|litval)!=0xff)
9893             emitcode ("anl","a,#0x%02x", mask);
9894           if (litval)
9895             emitcode ("orl","a,#0x%02x", litval);
9896         }
9897       else
9898         {
9899           if ((blen==1) && (p_type!=GPOINTER))
9900             {
9901               /* Case with a bitfield length == 1 and no generic pointer
9902               */
9903               if (AOP_TYPE (right) == AOP_CRY)
9904                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9905               else
9906                 {
9907                   MOVA (aopGet (right, 0, FALSE, FALSE));
9908                   emitcode ("rrc","a");
9909                 }
9910               emitPtrByteGet (rname, p_type, FALSE);
9911               emitcode ("mov","acc.%d,c",bstr);
9912             }
9913           else
9914             {
9915               bool pushedB;
9916               /* Case with a bitfield length < 8 and arbitrary source
9917               */
9918               MOVA (aopGet (right, 0, FALSE, FALSE));
9919               /* shift and mask source value */
9920               AccLsh (bstr);
9921               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9922
9923               pushedB = pushB ();
9924               /* transfer A to B and get next byte */
9925               emitPtrByteGet (rname, p_type, TRUE);
9926
9927               emitcode ("anl", "a,#0x%02x", mask);
9928               emitcode ("orl", "a,b");
9929               if (p_type == GPOINTER)
9930                 emitcode ("pop", "b");
9931
9932               popB (pushedB);
9933            }
9934         }
9935
9936       emitPtrByteSet (rname, p_type, "a");
9937       return;
9938     }
9939
9940   /* Bit length is greater than 7 bits. In this case, copy  */
9941   /* all except the partial byte at the end                 */
9942   for (rlen=blen;rlen>=8;rlen-=8)
9943     {
9944       emitPtrByteSet (rname, p_type,
9945                       aopGet (right, offset++, FALSE, TRUE) );
9946       if (rlen>8)
9947         emitcode ("inc", "%s", rname);
9948     }
9949
9950   /* If there was a partial byte at the end */
9951   if (rlen)
9952     {
9953       mask = (((unsigned char) -1 << rlen) & 0xff);
9954
9955       if (AOP_TYPE (right) == AOP_LIT)
9956         {
9957           /* Case with partial byte and literal source
9958           */
9959           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9960           litval >>= (blen-rlen);
9961           litval &= (~mask) & 0xff;
9962           emitPtrByteGet (rname, p_type, FALSE);
9963           if ((mask|litval)!=0xff)
9964             emitcode ("anl","a,#0x%02x", mask);
9965           if (litval)
9966             emitcode ("orl","a,#0x%02x", litval);
9967         }
9968       else
9969         {
9970           bool pushedB;
9971           /* Case with partial byte and arbitrary source
9972           */
9973           MOVA (aopGet (right, offset++, FALSE, FALSE));
9974           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9975
9976           pushedB = pushB ();
9977           /* transfer A to B and get next byte */
9978           emitPtrByteGet (rname, p_type, TRUE);
9979
9980           emitcode ("anl", "a,#0x%02x", mask);
9981           emitcode ("orl", "a,b");
9982           if (p_type == GPOINTER)
9983             emitcode ("pop", "b");
9984
9985           popB (pushedB);
9986         }
9987       emitPtrByteSet (rname, p_type, "a");
9988     }
9989
9990 }
9991
9992
9993 /*-----------------------------------------------------------------*/
9994 /* genDataPointerSet - remat pointer to data space                 */
9995 /*-----------------------------------------------------------------*/
9996 static void
9997 genDataPointerSet (operand * right,
9998                    operand * result,
9999                    iCode * ic)
10000 {
10001   int size, offset = 0;
10002   char *l, buffer[256];
10003
10004   D(emitcode (";     genDataPointerSet",""));
10005
10006   aopOp (right, ic, FALSE);
10007
10008   l = aopGet (result, 0, FALSE, TRUE);
10009   size = AOP_SIZE (right);
10010   while (size--)
10011     {
10012       if (offset)
10013         sprintf (buffer, "(%s + %d)", l + 1, offset);
10014       else
10015         sprintf (buffer, "%s", l + 1);
10016       emitcode ("mov", "%s,%s", buffer,
10017                 aopGet (right, offset++, FALSE, FALSE));
10018     }
10019
10020   freeAsmop (right, NULL, ic, TRUE);
10021   freeAsmop (result, NULL, ic, TRUE);
10022 }
10023
10024 /*-----------------------------------------------------------------*/
10025 /* genNearPointerSet - emitcode for near pointer put                */
10026 /*-----------------------------------------------------------------*/
10027 static void
10028 genNearPointerSet (operand * right,
10029                    operand * result,
10030                    iCode * ic,
10031                    iCode * pi)
10032 {
10033   asmop *aop = NULL;
10034   regs *preg = NULL;
10035   char *rname, *l;
10036   sym_link *retype, *letype;
10037   sym_link *ptype = operandType (result);
10038
10039   D(emitcode (";     genNearPointerSet",""));
10040
10041   retype = getSpec (operandType (right));
10042   letype = getSpec (ptype);
10043   aopOp (result, ic, FALSE);
10044
10045   /* if the result is rematerializable &
10046      in data space & not a bit variable */
10047   if (AOP_TYPE (result) == AOP_IMMD &&
10048       DCL_TYPE (ptype) == POINTER &&
10049       !IS_BITVAR (retype) &&
10050       !IS_BITVAR (letype))
10051     {
10052       genDataPointerSet (right, result, ic);
10053       return;
10054     }
10055
10056   /* if the value is already in a pointer register
10057      then don't need anything more */
10058   if (!AOP_INPREG (AOP (result)))
10059     {
10060         if (
10061             //AOP_TYPE (result) == AOP_STK
10062             IS_AOP_PREG(result)
10063             )
10064         {
10065             // Aha, it is a pointer, just in disguise.
10066             rname = aopGet (result, 0, FALSE, FALSE);
10067             if (*rname != '@')
10068             {
10069                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10070                         __FILE__, __LINE__);
10071             }
10072             else
10073             {
10074                 // Expected case.
10075                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10076                 rname++;  // skip the '@'.
10077             }
10078         }
10079         else
10080         {
10081             /* otherwise get a free pointer register */
10082             aop = newAsmop (0);
10083             preg = getFreePtr (ic, &aop, FALSE);
10084             emitcode ("mov", "%s,%s",
10085                       preg->name,
10086                       aopGet (result, 0, FALSE, TRUE));
10087             rname = preg->name;
10088         }
10089     }
10090     else
10091     {
10092         rname = aopGet (result, 0, FALSE, FALSE);
10093     }
10094
10095   aopOp (right, ic, FALSE);
10096
10097   /* if bitfield then unpack the bits */
10098   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10099     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10100   else
10101     {
10102       /* we have can just get the values */
10103       int size = AOP_SIZE (right);
10104       int offset = 0;
10105
10106       while (size--)
10107         {
10108           l = aopGet (right, offset, FALSE, TRUE);
10109           if (*l == '@')
10110             {
10111               MOVA (l);
10112               emitcode ("mov", "@%s,a", rname);
10113             }
10114           else
10115             emitcode ("mov", "@%s,%s", rname, l);
10116           if (size || pi)
10117             emitcode ("inc", "%s", rname);
10118           offset++;
10119         }
10120     }
10121
10122   /* now some housekeeping stuff */
10123   if (aop) /* we had to allocate for this iCode */
10124     {
10125       if (pi)
10126         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10127       freeAsmop (NULL, aop, ic, TRUE);
10128     }
10129   else
10130     {
10131       /* we did not allocate which means left
10132          already in a pointer register, then
10133          if size > 0 && this could be used again
10134          we have to point it back to where it
10135          belongs */
10136       if ((AOP_SIZE (right) > 1 &&
10137            !OP_SYMBOL (result)->remat &&
10138            (OP_SYMBOL (result)->liveTo > ic->seq ||
10139             ic->depth)) &&
10140           !pi)
10141         {
10142           int size = AOP_SIZE (right) - 1;
10143           while (size--)
10144             emitcode ("dec", "%s", rname);
10145         }
10146     }
10147
10148   /* done */
10149   if (pi) pi->generated = 1;
10150   freeAsmop (result, NULL, ic, TRUE);
10151   freeAsmop (right, NULL, ic, TRUE);
10152 }
10153
10154 /*-----------------------------------------------------------------*/
10155 /* genPagedPointerSet - emitcode for Paged pointer put             */
10156 /*-----------------------------------------------------------------*/
10157 static void
10158 genPagedPointerSet (operand * right,
10159                     operand * result,
10160                     iCode * ic,
10161                     iCode * pi)
10162 {
10163   asmop *aop = NULL;
10164   regs *preg = NULL;
10165   char *rname, *l;
10166   sym_link *retype, *letype;
10167
10168   D(emitcode (";     genPagedPointerSet",""));
10169
10170   retype = getSpec (operandType (right));
10171   letype = getSpec (operandType (result));
10172
10173   aopOp (result, ic, FALSE);
10174
10175   /* if the value is already in a pointer register
10176      then don't need anything more */
10177   if (!AOP_INPREG (AOP (result)))
10178     {
10179       /* otherwise get a free pointer register */
10180       aop = newAsmop (0);
10181       preg = getFreePtr (ic, &aop, FALSE);
10182       emitcode ("mov", "%s,%s",
10183                 preg->name,
10184                 aopGet (result, 0, FALSE, TRUE));
10185       rname = preg->name;
10186     }
10187   else
10188     rname = aopGet (result, 0, FALSE, FALSE);
10189
10190   aopOp (right, ic, FALSE);
10191
10192   /* if bitfield then unpack the bits */
10193   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10194     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10195   else
10196     {
10197       /* we have can just get the values */
10198       int size = AOP_SIZE (right);
10199       int offset = 0;
10200
10201       while (size--)
10202         {
10203           l = aopGet (right, offset, FALSE, TRUE);
10204
10205           MOVA (l);
10206           emitcode ("movx", "@%s,a", rname);
10207
10208           if (size || pi)
10209             emitcode ("inc", "%s", rname);
10210
10211           offset++;
10212         }
10213     }
10214
10215   /* now some housekeeping stuff */
10216   if (aop) /* we had to allocate for this iCode */
10217     {
10218       if (pi)
10219         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10220       freeAsmop (NULL, aop, ic, TRUE);
10221     }
10222   else
10223     {
10224       /* we did not allocate which means left
10225          already in a pointer register, then
10226          if size > 0 && this could be used again
10227          we have to point it back to where it
10228          belongs */
10229       if (AOP_SIZE (right) > 1 &&
10230           !OP_SYMBOL (result)->remat &&
10231           (OP_SYMBOL (result)->liveTo > ic->seq ||
10232            ic->depth))
10233         {
10234           int size = AOP_SIZE (right) - 1;
10235           while (size--)
10236             emitcode ("dec", "%s", rname);
10237         }
10238     }
10239
10240   /* done */
10241   if (pi) pi->generated = 1;
10242   freeAsmop (result, NULL, ic, TRUE);
10243   freeAsmop (right, NULL, ic, TRUE);
10244
10245
10246 }
10247
10248 /*-----------------------------------------------------------------*/
10249 /* genFarPointerSet - set value from far space                     */
10250 /*-----------------------------------------------------------------*/
10251 static void
10252 genFarPointerSet (operand * right,
10253                   operand * result, iCode * ic, iCode * pi)
10254 {
10255   int size, offset;
10256   sym_link *retype = getSpec (operandType (right));
10257   sym_link *letype = getSpec (operandType (result));
10258
10259   D(emitcode (";     genFarPointerSet",""));
10260
10261   aopOp (result, ic, FALSE);
10262   loadDptrFromOperand (result, FALSE);
10263
10264   /* so dptr know contains the address */
10265   aopOp (right, ic, FALSE);
10266
10267   /* if bit then unpack */
10268   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10269     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10270   else
10271     {
10272       size = AOP_SIZE (right);
10273       offset = 0;
10274
10275       while (size--)
10276         {
10277           char *l = aopGet (right, offset++, FALSE, FALSE);
10278           MOVA (l);
10279           emitcode ("movx", "@dptr,a");
10280           if (size || pi)
10281             emitcode ("inc", "dptr");
10282         }
10283     }
10284   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10285     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10286     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10287     pi->generated=1;
10288   }
10289   freeAsmop (result, NULL, ic, TRUE);
10290   freeAsmop (right, NULL, ic, TRUE);
10291 }
10292
10293 /*-----------------------------------------------------------------*/
10294 /* genGenPointerSet - set value from generic pointer space         */
10295 /*-----------------------------------------------------------------*/
10296 static void
10297 genGenPointerSet (operand * right,
10298                   operand * result, iCode * ic, iCode * pi)
10299 {
10300   int size, offset;
10301   sym_link *retype = getSpec (operandType (right));
10302   sym_link *letype = getSpec (operandType (result));
10303
10304   D(emitcode (";     genGenPointerSet",""));
10305
10306   aopOp (result, ic, FALSE);
10307   loadDptrFromOperand (result, TRUE);
10308
10309   /* so dptr know contains the address */
10310   aopOp (right, ic, FALSE);
10311
10312   /* if bit then unpack */
10313   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10314     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10315   else
10316     {
10317       size = AOP_SIZE (right);
10318       offset = 0;
10319
10320       while (size--)
10321         {
10322           char *l = aopGet (right, offset++, FALSE, FALSE);
10323           MOVA (l);
10324           emitcode ("lcall", "__gptrput");
10325           if (size || pi)
10326             emitcode ("inc", "dptr");
10327         }
10328     }
10329
10330   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10331     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10332     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10333     pi->generated=1;
10334   }
10335   freeAsmop (result, NULL, ic, TRUE);
10336   freeAsmop (right, NULL, ic, TRUE);
10337 }
10338
10339 /*-----------------------------------------------------------------*/
10340 /* genPointerSet - stores the value into a pointer location        */
10341 /*-----------------------------------------------------------------*/
10342 static void
10343 genPointerSet (iCode * ic, iCode *pi)
10344 {
10345   operand *right, *result;
10346   sym_link *type, *etype;
10347   int p_type;
10348
10349   D(emitcode (";     genPointerSet",""));
10350
10351   right = IC_RIGHT (ic);
10352   result = IC_RESULT (ic);
10353
10354   /* depending on the type of pointer we need to
10355      move it to the correct pointer register */
10356   type = operandType (result);
10357   etype = getSpec (type);
10358   /* if left is of type of pointer then it is simple */
10359   if (IS_PTR (type) && !IS_FUNC (type->next))
10360     {
10361       p_type = DCL_TYPE (type);
10362     }
10363   else
10364     {
10365       /* we have to go by the storage class */
10366       p_type = PTR_TYPE (SPEC_OCLS (etype));
10367     }
10368
10369   /* special case when cast remat */
10370   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10371       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10372           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10373           type = operandType (result);
10374           p_type = DCL_TYPE (type);
10375   }
10376   /* now that we have the pointer type we assign
10377      the pointer values */
10378   switch (p_type)
10379     {
10380
10381     case POINTER:
10382     case IPOINTER:
10383       genNearPointerSet (right, result, ic, pi);
10384       break;
10385
10386     case PPOINTER:
10387       genPagedPointerSet (right, result, ic, pi);
10388       break;
10389
10390     case FPOINTER:
10391       genFarPointerSet (right, result, ic, pi);
10392       break;
10393
10394     case GPOINTER:
10395       genGenPointerSet (right, result, ic, pi);
10396       break;
10397
10398     default:
10399       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10400               "genPointerSet: illegal pointer type");
10401     }
10402
10403 }
10404
10405 /*-----------------------------------------------------------------*/
10406 /* genIfx - generate code for Ifx statement                        */
10407 /*-----------------------------------------------------------------*/
10408 static void
10409 genIfx (iCode * ic, iCode * popIc)
10410 {
10411   operand *cond = IC_COND (ic);
10412   int isbit = 0;
10413   char *dup = NULL;
10414
10415   D(emitcode (";     genIfx",""));
10416
10417   aopOp (cond, ic, FALSE);
10418
10419   /* get the value into acc */
10420   if (AOP_TYPE (cond) != AOP_CRY)
10421     toBoolean (cond);
10422   else
10423     {
10424       isbit = 1;
10425       if (AOP(cond)->aopu.aop_dir)
10426         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10427     }
10428   /* the result is now in the accumulator or a directly addressable bit */
10429   freeAsmop (cond, NULL, ic, TRUE);
10430
10431   /* if there was something to be popped then do it */
10432   if (popIc)
10433     genIpop (popIc);
10434
10435   /* if the condition is a bit variable */
10436   if (isbit && dup)
10437     genIfxJump(ic, dup, NULL, NULL, NULL);
10438   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10439     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10440   else if (isbit && !IS_ITEMP (cond))
10441     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10442   else
10443     genIfxJump (ic, "a", NULL, NULL, NULL);
10444
10445   ic->generated = 1;
10446 }
10447
10448 /*-----------------------------------------------------------------*/
10449 /* genAddrOf - generates code for address of                       */
10450 /*-----------------------------------------------------------------*/
10451 static void
10452 genAddrOf (iCode * ic)
10453 {
10454   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10455   int size, offset;
10456
10457   D(emitcode (";     genAddrOf",""));
10458
10459   aopOp (IC_RESULT (ic), ic, FALSE);
10460
10461   /* if the operand is on the stack then we
10462      need to get the stack offset of this
10463      variable */
10464   if (sym->onStack)
10465     {
10466       /* if it has an offset then we need to compute
10467          it */
10468       if (sym->stack)
10469         {
10470           emitcode ("mov", "a,%s", SYM_BP (sym));
10471           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
10472                                          ((char) (sym->stack - _G.nRegsSaved)) :
10473                                          ((char) sym->stack)) & 0xff);
10474           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10475         }
10476       else
10477         {
10478           /* we can just move _bp */
10479           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10480         }
10481       /* fill the result with zero */
10482       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10483
10484       offset = 1;
10485       while (size--)
10486         {
10487           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10488         }
10489
10490       goto release;
10491     }
10492
10493   /* object not on stack then we need the name */
10494   size = AOP_SIZE (IC_RESULT (ic));
10495   offset = 0;
10496
10497   while (size--)
10498     {
10499       char s[SDCC_NAME_MAX];
10500       if (offset)
10501         sprintf (s, "#(%s >> %d)",
10502                  sym->rname,
10503                  offset * 8);
10504       else
10505         sprintf (s, "#%s", sym->rname);
10506       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10507     }
10508
10509 release:
10510   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10511
10512 }
10513
10514 /*-----------------------------------------------------------------*/
10515 /* genFarFarAssign - assignment when both are in far space         */
10516 /*-----------------------------------------------------------------*/
10517 static void
10518 genFarFarAssign (operand * result, operand * right, iCode * ic)
10519 {
10520   int size = AOP_SIZE (right);
10521   int offset = 0;
10522   char *l;
10523
10524   D(emitcode (";     genFarFarAssign",""));
10525
10526   /* first push the right side on to the stack */
10527   while (size--)
10528     {
10529       l = aopGet (right, offset++, FALSE, FALSE);
10530       MOVA (l);
10531       emitcode ("push", "acc");
10532     }
10533
10534   freeAsmop (right, NULL, ic, FALSE);
10535   /* now assign DPTR to result */
10536   aopOp (result, ic, FALSE);
10537   size = AOP_SIZE (result);
10538   while (size--)
10539     {
10540       emitcode ("pop", "acc");
10541       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
10542     }
10543   freeAsmop (result, NULL, ic, FALSE);
10544
10545 }
10546
10547 /*-----------------------------------------------------------------*/
10548 /* genAssign - generate code for assignment                        */
10549 /*-----------------------------------------------------------------*/
10550 static void
10551 genAssign (iCode * ic)
10552 {
10553   operand *result, *right;
10554   int size, offset;
10555   unsigned long lit = 0L;
10556
10557   D(emitcode(";     genAssign",""));
10558
10559   result = IC_RESULT (ic);
10560   right = IC_RIGHT (ic);
10561
10562   /* if they are the same */
10563   if (operandsEqu (result, right) &&
10564       !isOperandVolatile (result, FALSE) &&
10565       !isOperandVolatile (right, FALSE))
10566     return;
10567
10568   aopOp (right, ic, FALSE);
10569
10570   /* special case both in far space */
10571   if (AOP_TYPE (right) == AOP_DPTR &&
10572       IS_TRUE_SYMOP (result) &&
10573       isOperandInFarSpace (result))
10574     {
10575
10576       genFarFarAssign (result, right, ic);
10577       return;
10578     }
10579
10580   aopOp (result, ic, TRUE);
10581
10582   /* if they are the same registers */
10583   if (sameRegs (AOP (right), AOP (result)) &&
10584       !isOperandVolatile (result, FALSE) &&
10585       !isOperandVolatile (right, FALSE))
10586     goto release;
10587
10588   /* if the result is a bit */
10589   if (AOP_TYPE (result) == AOP_CRY)
10590     {
10591
10592       /* if the right size is a literal then
10593          we know what the value is */
10594       if (AOP_TYPE (right) == AOP_LIT)
10595         {
10596           if (((int) operandLitValue (right)))
10597             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10598           else
10599             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10600           goto release;
10601         }
10602
10603       /* the right is also a bit variable */
10604       if (AOP_TYPE (right) == AOP_CRY)
10605         {
10606           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10607           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10608           goto release;
10609         }
10610
10611       /* we need to or */
10612       toBoolean (right);
10613       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10614       goto release;
10615     }
10616
10617   /* bit variables done */
10618   /* general case */
10619   size = AOP_SIZE (result);
10620   offset = 0;
10621   if (AOP_TYPE (right) == AOP_LIT)
10622     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10623   if ((size > 1) &&
10624       (AOP_TYPE (result) != AOP_REG) &&
10625       (AOP_TYPE (right) == AOP_LIT) &&
10626       !IS_FLOAT (operandType (right)) &&
10627       (lit < 256L))
10628     {
10629       while ((size) && (lit))
10630         {
10631           aopPut (result,
10632                   aopGet (right, offset, FALSE, FALSE),
10633                   offset,
10634                   isOperandVolatile (result, FALSE));
10635           lit >>= 8;
10636           offset++;
10637           size--;
10638         }
10639       emitcode ("clr", "a");
10640       while (size--)
10641         {
10642           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10643           offset++;
10644         }
10645     }
10646   else
10647     {
10648       while (size--)
10649         {
10650           aopPut (result,
10651                   aopGet (right, offset, FALSE, FALSE),
10652                   offset,
10653                   isOperandVolatile (result, FALSE));
10654           offset++;
10655         }
10656     }
10657
10658 release:
10659   freeAsmop (right, NULL, ic, TRUE);
10660   freeAsmop (result, NULL, ic, TRUE);
10661 }
10662
10663 /*-----------------------------------------------------------------*/
10664 /* genJumpTab - generates code for jump table                      */
10665 /*-----------------------------------------------------------------*/
10666 static void
10667 genJumpTab (iCode * ic)
10668 {
10669   symbol *jtab,*jtablo,*jtabhi;
10670   char *l;
10671   unsigned int count;
10672
10673   D(emitcode (";     genJumpTab",""));
10674
10675   count = elementsInSet( IC_JTLABELS (ic) );
10676
10677   if( count <= 16 )
10678     {
10679       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10680          if the switch argument is in a register.
10681          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10682       /* (MB) What if peephole converts ljmp to sjmp or ret ???
10683          How will multiply by three be updated ???*/
10684       aopOp (IC_JTCOND (ic), ic, FALSE);
10685       /* get the condition into accumulator */
10686       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10687       MOVA (l);
10688       /* multiply by three */
10689       emitcode ("add", "a,acc");
10690       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10691       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10692
10693       jtab = newiTempLabel (NULL);
10694       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10695       emitcode ("jmp", "@a+dptr");
10696       emitcode ("", "%05d$:", jtab->key + 100);
10697       /* now generate the jump labels */
10698       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10699            jtab = setNextItem (IC_JTLABELS (ic)))
10700         emitcode ("ljmp", "%05d$", jtab->key + 100);
10701     }
10702   else
10703     {
10704       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10705          if the switch argument is in a register.
10706          For n>6 this algorithm may be more compact */
10707       jtablo = newiTempLabel (NULL);
10708       jtabhi = newiTempLabel (NULL);
10709
10710       /* get the condition into accumulator.
10711          Using b as temporary storage, if register push/pop is needed */
10712       aopOp (IC_JTCOND (ic), ic, FALSE);
10713       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10714       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10715           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10716         {
10717           // (MB) what if B is in use???
10718           wassertl(!BINUSE, "B was in use");
10719           emitcode ("mov", "b,%s", l);
10720           l = "b";
10721         }
10722       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10723       MOVA (l);
10724       if( count <= 112 )
10725         {
10726           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10727           emitcode ("movc", "a,@a+pc");
10728           emitcode ("push", "acc");
10729
10730           MOVA (l);
10731           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10732           emitcode ("movc", "a,@a+pc");
10733           emitcode ("push", "acc");
10734         }
10735       else
10736         {
10737           /* this scales up to n<=255, but needs two more bytes
10738              and changes dptr */
10739           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10740           emitcode ("movc", "a,@a+dptr");
10741           emitcode ("push", "acc");
10742
10743           MOVA (l);
10744           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10745           emitcode ("movc", "a,@a+dptr");
10746           emitcode ("push", "acc");
10747         }
10748
10749       emitcode ("ret", "");
10750
10751       /* now generate jump table, LSB */
10752       emitcode ("", "%05d$:", jtablo->key + 100);
10753       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10754            jtab = setNextItem (IC_JTLABELS (ic)))
10755         emitcode (".db", "%05d$", jtab->key + 100);
10756
10757       /* now generate jump table, MSB */
10758       emitcode ("", "%05d$:", jtabhi->key + 100);
10759       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10760            jtab = setNextItem (IC_JTLABELS (ic)))
10761          emitcode (".db", "%05d$>>8", jtab->key + 100);
10762     }
10763 }
10764
10765 /*-----------------------------------------------------------------*/
10766 /* genCast - gen code for casting                                  */
10767 /*-----------------------------------------------------------------*/
10768 static void
10769 genCast (iCode * ic)
10770 {
10771   operand *result = IC_RESULT (ic);
10772   sym_link *ctype = operandType (IC_LEFT (ic));
10773   sym_link *rtype = operandType (IC_RIGHT (ic));
10774   operand *right = IC_RIGHT (ic);
10775   int size, offset;
10776
10777   D(emitcode(";     genCast",""));
10778
10779   /* if they are equivalent then do nothing */
10780   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10781     return;
10782
10783   aopOp (right, ic, FALSE);
10784   aopOp (result, ic, FALSE);
10785
10786   /* if the result is a bit (and not a bitfield) */
10787   // if (AOP_TYPE (result) == AOP_CRY)
10788   if (IS_BITVAR (OP_SYMBOL (result)->type)
10789       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10790     {
10791       /* if the right size is a literal then
10792          we know what the value is */
10793       if (AOP_TYPE (right) == AOP_LIT)
10794         {
10795           if (((int) operandLitValue (right)))
10796             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10797           else
10798             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10799
10800           goto release;
10801         }
10802
10803       /* the right is also a bit variable */
10804       if (AOP_TYPE (right) == AOP_CRY)
10805         {
10806           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10807           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10808           goto release;
10809         }
10810
10811       /* we need to or */
10812       toBoolean (right);
10813       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10814       goto release;
10815     }
10816
10817
10818   /* if they are the same size : or less */
10819   if (AOP_SIZE (result) <= AOP_SIZE (right))
10820     {
10821
10822       /* if they are in the same place */
10823       if (sameRegs (AOP (right), AOP (result)))
10824         goto release;
10825
10826       /* if they in different places then copy */
10827       size = AOP_SIZE (result);
10828       offset = 0;
10829       while (size--)
10830         {
10831           aopPut (result,
10832                   aopGet (right, offset, FALSE, FALSE),
10833                   offset,
10834                   isOperandVolatile (result, FALSE));
10835           offset++;
10836         }
10837       goto release;
10838     }
10839
10840
10841   /* if the result is of type pointer */
10842   if (IS_PTR (ctype))
10843     {
10844
10845       int p_type;
10846       sym_link *type = operandType (right);
10847       sym_link *etype = getSpec (type);
10848
10849       /* pointer to generic pointer */
10850       if (IS_GENPTR (ctype))
10851         {
10852           if (IS_PTR (type))
10853             p_type = DCL_TYPE (type);
10854           else
10855             {
10856               if (SPEC_SCLS(etype)==S_REGISTER) {
10857                 // let's assume it is a generic pointer
10858                 p_type=GPOINTER;
10859               } else {
10860                 /* we have to go by the storage class */
10861                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10862               }
10863             }
10864
10865           /* the first two bytes are known */
10866           size = GPTRSIZE - 1;
10867           offset = 0;
10868           while (size--)
10869             {
10870               aopPut (result,
10871                       aopGet (right, offset, FALSE, FALSE),
10872                       offset,
10873                       isOperandVolatile (result, FALSE));
10874               offset++;
10875             }
10876           /* the last byte depending on type */
10877             {
10878                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10879                 char gpValStr[10];
10880
10881                 if (gpVal == -1)
10882                 {
10883                     // pointerTypeToGPByte will have bitched.
10884                     exit(1);
10885                 }
10886
10887                 sprintf(gpValStr, "#0x%x", gpVal);
10888                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10889             }
10890           goto release;
10891         }
10892
10893       /* just copy the pointers */
10894       size = AOP_SIZE (result);
10895       offset = 0;
10896       while (size--)
10897         {
10898           aopPut (result,
10899                   aopGet (right, offset, FALSE, FALSE),
10900                   offset,
10901                   isOperandVolatile (result, FALSE));
10902           offset++;
10903         }
10904       goto release;
10905     }
10906
10907   /* so we now know that the size of destination is greater
10908      than the size of the source */
10909   /* we move to result for the size of source */
10910   size = AOP_SIZE (right);
10911   offset = 0;
10912   while (size--)
10913     {
10914       aopPut (result,
10915               aopGet (right, offset, FALSE, FALSE),
10916               offset,
10917               isOperandVolatile (result, FALSE));
10918       offset++;
10919     }
10920
10921   /* now depending on the sign of the source && destination */
10922   size = AOP_SIZE (result) - AOP_SIZE (right);
10923   /* if unsigned or not an integral type */
10924   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10925     {
10926       while (size--)
10927         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10928     }
10929   else
10930     {
10931       /* we need to extend the sign :{ */
10932       char *l = aopGet (right, AOP_SIZE (right) - 1,
10933                         FALSE, FALSE);
10934       MOVA (l);
10935       emitcode ("rlc", "a");
10936       emitcode ("subb", "a,acc");
10937       while (size--)
10938         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10939     }
10940
10941   /* we are done hurray !!!! */
10942
10943 release:
10944   freeAsmop (right, NULL, ic, TRUE);
10945   freeAsmop (result, NULL, ic, TRUE);
10946
10947 }
10948
10949 /*-----------------------------------------------------------------*/
10950 /* genDjnz - generate decrement & jump if not zero instrucion      */
10951 /*-----------------------------------------------------------------*/
10952 static int
10953 genDjnz (iCode * ic, iCode * ifx)
10954 {
10955   symbol *lbl, *lbl1;
10956   if (!ifx)
10957     return 0;
10958
10959   D(emitcode (";     genDjnz",""));
10960
10961   /* if the if condition has a false label
10962      then we cannot save */
10963   if (IC_FALSE (ifx))
10964     return 0;
10965
10966   /* if the minus is not of the form
10967      a = a - 1 */
10968   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10969       !IS_OP_LITERAL (IC_RIGHT (ic)))
10970     return 0;
10971
10972   if (operandLitValue (IC_RIGHT (ic)) != 1)
10973     return 0;
10974
10975   /* if the size of this greater than one then no
10976      saving */
10977   if (getSize (operandType (IC_RESULT (ic))) > 1)
10978     return 0;
10979
10980   /* otherwise we can save BIG */
10981   lbl = newiTempLabel (NULL);
10982   lbl1 = newiTempLabel (NULL);
10983
10984   aopOp (IC_RESULT (ic), ic, FALSE);
10985
10986   if (AOP_NEEDSACC(IC_RESULT(ic)))
10987   {
10988       /* If the result is accessed indirectly via
10989        * the accumulator, we must explicitly write
10990        * it back after the decrement.
10991        */
10992       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
10993
10994       if (strcmp(rByte, "a"))
10995       {
10996            /* Something is hopelessly wrong */
10997            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10998                    __FILE__, __LINE__);
10999            /* We can just give up; the generated code will be inefficient,
11000             * but what the hey.
11001             */
11002            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11003            return 0;
11004       }
11005       emitcode ("dec", "%s", rByte);
11006       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
11007       emitcode ("jnz", "%05d$", lbl->key + 100);
11008   }
11009   else if (IS_AOP_PREG (IC_RESULT (ic)))
11010     {
11011       emitcode ("dec", "%s",
11012                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11013       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11014       emitcode ("jnz", "%05d$", lbl->key + 100);
11015     }
11016   else
11017     {
11018       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11019                 lbl->key + 100);
11020     }
11021   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11022   emitcode ("", "%05d$:", lbl->key + 100);
11023   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11024   emitcode ("", "%05d$:", lbl1->key + 100);
11025
11026   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11027   ifx->generated = 1;
11028   return 1;
11029 }
11030
11031 /*-----------------------------------------------------------------*/
11032 /* genReceive - generate code for a receive iCode                  */
11033 /*-----------------------------------------------------------------*/
11034 static void
11035 genReceive (iCode * ic)
11036 {
11037   int size = getSize (operandType (IC_RESULT (ic)));
11038   int offset = 0;
11039
11040   D(emitcode (";     genReceive",""));
11041
11042   if (ic->argreg == 1)
11043     { /* first parameter */
11044       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11045            isOperandInPagedSpace (IC_RESULT (ic))) &&
11046           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11047            IS_TRUE_SYMOP (IC_RESULT (ic))))
11048         {
11049           regs *tempRegs[4];
11050           int receivingA = 0;
11051           int roffset = 0;
11052
11053           for (offset = 0; offset<size; offset++)
11054             if (!strcmp (fReturn[offset], "a"))
11055               receivingA = 1;
11056
11057           if (!receivingA)
11058             {
11059               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11060                 {
11061                   for (offset = size-1; offset>0; offset--)
11062                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11063                   emitcode("mov","a,%s", fReturn[0]);
11064                   _G.accInUse++;
11065                   aopOp (IC_RESULT (ic), ic, FALSE);
11066                   _G.accInUse--;
11067                   aopPut (IC_RESULT (ic), "a", offset,
11068                           isOperandVolatile (IC_RESULT (ic), FALSE));
11069                   for (offset = 1; offset<size; offset++)
11070                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
11071                             isOperandVolatile (IC_RESULT (ic), FALSE));
11072                   goto release;
11073                 }
11074             }
11075           else
11076             {
11077               if (getTempRegs(tempRegs, size, ic))
11078                 {
11079                   for (offset = 0; offset<size; offset++)
11080                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11081                   aopOp (IC_RESULT (ic), ic, FALSE);
11082                   for (offset = 0; offset<size; offset++)
11083                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
11084                             isOperandVolatile (IC_RESULT (ic), FALSE));
11085                   goto release;
11086                 }
11087             }
11088
11089           offset = fReturnSizeMCS51 - size;
11090           while (size--)
11091             {
11092               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11093                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11094               offset++;
11095             }
11096           aopOp (IC_RESULT (ic), ic, FALSE);
11097           size = AOP_SIZE (IC_RESULT (ic));
11098           offset = 0;
11099           while (size--)
11100             {
11101               emitcode ("pop", "acc");
11102               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11103             }
11104         }
11105       else
11106         {
11107           _G.accInUse++;
11108           aopOp (IC_RESULT (ic), ic, FALSE);
11109           _G.accInUse--;
11110           assignResultValue (IC_RESULT (ic), NULL);
11111         }
11112     }
11113   else if (ic->argreg > 12)
11114     { /* bit parameters */
11115       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11116         {
11117           aopOp (IC_RESULT (ic), ic, FALSE);
11118           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11119           outBitC(IC_RESULT (ic));
11120         }
11121     }
11122   else
11123     { /* other parameters */
11124       int rb1off ;
11125       aopOp (IC_RESULT (ic), ic, FALSE);
11126       rb1off = ic->argreg;
11127       while (size--)
11128         {
11129           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11130         }
11131     }
11132
11133 release:
11134   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11135 }
11136
11137 /*-----------------------------------------------------------------*/
11138 /* genDummyRead - generate code for dummy read of volatiles        */
11139 /*-----------------------------------------------------------------*/
11140 static void
11141 genDummyRead (iCode * ic)
11142 {
11143   operand *op;
11144   int size, offset;
11145
11146   D(emitcode(";     genDummyRead",""));
11147
11148   op = IC_RIGHT (ic);
11149   if (op && IS_SYMOP (op))
11150     {
11151       aopOp (op, ic, FALSE);
11152
11153       /* if the result is a bit */
11154       if (AOP_TYPE (op) == AOP_CRY)
11155         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11156       else
11157         {
11158           /* bit variables done */
11159           /* general case */
11160           size = AOP_SIZE (op);
11161           offset = 0;
11162           while (size--)
11163           {
11164             MOVA (aopGet (op, offset, FALSE, FALSE));
11165             offset++;
11166           }
11167         }
11168
11169       freeAsmop (op, NULL, ic, TRUE);
11170     }
11171
11172   op = IC_LEFT (ic);
11173   if (op && IS_SYMOP (op))
11174     {
11175       aopOp (op, ic, FALSE);
11176
11177       /* if the result is a bit */
11178       if (AOP_TYPE (op) == AOP_CRY)
11179         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11180       else
11181         {
11182           /* bit variables done */
11183           /* general case */
11184           size = AOP_SIZE (op);
11185           offset = 0;
11186           while (size--)
11187           {
11188             MOVA (aopGet (op, offset, FALSE, FALSE));
11189             offset++;
11190           }
11191         }
11192
11193       freeAsmop (op, NULL, ic, TRUE);
11194     }
11195 }
11196
11197 /*-----------------------------------------------------------------*/
11198 /* genCritical - generate code for start of a critical sequence    */
11199 /*-----------------------------------------------------------------*/
11200 static void
11201 genCritical (iCode *ic)
11202 {
11203   symbol *tlbl = newiTempLabel (NULL);
11204
11205   D(emitcode(";     genCritical",""));
11206
11207   if (IC_RESULT (ic))
11208     {
11209       aopOp (IC_RESULT (ic), ic, TRUE);
11210       aopPut (IC_RESULT (ic), one, 0, 0);
11211       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11212       aopPut (IC_RESULT (ic), zero, 0, 0);
11213       emitcode ("", "%05d$:", (tlbl->key + 100));
11214       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11215     }
11216   else
11217     {
11218       emitcode ("setb", "c");
11219       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11220       emitcode ("clr", "c");
11221       emitcode ("", "%05d$:", (tlbl->key + 100));
11222       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11223     }
11224 }
11225
11226 /*-----------------------------------------------------------------*/
11227 /* genEndCritical - generate code for end of a critical sequence   */
11228 /*-----------------------------------------------------------------*/
11229 static void
11230 genEndCritical (iCode *ic)
11231 {
11232   D(emitcode(";     genEndCritical",""));
11233
11234   if (IC_RIGHT (ic))
11235     {
11236       aopOp (IC_RIGHT (ic), ic, FALSE);
11237       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11238         {
11239           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11240           emitcode ("mov", "ea,c");
11241         }
11242       else
11243         {
11244           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11245             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11246           emitcode ("rrc", "a");
11247           emitcode ("mov", "ea,c");
11248         }
11249       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11250     }
11251   else
11252     {
11253       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11254       emitcode ("mov", "ea,c");
11255     }
11256 }
11257
11258 /*-----------------------------------------------------------------*/
11259 /* gen51Code - generate code for 8051 based controllers            */
11260 /*-----------------------------------------------------------------*/
11261 void
11262 gen51Code (iCode * lic)
11263 {
11264   iCode *ic;
11265   int cln = 0;
11266   /* int cseq = 0; */
11267
11268   _G.currentFunc = NULL;
11269   lineHead = lineCurr = NULL;
11270
11271   /* print the allocation information */
11272   if (allocInfo && currFunc)
11273     printAllocInfo (currFunc, codeOutFile);
11274   /* if debug information required */
11275   if (options.debug && currFunc)
11276     {
11277       debugFile->writeFunction (currFunc, lic);
11278     }
11279   /* stack pointer name */
11280   if (options.useXstack)
11281     spname = "_spx";
11282   else
11283     spname = "sp";
11284
11285
11286   for (ic = lic; ic; ic = ic->next)
11287     {
11288       _G.current_iCode = ic;
11289
11290       if (ic->lineno && cln != ic->lineno)
11291         {
11292           if (options.debug)
11293             {
11294               debugFile->writeCLine (ic);
11295             }
11296           if (!options.noCcodeInAsm) {
11297             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
11298                       printCLine(ic->filename, ic->lineno));
11299           }
11300           cln = ic->lineno;
11301         }
11302       #if 0
11303       if (ic->seqPoint && ic->seqPoint != cseq)
11304         {
11305           emitcode ("", "; sequence point %d", ic->seqPoint);
11306           cseq = ic->seqPoint;
11307         }
11308       #endif
11309       if (options.iCodeInAsm) {
11310         char regsInUse[80];
11311         int i;
11312
11313         for (i=0; i<8; i++) {
11314           sprintf (&regsInUse[i],
11315                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
11316         }
11317         regsInUse[i]=0;
11318         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11319       }
11320       /* if the result is marked as
11321          spilt and rematerializable or code for
11322          this has already been generated then
11323          do nothing */
11324       if (resultRemat (ic) || ic->generated)
11325         continue;
11326
11327       /* depending on the operation */
11328       switch (ic->op)
11329         {
11330         case '!':
11331           genNot (ic);
11332           break;
11333
11334         case '~':
11335           genCpl (ic);
11336           break;
11337
11338         case UNARYMINUS:
11339           genUminus (ic);
11340           break;
11341
11342         case IPUSH:
11343           genIpush (ic);
11344           break;
11345
11346         case IPOP:
11347           /* IPOP happens only when trying to restore a
11348              spilt live range, if there is an ifx statement
11349              following this pop then the if statement might
11350              be using some of the registers being popped which
11351              would destory the contents of the register so
11352              we need to check for this condition and handle it */
11353           if (ic->next &&
11354               ic->next->op == IFX &&
11355               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11356             genIfx (ic->next, ic);
11357           else
11358             genIpop (ic);
11359           break;
11360
11361         case CALL:
11362           genCall (ic);
11363           break;
11364
11365         case PCALL:
11366           genPcall (ic);
11367           break;
11368
11369         case FUNCTION:
11370           genFunction (ic);
11371           break;
11372
11373         case ENDFUNCTION:
11374           genEndFunction (ic);
11375           break;
11376
11377         case RETURN:
11378           genRet (ic);
11379           break;
11380
11381         case LABEL:
11382           genLabel (ic);
11383           break;
11384
11385         case GOTO:
11386           genGoto (ic);
11387           break;
11388
11389         case '+':
11390           genPlus (ic);
11391           break;
11392
11393         case '-':
11394           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11395             genMinus (ic);
11396           break;
11397
11398         case '*':
11399           genMult (ic);
11400           break;
11401
11402         case '/':
11403           genDiv (ic);
11404           break;
11405
11406         case '%':
11407           genMod (ic);
11408           break;
11409
11410         case '>':
11411           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11412           break;
11413
11414         case '<':
11415           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11416           break;
11417
11418         case LE_OP:
11419         case GE_OP:
11420         case NE_OP:
11421
11422           /* note these two are xlated by algebraic equivalence
11423              during parsing SDCC.y */
11424           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11425                   "got '>=' or '<=' shouldn't have come here");
11426           break;
11427
11428         case EQ_OP:
11429           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11430           break;
11431
11432         case AND_OP:
11433           genAndOp (ic);
11434           break;
11435
11436         case OR_OP:
11437           genOrOp (ic);
11438           break;
11439
11440         case '^':
11441           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11442           break;
11443
11444         case '|':
11445           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11446           break;
11447
11448         case BITWISEAND:
11449           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11450           break;
11451
11452         case INLINEASM:
11453           genInline (ic);
11454           break;
11455
11456         case RRC:
11457           genRRC (ic);
11458           break;
11459
11460         case RLC:
11461           genRLC (ic);
11462           break;
11463
11464         case GETHBIT:
11465           genGetHbit (ic);
11466           break;
11467
11468         case GETABIT:
11469           genGetAbit (ic);
11470           break;
11471
11472         case GETBYTE:
11473           genGetByte (ic);
11474           break;
11475
11476         case GETWORD:
11477           genGetWord (ic);
11478           break;
11479
11480         case LEFT_OP:
11481           genLeftShift (ic);
11482           break;
11483
11484         case RIGHT_OP:
11485           genRightShift (ic);
11486           break;
11487
11488         case GET_VALUE_AT_ADDRESS:
11489           genPointerGet (ic,
11490                          hasInc (IC_LEFT (ic), ic,
11491                                  getSize (operandType (IC_RESULT (ic)))),
11492                          ifxForOp (IC_RESULT (ic), ic) );
11493           break;
11494
11495         case '=':
11496           if (POINTER_SET (ic))
11497             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
11498           else
11499             genAssign (ic);
11500           break;
11501
11502         case IFX:
11503           genIfx (ic, NULL);
11504           break;
11505
11506         case ADDRESS_OF:
11507           genAddrOf (ic);
11508           break;
11509
11510         case JUMPTABLE:
11511           genJumpTab (ic);
11512           break;
11513
11514         case CAST:
11515           genCast (ic);
11516           break;
11517
11518         case RECEIVE:
11519           genReceive (ic);
11520           break;
11521
11522         case SEND:
11523           addSet (&_G.sendSet, ic);
11524           break;
11525
11526         case DUMMY_READ_VOLATILE:
11527           genDummyRead (ic);
11528           break;
11529
11530         case CRITICAL:
11531           genCritical (ic);
11532           break;
11533
11534         case ENDCRITICAL:
11535           genEndCritical (ic);
11536           break;
11537
11538         case SWAP:
11539           genSwap (ic);
11540           break;
11541
11542         default:
11543           ic = ic;
11544         }
11545     }
11546
11547   _G.current_iCode = NULL;
11548
11549   /* now we are ready to call the
11550      peep hole optimizer */
11551   if (!options.nopeep)
11552     peepHole (&lineHead);
11553
11554   /* now do the actual printing */
11555   printLine (lineHead, codeOutFile);
11556   return;
11557 }