* src/SDCCcse.c (ReplaceOpWithCheaperOp): minor fix for debugging only
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   SDCCgen51.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 //#define D(x)
32 #define D(x) x
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include "SDCCglobl.h"
39 #include "newalloc.h"
40
41 #include "common.h"
42 #include "SDCCpeeph.h"
43 #include "ralloc.h"
44 #include "gen.h"
45
46 char *aopLiteral (value * val, int offset);
47 char *aopLiteralLong (value * val, int offset, int size);
48 extern int allocInfo;
49
50 /* this is the down and dirty file with all kinds of
51    kludgy & hacky stuff. This is what it is all about
52    CODE GENERATION for a specific MCU . some of the
53    routines may be reusable, will have to see */
54
55 static char *zero = "#0x00";
56 static char *one = "#0x01";
57 static char *spname;
58
59 char *fReturn8051[] =
60 {"dpl", "dph", "b", "a"};
61 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
62 char **fReturn = fReturn8051;
63 static char *accUse[] =
64 {"a", "b"};
65
66 static unsigned short rbank = -1;
67
68 #define AOP(op) op->aop
69 #define AOP_TYPE(op) AOP(op)->type
70 #define AOP_SIZE(op) AOP(op)->size
71 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
72                        AOP_TYPE(x) == AOP_R0))
73
74 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
75                         AOP_TYPE(x) == AOP_DPTR || AOP(x)->paged))
76
77 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
78                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
79                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
80
81
82 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
83
84 #define R0INB   _G.bu.bs.r0InB
85 #define R1INB   _G.bu.bs.r1InB
86 #define OPINB   _G.bu.bs.OpInB
87 #define BINUSE  _G.bu.BInUse
88
89 static struct
90   {
91     short r0Pushed;
92     short r1Pushed;
93     union
94       {
95         struct
96           {
97             short r0InB : 2;//2 so we can see it overflow
98             short r1InB : 2;//2 so we can see it overflow
99             short OpInB : 2;//2 so we can see it overflow
100           } bs;
101         short BInUse;
102       } bu;
103     short accInUse;
104     short inLine;
105     short debugLine;
106     short nRegsSaved;
107     set *sendSet;
108     iCode *current_iCode;
109     symbol *currentFunc;
110   }
111 _G;
112
113 static char *rb1regs[] = {
114     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
115     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
116 };
117
118 extern int mcs51_ptrRegReq;
119 extern int mcs51_nRegs;
120 extern FILE *codeOutFile;
121 static void saveRBank (int, iCode *, bool);
122
123 #define RESULTONSTACK(x) \
124                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
125                          IC_RESULT(x)->aop->type == AOP_STK )
126
127 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
128 #define CLRC     emitcode("clr","c")
129 #define SETC     emitcode("setb","c")
130
131 static lineNode *lineHead = NULL;
132 static lineNode *lineCurr = NULL;
133
134 static unsigned char SLMask[] =
135 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
136  0xE0, 0xC0, 0x80, 0x00};
137 static unsigned char SRMask[] =
138 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
139  0x07, 0x03, 0x01, 0x00};
140
141 #define LSB     0
142 #define MSB16   1
143 #define MSB24   2
144 #define MSB32   3
145
146 /*-----------------------------------------------------------------*/
147 /* emitcode - writes the code into a file : for now it is simple    */
148 /*-----------------------------------------------------------------*/
149 static void
150 emitcode (char *inst, const char *fmt,...)
151 {
152   va_list ap;
153   char lb[INITIAL_INLINEASM];
154   char *lbp = lb;
155
156   va_start (ap, fmt);
157
158   if (inst && *inst)
159     {
160       if (fmt && *fmt)
161           SNPRINTF (lb, sizeof(lb), "%s\t", inst);
162       else
163           SNPRINTF (lb, sizeof(lb), "%s", inst);
164       tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb), fmt, ap);
165     }
166   else
167       tvsprintf (lb, sizeof(lb), fmt, ap);
168
169   while (isspace ((unsigned char)*lbp))
170       lbp++;
171
172   if (lbp && *lbp)
173       lineCurr = (lineCurr ?
174                   connectLine (lineCurr, newLineNode (lb)) :
175                   (lineHead = newLineNode (lb)));
176   lineCurr->isInline = _G.inLine;
177   lineCurr->isDebug = _G.debugLine;
178   lineCurr->ic = _G.current_iCode;
179   lineCurr->isComment = (*lbp==';');
180   va_end (ap);
181 }
182
183 /*-----------------------------------------------------------------*/
184 /* mcs51_emitDebuggerSymbol - associate the current code location  */
185 /*   with a debugger symbol                                        */
186 /*-----------------------------------------------------------------*/
187 void
188 mcs51_emitDebuggerSymbol (char * debugSym)
189 {
190   _G.debugLine = 1;
191   emitcode ("", "%s ==.", debugSym);
192   _G.debugLine = 0;
193 }
194
195 /*-----------------------------------------------------------------*/
196 /* mova - moves specified value into accumulator                   */
197 /*-----------------------------------------------------------------*/
198 static void
199 mova (const char *x)
200 {
201   /* do some early peephole optimization */
202   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
203     return;
204
205   emitcode("mov","a,%s", x);
206 }
207
208 /*-----------------------------------------------------------------*/
209 /* movc - moves specified value into the carry                     */
210 /*-----------------------------------------------------------------*/
211 static void
212 movc (const char *s)
213 {
214   if (s == zero)
215     CLRC;
216   else if (s == one)
217     SETC;
218   else if (strcmp (s, "c"))
219     {/* it's not in carry already */
220       MOVA (s);
221       /* set C, if a >= 1 */
222       emitcode ("add", "a,#0xff");
223     }
224 }
225
226 /*-----------------------------------------------------------------*/
227 /* pushB - saves register B if necessary                           */
228 /*-----------------------------------------------------------------*/
229 static bool
230 pushB (void)
231 {
232   bool pushedB = FALSE;
233
234   if (BINUSE)
235     {
236       emitcode ("push", "b");
237 //    printf("B was in use !\n");
238       pushedB = TRUE;
239     }
240   else
241     {
242       OPINB++;
243     }
244   return pushedB;
245 }
246
247 /*-----------------------------------------------------------------*/
248 /* popB - restores value of register B if necessary                */
249 /*-----------------------------------------------------------------*/
250 static void
251 popB (bool pushedB)
252 {
253   if (pushedB)
254     {
255       emitcode ("pop", "b");
256     }
257   else
258     {
259       OPINB--;
260     }
261 }
262
263 /*-----------------------------------------------------------------*/
264 /* pushReg - saves register                                        */
265 /*-----------------------------------------------------------------*/
266 static bool
267 pushReg (int index, bool bits_pushed)
268 {
269   regs * reg = mcs51_regWithIdx (index);
270   if (reg->type == REG_BIT)
271     {
272       if (!bits_pushed)
273         emitcode ("push", "%s", reg->base);
274       return TRUE;
275     }
276   else
277     emitcode ("push", "%s", reg->dname);
278   return bits_pushed;
279 }
280
281 /*-----------------------------------------------------------------*/
282 /* popReg - restores register                                      */
283 /*-----------------------------------------------------------------*/
284 static bool
285 popReg (int index, bool bits_popped)
286 {
287   regs * reg = mcs51_regWithIdx (index);
288   if (reg->type == REG_BIT)
289     {
290       if (!bits_popped)
291         emitcode ("pop", "%s", reg->base);
292       return TRUE;
293     }
294   else
295     emitcode ("pop", "%s", reg->dname);
296   return bits_popped;
297 }
298
299 /*-----------------------------------------------------------------*/
300 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
301 /*-----------------------------------------------------------------*/
302 static regs *
303 getFreePtr (iCode * ic, asmop ** aopp, bool result)
304 {
305   bool r0iu, r1iu;
306   bool r0ou, r1ou;
307
308   /* the logic: if r0 & r1 used in the instruction
309      then we are in trouble otherwise */
310
311   /* first check if r0 & r1 are used by this
312      instruction, in which case we are in trouble */
313   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
314   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
315   if (r0iu && r1iu) {
316       goto endOfWorld;
317     }
318
319   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
320   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
321
322   /* if no usage of r0 then return it */
323   if (!r0iu && !r0ou)
324     {
325       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
326       (*aopp)->type = AOP_R0;
327
328       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
329     }
330
331   /* if no usage of r1 then return it */
332   if (!r1iu && !r1ou)
333     {
334       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
335       (*aopp)->type = AOP_R1;
336
337       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R1_IDX);
338     }
339
340   /* now we know they both have usage */
341   /* if r0 not used in this instruction */
342   if (!r0iu)
343     {
344       /* push it if not already pushed */
345       if (ic->op == IPUSH)
346         {
347           emitcode ("mov", "b,%s",
348                     mcs51_regWithIdx (R0_IDX)->dname);
349           R0INB++;
350         }
351       else if (!_G.r0Pushed)
352         {
353           emitcode ("push", "%s",
354                     mcs51_regWithIdx (R0_IDX)->dname);
355           _G.r0Pushed++;
356         }
357
358       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
359       (*aopp)->type = AOP_R0;
360
361       return (*aopp)->aopu.aop_ptr = mcs51_regWithIdx (R0_IDX);
362     }
363
364   /* if r1 not used then */
365
366   if (!r1iu)
367     {
368       /* push it if not already pushed */
369       if (ic->op == IPUSH)
370         {
371           emitcode ("mov", "b,%s",
372                     mcs51_regWithIdx (R1_IDX)->dname);
373           R1INB++;
374         }
375       else if (!_G.r1Pushed)
376         {
377           emitcode ("push", "%s",
378                     mcs51_regWithIdx (R1_IDX)->dname);
379           _G.r1Pushed++;
380         }
381
382       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
383       (*aopp)->type = AOP_R1;
384       return mcs51_regWithIdx (R1_IDX);
385     }
386 endOfWorld:
387   /* I said end of world, but not quite end of world yet */
388   if (result) {
389     /* we can push it on the stack */
390     (*aopp)->type = AOP_STK;
391     return NULL;
392   } else {
393     /* in the case that result AND left AND right needs a pointer reg
394        we can safely use the result's */
395     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX)) {
396       (*aopp)->type = AOP_R0;
397       return mcs51_regWithIdx (R0_IDX);
398     }
399     if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX)) {
400       (*aopp)->type = AOP_R1;
401       return mcs51_regWithIdx (R1_IDX);
402     }
403   }
404
405   /* now this is REALLY the end of the world */
406   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
407           "getFreePtr should never reach here");
408   exit (1);
409 }
410
411
412 /*-----------------------------------------------------------------*/
413 /* getTempRegs - initialize an array of pointers to GPR registers */
414 /*               that are not in use. Returns 1 if the requested   */
415 /*               number of registers were available, 0 otherwise.  */
416 /*-----------------------------------------------------------------*/
417 int
418 getTempRegs(regs **tempRegs, int size, iCode *ic)
419 {
420   bitVect * freeRegs;
421   int i;
422   int offset;
423
424   if (!ic)
425     ic = _G.current_iCode;
426   if (!ic)
427     return 0;
428   if (!_G.currentFunc)
429     return 0;
430
431   freeRegs = newBitVect(8);
432   bitVectSetBit (freeRegs, R2_IDX);
433   bitVectSetBit (freeRegs, R3_IDX);
434   bitVectSetBit (freeRegs, R4_IDX);
435   bitVectSetBit (freeRegs, R5_IDX);
436   bitVectSetBit (freeRegs, R6_IDX);
437   bitVectSetBit (freeRegs, R7_IDX);
438
439   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
440     {
441       bitVect * newfreeRegs;
442       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
443       freeBitVect(freeRegs);
444       freeRegs = newfreeRegs;
445     }
446   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
447
448   offset = 0;
449   for (i=0; i<freeRegs->size; i++)
450     {
451       if (bitVectBitValue(freeRegs,i))
452         tempRegs[offset++] = mcs51_regWithIdx(i);
453       if (offset>=size)
454         {
455           freeBitVect(freeRegs);
456           return 1;
457         }
458     }
459
460   freeBitVect(freeRegs);
461   return 0;
462 }
463
464
465 /*-----------------------------------------------------------------*/
466 /* newAsmop - creates a new asmOp                                  */
467 /*-----------------------------------------------------------------*/
468 static asmop *
469 newAsmop (short type)
470 {
471   asmop *aop;
472
473   aop = Safe_calloc (1, sizeof (asmop));
474   aop->type = type;
475   return aop;
476 }
477
478 /*-----------------------------------------------------------------*/
479 /* pointerCode - returns the code for a pointer type               */
480 /*-----------------------------------------------------------------*/
481 static int
482 pointerCode (sym_link * etype)
483 {
484
485   return PTR_TYPE (SPEC_OCLS (etype));
486
487 }
488
489 /*-----------------------------------------------------------------*/
490 /* leftRightUseAcc - returns size of accumulator use by operands   */
491 /*-----------------------------------------------------------------*/
492 static int
493 leftRightUseAcc(iCode *ic)
494 {
495   operand *op;
496   int size;
497   int accuseSize = 0;
498   int accuse = 0;
499
500   if (!ic)
501     {
502       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
503               "null iCode pointer");
504       return 0;
505     }
506
507   if (ic->op == IFX)
508     {
509       op = IC_COND (ic);
510       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
511         {
512           accuse = 1;
513           size = getSize (OP_SYMBOL (op)->type);
514           if (size>accuseSize)
515             accuseSize = size;
516         }
517     }
518   else if (ic->op == JUMPTABLE)
519     {
520       op = IC_JTCOND (ic);
521       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
522         {
523           accuse = 1;
524           size = getSize (OP_SYMBOL (op)->type);
525           if (size>accuseSize)
526             accuseSize = size;
527         }
528     }
529   else
530     {
531       op = IC_LEFT (ic);
532       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
533         {
534           accuse = 1;
535           size = getSize (OP_SYMBOL (op)->type);
536           if (size>accuseSize)
537             accuseSize = size;
538         }
539       op = IC_RIGHT (ic);
540       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
541         {
542           accuse = 1;
543           size = getSize (OP_SYMBOL (op)->type);
544           if (size>accuseSize)
545             accuseSize = size;
546         }
547     }
548
549   if (accuseSize)
550     return accuseSize;
551   else
552     return accuse;
553 }
554
555 /*-----------------------------------------------------------------*/
556 /* aopForSym - for a true symbol                                   */
557 /*-----------------------------------------------------------------*/
558 static asmop *
559 aopForSym (iCode * ic, symbol * sym, bool result)
560 {
561   asmop *aop;
562   memmap *space;
563
564   wassertl (ic != NULL, "Got a null iCode");
565   wassertl (sym != NULL, "Got a null symbol");
566
567   space = SPEC_OCLS (sym->etype);
568
569   /* if already has one */
570   if (sym->aop)
571     return sym->aop;
572
573   /* assign depending on the storage class */
574   /* if it is on the stack or indirectly addressable */
575   /* space we need to assign either r0 or r1 to it   */
576   if (sym->onStack || sym->iaccess)
577     {
578       sym->aop = aop = newAsmop (0);
579       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
580       aop->size = getSize (sym->type);
581
582       /* now assign the address of the variable to
583          the pointer register */
584       if (aop->type != AOP_STK)
585         {
586
587           if (sym->onStack)
588             {
589               char offset = ((sym->stack < 0) ?
590                          ((char) (sym->stack - _G.nRegsSaved)) :
591                          ((char) sym->stack)) & 0xff;
592
593               if ((offset >= -3) && (offset <= 3))
594                 {
595                   emitcode ("mov", "%s,%s",
596                             aop->aopu.aop_ptr->name, SYM_BP (sym));
597                   while (offset < 0)
598                     {
599                       emitcode ("dec", aop->aopu.aop_ptr->name);
600                       offset++;
601                     }
602                   while (offset > 0)
603                     {
604                       emitcode ("inc", aop->aopu.aop_ptr->name);
605                       offset--;
606                     }
607                 }
608               else
609                 {
610                   if (_G.accInUse || leftRightUseAcc (ic))
611                     emitcode ("push", "acc");
612                   emitcode ("mov", "a,%s", SYM_BP (sym));
613                   emitcode ("add", "a,#0x%02x", offset);
614                   emitcode ("mov", "%s,a",
615                             aop->aopu.aop_ptr->name);
616                   if (_G.accInUse || leftRightUseAcc (ic))
617                     emitcode ("pop", "acc");
618                 }
619             }
620           else
621             emitcode ("mov", "%s,#%s",
622                       aop->aopu.aop_ptr->name,
623                       sym->rname);
624           aop->paged = space->paged;
625         }
626       else
627         aop->aopu.aop_stk = sym->stack;
628       return aop;
629     }
630
631   /* if in bit space */
632   if (IN_BITSPACE (space))
633     {
634       sym->aop = aop = newAsmop (AOP_CRY);
635       aop->aopu.aop_dir = sym->rname;
636       aop->size = getSize (sym->type);
637       return aop;
638     }
639   /* if it is in direct space */
640   if (IN_DIRSPACE (space))
641     {
642       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
643       //printTypeChainRaw(sym->type, NULL);
644       //printf("space = %s\n", space ? space->sname : "NULL");
645       sym->aop = aop = newAsmop (AOP_DIR);
646       aop->aopu.aop_dir = sym->rname;
647       aop->size = getSize (sym->type);
648       return aop;
649     }
650
651   /* special case for a function */
652   if (IS_FUNC (sym->type))
653     {
654       sym->aop = aop = newAsmop (AOP_IMMD);
655       aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (sym->rname) + 1);
656       strcpy (aop->aopu.aop_immd.aop_immd1, sym->rname);
657       aop->size = getSize (sym->type);
658       return aop;
659     }
660
661   /* only remaining is far space */
662   /* in which case DPTR gets the address */
663   sym->aop = aop = newAsmop (AOP_DPTR);
664   emitcode ("mov", "dptr,#%s", sym->rname);
665   aop->size = getSize (sym->type);
666
667   /* if it is in code space */
668   if (IN_CODESPACE (space))
669     aop->code = 1;
670
671   return aop;
672 }
673
674 /*-----------------------------------------------------------------*/
675 /* aopForRemat - rematerialzes an object                           */
676 /*-----------------------------------------------------------------*/
677 static asmop *
678 aopForRemat (symbol * sym)
679 {
680   iCode *ic = sym->rematiCode;
681   asmop *aop = newAsmop (AOP_IMMD);
682   int ptr_type = 0;
683   int val = 0;
684
685   for (;;)
686     {
687       if (ic->op == '+')
688         val += (int) operandLitValue (IC_RIGHT (ic));
689       else if (ic->op == '-')
690         val -= (int) operandLitValue (IC_RIGHT (ic));
691       else if (IS_CAST_ICODE(ic)) {
692               sym_link *from_type = operandType(IC_RIGHT(ic));
693               aop->aopu.aop_immd.from_cast_remat = 1;
694               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
695               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
696               continue;
697       } else break;
698
699       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
700     }
701
702   if (val)
703     sprintf (buffer, "(%s %c 0x%04x)",
704              OP_SYMBOL (IC_LEFT (ic))->rname,
705              val >= 0 ? '+' : '-',
706              abs (val) & 0xffff);
707   else
708     strcpy (buffer, OP_SYMBOL (IC_LEFT (ic))->rname);
709
710   aop->aopu.aop_immd.aop_immd1 = Safe_calloc (1, strlen (buffer) + 1);
711   strcpy (aop->aopu.aop_immd.aop_immd1, buffer);
712   /* set immd2 field if required */
713   if (aop->aopu.aop_immd.from_cast_remat) {
714           sprintf(buffer,"#0x%02x",ptr_type);
715           aop->aopu.aop_immd.aop_immd2 = Safe_calloc (1, strlen (buffer) + 1);
716           strcpy (aop->aopu.aop_immd.aop_immd2, buffer);
717   }
718
719   return aop;
720 }
721
722 /*-----------------------------------------------------------------*/
723 /* regsInCommon - two operands have some registers in common       */
724 /*-----------------------------------------------------------------*/
725 static bool
726 regsInCommon (operand * op1, operand * op2)
727 {
728   symbol *sym1, *sym2;
729   int i;
730
731   /* if they have registers in common */
732   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
733     return FALSE;
734
735   sym1 = OP_SYMBOL (op1);
736   sym2 = OP_SYMBOL (op2);
737
738   if (sym1->nRegs == 0 || sym2->nRegs == 0)
739     return FALSE;
740
741   for (i = 0; i < sym1->nRegs; i++)
742     {
743       int j;
744       if (!sym1->regs[i])
745         continue;
746
747       for (j = 0; j < sym2->nRegs; j++)
748         {
749           if (!sym2->regs[j])
750             continue;
751
752           if (sym2->regs[j] == sym1->regs[i])
753             return TRUE;
754         }
755     }
756
757   return FALSE;
758 }
759
760 /*-----------------------------------------------------------------*/
761 /* operandsEqu - equivalent                                        */
762 /*-----------------------------------------------------------------*/
763 static bool
764 operandsEqu (operand * op1, operand * op2)
765 {
766   symbol *sym1, *sym2;
767
768   /* if they're not symbols */
769   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
770     return FALSE;
771
772   sym1 = OP_SYMBOL (op1);
773   sym2 = OP_SYMBOL (op2);
774
775   /* if both are itemps & one is spilt
776      and the other is not then false */
777   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
778       sym1->isspilt != sym2->isspilt)
779     return FALSE;
780
781   /* if they are the same */
782   if (sym1 == sym2)
783     return TRUE;
784
785   /* if they have the same rname */
786   if (sym1->rname[0] && sym2->rname[0] &&
787       strcmp (sym1->rname, sym2->rname) == 0 &&
788       !(IS_PARM (op2) && IS_ITEMP (op1)))
789     return TRUE;
790
791   /* if left is a tmp & right is not */
792   if (IS_ITEMP (op1) &&
793       !IS_ITEMP (op2) &&
794       sym1->isspilt &&
795       (sym1->usl.spillLoc == sym2))
796     return TRUE;
797
798   if (IS_ITEMP (op2) &&
799       !IS_ITEMP (op1) &&
800       sym2->isspilt &&
801       sym1->level > 0 &&
802       (sym2->usl.spillLoc == sym1))
803     return TRUE;
804
805   return FALSE;
806 }
807
808 /*-----------------------------------------------------------------*/
809 /* sameRegs - two asmops have the same registers                   */
810 /*-----------------------------------------------------------------*/
811 static bool
812 sameRegs (asmop * aop1, asmop * aop2)
813 {
814   int i;
815
816   if (aop1 == aop2)
817     return TRUE;
818
819   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
820     return FALSE;
821
822   if (aop1->type != aop2->type)
823     return FALSE;
824
825   if (aop1->size != aop2->size)
826     return FALSE;
827
828   for (i = 0; i < aop1->size; i++)
829     if (aop1->aopu.aop_reg[i] !=
830         aop2->aopu.aop_reg[i])
831       return FALSE;
832
833   return TRUE;
834 }
835
836 /*-----------------------------------------------------------------*/
837 /* aopOp - allocates an asmop for an operand  :                    */
838 /*-----------------------------------------------------------------*/
839 static void
840 aopOp (operand * op, iCode * ic, bool result)
841 {
842   asmop *aop;
843   symbol *sym;
844   int i;
845
846   if (!op)
847     return;
848
849   /* if this a literal */
850   if (IS_OP_LITERAL (op))
851     {
852       op->aop = aop = newAsmop (AOP_LIT);
853       aop->aopu.aop_lit = op->operand.valOperand;
854       aop->size = getSize (operandType (op));
855       return;
856     }
857
858   /* if already has a asmop then continue */
859   if (op->aop )
860     return;
861
862   /* if the underlying symbol has a aop */
863   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
864     {
865       op->aop = OP_SYMBOL (op)->aop;
866       return;
867     }
868
869   /* if this is a true symbol */
870   if (IS_TRUE_SYMOP (op))
871     {
872       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
873       return;
874     }
875
876   /* this is a temporary : this has
877      only five choices :
878      a) register
879      b) spillocation
880      c) rematerialize
881      d) conditional
882      e) can be a return use only */
883
884   sym = OP_SYMBOL (op);
885
886   /* if the type is a conditional */
887   if (sym->regType == REG_CND)
888     {
889       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
890       aop->size = 0;
891       return;
892     }
893
894   /* if it is spilt then two situations
895      a) is rematerialize
896      b) has a spill location */
897   if (sym->isspilt || sym->nRegs == 0)
898     {
899
900       /* rematerialize it NOW */
901       if (sym->remat)
902         {
903           sym->aop = op->aop = aop =
904             aopForRemat (sym);
905           aop->size = getSize (sym->type);
906           return;
907         }
908
909       if (sym->accuse)
910         {
911           int i;
912           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
913           aop->size = getSize (sym->type);
914           for (i = 0; i < 2; i++)
915             aop->aopu.aop_str[i] = accUse[i];
916           return;
917         }
918
919       if (sym->ruonly)
920         {
921           unsigned i;
922
923           aop = op->aop = sym->aop = newAsmop (AOP_STR);
924           aop->size = getSize (sym->type);
925           for (i = 0; i < fReturnSizeMCS51; i++)
926             aop->aopu.aop_str[i] = fReturn[i];
927           return;
928         }
929
930       if (sym->usl.spillLoc)
931         {
932           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
933             {
934               /* force a new aop if sizes differ */
935               sym->usl.spillLoc->aop = NULL;
936             }
937           sym->aop = op->aop = aop =
938                      aopForSym (ic, sym->usl.spillLoc, result);
939           aop->size = getSize (sym->type);
940           return;
941         }
942
943       /* else must be a dummy iTemp */
944       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
945       aop->size = getSize (sym->type);
946       return;
947     }
948
949   /* if the type is a bit register */
950   if (sym->regType == REG_BIT)
951     {
952       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
953       aop->size = sym->nRegs;//1???
954       aop->aopu.aop_reg[0] = sym->regs[0];
955       aop->aopu.aop_dir = sym->regs[0]->name;
956       return;
957     }
958
959   /* must be in a register */
960   sym->aop = op->aop = aop = newAsmop (AOP_REG);
961   aop->size = sym->nRegs;
962   for (i = 0; i < sym->nRegs; i++)
963     aop->aopu.aop_reg[i] = sym->regs[i];
964 }
965
966 /*-----------------------------------------------------------------*/
967 /* freeAsmop - free up the asmop given to an operand               */
968 /*----------------------------------------------------------------*/
969 static void
970 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
971 {
972   asmop *aop;
973
974   if (!op)
975     aop = aaop;
976   else
977     aop = op->aop;
978
979   if (!aop)
980     return;
981
982   if (aop->freed)
983     goto dealloc;
984
985   aop->freed = 1;
986
987   /* depending on the asmop type only three cases need work AOP_RO
988      , AOP_R1 && AOP_STK */
989   switch (aop->type)
990     {
991     case AOP_R0:
992       if (R0INB)
993         {
994           emitcode ("mov", "r0,b");
995           R0INB--;
996         }
997       else if (_G.r0Pushed)
998         {
999           if (pop)
1000             {
1001               emitcode ("pop", "ar0");
1002               _G.r0Pushed--;
1003             }
1004         }
1005       bitVectUnSetBit (ic->rUsed, R0_IDX);
1006       break;
1007
1008     case AOP_R1:
1009       if (R1INB)
1010         {
1011           emitcode ("mov", "r1,b");
1012           R1INB--;
1013         }
1014       if (_G.r1Pushed)
1015         {
1016           if (pop)
1017             {
1018               emitcode ("pop", "ar1");
1019               _G.r1Pushed--;
1020             }
1021         }
1022       bitVectUnSetBit (ic->rUsed, R1_IDX);
1023       break;
1024
1025     case AOP_STK:
1026       {
1027         int sz = aop->size;
1028         int stk = aop->aopu.aop_stk + aop->size - 1;
1029         bitVectUnSetBit (ic->rUsed, R0_IDX);
1030         bitVectUnSetBit (ic->rUsed, R1_IDX);
1031
1032         getFreePtr (ic, &aop, FALSE);
1033
1034         if (stk)
1035           {
1036             emitcode ("mov", "a,_bp");
1037             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1038             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1039           }
1040         else
1041           {
1042             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1043           }
1044
1045         while (sz--)
1046           {
1047             emitcode ("pop", "acc");
1048             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1049             if (!sz)
1050               break;
1051             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1052           }
1053         op->aop = aop;
1054         freeAsmop (op, NULL, ic, TRUE);
1055         if (_G.r1Pushed)
1056           {
1057             emitcode ("pop", "ar1");
1058             _G.r1Pushed--;
1059           }
1060
1061         if (_G.r0Pushed)
1062           {
1063             emitcode ("pop", "ar0");
1064             _G.r0Pushed--;
1065           }
1066       }
1067     }
1068
1069 dealloc:
1070   /* all other cases just dealloc */
1071   if (op)
1072     {
1073       op->aop = NULL;
1074       if (IS_SYMOP (op))
1075         {
1076           OP_SYMBOL (op)->aop = NULL;
1077           /* if the symbol has a spill */
1078           if (SPIL_LOC (op))
1079             SPIL_LOC (op)->aop = NULL;
1080         }
1081     }
1082 }
1083
1084 /*------------------------------------------------------------------*/
1085 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1086 /*                      pop r0 or r1 off stack if pushed            */
1087 /*------------------------------------------------------------------*/
1088 static void
1089 freeForBranchAsmop (operand * op)
1090 {
1091   asmop *aop;
1092
1093   if (!op)
1094     return;
1095
1096   aop = op->aop;
1097
1098   if (!aop)
1099     return;
1100
1101   if (aop->freed)
1102     return;
1103
1104   switch (aop->type)
1105     {
1106     case AOP_R0:
1107       if (R0INB)
1108         {
1109           emitcode ("mov", "r0,b");
1110         }
1111       else if (_G.r0Pushed)
1112         {
1113           emitcode ("pop", "ar0");
1114         }
1115       break;
1116
1117     case AOP_R1:
1118       if (R1INB)
1119         {
1120           emitcode ("mov", "r1,b");
1121         }
1122       else if (_G.r1Pushed)
1123         {
1124           emitcode ("pop", "ar1");
1125         }
1126       break;
1127
1128     case AOP_STK:
1129       {
1130         int sz = aop->size;
1131         int stk = aop->aopu.aop_stk + aop->size - 1;
1132
1133         emitcode ("mov", "b,r0");
1134         if (stk)
1135           {
1136             emitcode ("mov", "a,_bp");
1137             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1138             emitcode ("mov", "r0,a");
1139           }
1140         else
1141           {
1142             emitcode ("mov", "r0,_bp");
1143           }
1144
1145         while (sz--)
1146           {
1147             emitcode ("pop", "acc");
1148             emitcode ("mov", "@r0,a");
1149             if (!sz)
1150               break;
1151             emitcode ("dec", "r0");
1152           }
1153         emitcode ("mov", "r0,b");
1154       }
1155     }
1156
1157 }
1158
1159 /*-----------------------------------------------------------------*/
1160 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1161 /*                 clobber the accumulator                         */
1162 /*-----------------------------------------------------------------*/
1163 static bool
1164 aopGetUsesAcc (operand * oper, int offset)
1165 {
1166   asmop * aop = AOP (oper);
1167
1168   if (offset > (aop->size - 1))
1169     return FALSE;
1170
1171   switch (aop->type)
1172     {
1173
1174     case AOP_R0:
1175     case AOP_R1:
1176       if (aop->paged)
1177         return TRUE;
1178       return FALSE;
1179     case AOP_DPTR:
1180       return TRUE;
1181     case AOP_IMMD:
1182       return FALSE;
1183     case AOP_DIR:
1184       return FALSE;
1185     case AOP_REG:
1186       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1187       return FALSE;
1188     case AOP_CRY:
1189       return TRUE;
1190     case AOP_ACC:
1191       if (offset)
1192         return FALSE;
1193       return TRUE;
1194     case AOP_LIT:
1195       return FALSE;
1196     case AOP_STR:
1197       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1198         return TRUE;
1199       return FALSE;
1200     case AOP_DUMMY:
1201       return FALSE;
1202     default:
1203       /* Error case --- will have been caught already */
1204       wassert(0);
1205       return FALSE;
1206     }
1207 }
1208
1209 /*-----------------------------------------------------------------*/
1210 /* aopGet - for fetching value of the aop                          */
1211 /*-----------------------------------------------------------------*/
1212 static char *
1213 aopGet (operand * oper, int offset, bool bit16, bool dname)
1214 {
1215   char *s = buffer;
1216   char *rs;
1217   asmop * aop = AOP (oper);
1218
1219   /* offset is greater than
1220      size then zero */
1221   if (offset > (aop->size - 1) &&
1222       aop->type != AOP_LIT)
1223     return zero;
1224
1225   /* depending on type */
1226   switch (aop->type)
1227     {
1228     case AOP_DUMMY:
1229       return zero;
1230
1231     case AOP_R0:
1232     case AOP_R1:
1233       /* if we need to increment it */
1234       while (offset > aop->coff)
1235         {
1236           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1237           aop->coff++;
1238         }
1239
1240       while (offset < aop->coff)
1241         {
1242           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1243           aop->coff--;
1244         }
1245
1246       aop->coff = offset;
1247       if (aop->paged)
1248         {
1249           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1250           return (dname ? "acc" : "a");
1251         }
1252       sprintf (s, "@%s", aop->aopu.aop_ptr->name);
1253       rs = Safe_calloc (1, strlen (s) + 1);
1254       strcpy (rs, s);
1255       return rs;
1256
1257     case AOP_DPTR:
1258       if (aop->code && aop->coff==0 && offset>=1) {
1259         emitcode ("mov", "a,#0x%02x", offset);
1260         emitcode ("movc", "a,@a+dptr");
1261         return (dname ? "acc" : "a");
1262       }
1263
1264       while (offset > aop->coff)
1265         {
1266           emitcode ("inc", "dptr");
1267           aop->coff++;
1268         }
1269
1270       while (offset < aop->coff)
1271         {
1272           emitcode ("lcall", "__decdptr");
1273           aop->coff--;
1274         }
1275
1276       aop->coff = offset;
1277       if (aop->code)
1278         {
1279           emitcode ("clr", "a");
1280           emitcode ("movc", "a,@a+dptr");
1281         }
1282       else
1283         {
1284           emitcode ("movx", "a,@dptr");
1285         }
1286       return (dname ? "acc" : "a");
1287
1288
1289     case AOP_IMMD:
1290       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1))) {
1291               sprintf(s,"%s",aop->aopu.aop_immd.aop_immd2);
1292       } else if (bit16)
1293         sprintf (s, "#%s", aop->aopu.aop_immd.aop_immd1);
1294       else if (offset)
1295         sprintf (s, "#(%s >> %d)",
1296                  aop->aopu.aop_immd.aop_immd1,
1297                  offset * 8);
1298       else
1299         sprintf (s, "#%s",
1300                  aop->aopu.aop_immd.aop_immd1);
1301       rs = Safe_calloc (1, strlen (s) + 1);
1302       strcpy (rs, s);
1303       return rs;
1304
1305     case AOP_DIR:
1306       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1307         sprintf (s, "(%s >> %d)",
1308                  aop->aopu.aop_dir, offset * 8);
1309       else if (offset)
1310         sprintf (s, "(%s + %d)",
1311                  aop->aopu.aop_dir,
1312                  offset);
1313       else
1314         sprintf (s, "%s", aop->aopu.aop_dir);
1315       rs = Safe_calloc (1, strlen (s) + 1);
1316       strcpy (rs, s);
1317       return rs;
1318
1319     case AOP_REG:
1320       if (dname)
1321         return aop->aopu.aop_reg[offset]->dname;
1322       else
1323         return aop->aopu.aop_reg[offset]->name;
1324
1325     case AOP_CRY:
1326       emitcode ("clr", "a");
1327       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1328       emitcode ("rlc", "a");
1329       return (dname ? "acc" : "a");
1330
1331     case AOP_ACC:
1332       if (!offset && dname)
1333         return "acc";
1334       return aop->aopu.aop_str[offset];
1335
1336     case AOP_LIT:
1337       return aopLiteral (aop->aopu.aop_lit, offset);
1338
1339     case AOP_STR:
1340       aop->coff = offset;
1341       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1342           dname)
1343         return "acc";
1344
1345       return aop->aopu.aop_str[offset];
1346
1347     }
1348
1349   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1350           "aopget got unsupported aop->type");
1351   exit (1);
1352 }
1353
1354 /*-----------------------------------------------------------------*/
1355 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1356 /*                 clobber the accumulator                         */
1357 /*-----------------------------------------------------------------*/
1358 static bool
1359 aopPutUsesAcc (operand * oper, const char *s, int offset)
1360 {
1361   asmop * aop = AOP (oper);
1362
1363   if (offset > (aop->size - 1))
1364     return FALSE;
1365
1366   switch (aop->type)
1367     {
1368     case AOP_DUMMY:
1369       return TRUE;
1370     case AOP_DIR:
1371       return FALSE;
1372     case AOP_REG:
1373       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1374       return FALSE;
1375     case AOP_DPTR:
1376       return TRUE;
1377     case AOP_R0:
1378     case AOP_R1:
1379       return ((aop->paged) || (*s == '@'));
1380     case AOP_STK:
1381       return (*s == '@');
1382     case AOP_CRY:
1383       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1384     case AOP_STR:
1385       return FALSE;
1386     case AOP_IMMD:
1387       return FALSE;
1388     case AOP_ACC:
1389       return FALSE;
1390     default:
1391       /* Error case --- will have been caught already */
1392       wassert(0);
1393       return FALSE;
1394     }
1395 }
1396
1397 /*-----------------------------------------------------------------*/
1398 /* aopPut - puts a string for a aop and indicates if acc is in use */
1399 /*-----------------------------------------------------------------*/
1400 static bool
1401 aopPut (operand * result, const char *s, int offset, bool bvolatile)
1402 {
1403   char *d = buffer;
1404   bool accuse = FALSE;
1405   asmop * aop = AOP (result);
1406
1407   if (aop->size && offset > (aop->size - 1))
1408     {
1409       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1410               "aopPut got offset > aop->size");
1411       exit (1);
1412     }
1413
1414   /* will assign value to value */
1415   /* depending on where it is ofcourse */
1416   switch (aop->type)
1417     {
1418     case AOP_DUMMY:
1419       MOVA (s);         /* read s in case it was volatile */
1420       accuse = TRUE;
1421       break;
1422
1423     case AOP_DIR:
1424       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1425         sprintf (d, "(%s >> %d)", aop->aopu.aop_dir, offset * 8);
1426       else if (offset)
1427         sprintf (d, "(%s + %d)", aop->aopu.aop_dir, offset);
1428       else
1429         sprintf (d, "%s", aop->aopu.aop_dir);
1430
1431       if (strcmp (d, s) || bvolatile)
1432           emitcode ("mov", "%s,%s", d, s);
1433       if (!strcmp (d, "acc"))
1434           accuse = TRUE;
1435
1436       break;
1437
1438     case AOP_REG:
1439       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1440           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1441         {
1442           if (*s == '@' ||
1443               strcmp (s, "r0") == 0 ||
1444               strcmp (s, "r1") == 0 ||
1445               strcmp (s, "r2") == 0 ||
1446               strcmp (s, "r3") == 0 ||
1447               strcmp (s, "r4") == 0 ||
1448               strcmp (s, "r5") == 0 ||
1449               strcmp (s, "r6") == 0 ||
1450               strcmp (s, "r7") == 0)
1451             emitcode ("mov", "%s,%s",
1452                       aop->aopu.aop_reg[offset]->dname, s);
1453           else
1454             emitcode ("mov", "%s,%s",
1455                       aop->aopu.aop_reg[offset]->name, s);
1456         }
1457       break;
1458
1459     case AOP_DPTR:
1460       if (aop->code)
1461         {
1462           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1463                   "aopPut writing to code space");
1464           exit (1);
1465         }
1466
1467       while (offset > aop->coff)
1468         {
1469           aop->coff++;
1470           emitcode ("inc", "dptr");
1471         }
1472
1473       while (offset < aop->coff)
1474         {
1475           aop->coff--;
1476           emitcode ("lcall", "__decdptr");
1477         }
1478
1479       aop->coff = offset;
1480
1481       /* if not in accumulator */
1482       MOVA (s);
1483
1484       emitcode ("movx", "@dptr,a");
1485       break;
1486
1487     case AOP_R0:
1488     case AOP_R1:
1489       while (offset > aop->coff)
1490         {
1491           aop->coff++;
1492           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1493         }
1494       while (offset < aop->coff)
1495         {
1496           aop->coff--;
1497           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1498         }
1499       aop->coff = offset;
1500
1501       if (aop->paged)
1502         {
1503           MOVA (s);
1504           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1505         }
1506       else if (*s == '@')
1507         {
1508           MOVA (s);
1509           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1510         }
1511       else if (strcmp (s, "r0") == 0 ||
1512                strcmp (s, "r1") == 0 ||
1513                strcmp (s, "r2") == 0 ||
1514                strcmp (s, "r3") == 0 ||
1515                strcmp (s, "r4") == 0 ||
1516                strcmp (s, "r5") == 0 ||
1517                strcmp (s, "r6") == 0 ||
1518                strcmp (s, "r7") == 0)
1519         {
1520           char buffer[10];
1521           sprintf (buffer, "a%s", s);
1522           emitcode ("mov", "@%s,%s",
1523                     aop->aopu.aop_ptr->name, buffer);
1524         }
1525       else
1526         emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1527
1528       break;
1529
1530     case AOP_STK:
1531       if (strcmp (s, "a") == 0)
1532         emitcode ("push", "acc");
1533       else
1534         if (*s=='@') {
1535           MOVA(s);
1536           emitcode ("push", "acc");
1537         } else {
1538           emitcode ("push", s);
1539         }
1540
1541       break;
1542
1543     case AOP_CRY:
1544       /* if not bit variable */
1545       if (!aop->aopu.aop_dir)
1546         {
1547           /* inefficient: move carry into A and use jz/jnz */
1548           emitcode ("clr", "a");
1549           emitcode ("rlc", "a");
1550           accuse = TRUE;
1551         }
1552       else
1553         {
1554           if (s == zero)
1555             emitcode ("clr", "%s", aop->aopu.aop_dir);
1556           else if (s == one)
1557             emitcode ("setb", "%s", aop->aopu.aop_dir);
1558           else if (!strcmp (s, "c"))
1559             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1560           else if (strcmp (s, aop->aopu.aop_dir))
1561             {
1562               MOVA (s);
1563               /* set C, if a >= 1 */
1564               emitcode ("add", "a,#0xff");
1565               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1566             }
1567         }
1568       break;
1569
1570     case AOP_STR:
1571       aop->coff = offset;
1572       if (strcmp (aop->aopu.aop_str[offset], s) ||
1573           bvolatile)
1574         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1575       break;
1576
1577     case AOP_ACC:
1578       accuse = TRUE;
1579       aop->coff = offset;
1580       if (!offset && (strcmp (s, "acc") == 0) &&
1581           !bvolatile)
1582         break;
1583
1584       if (strcmp (aop->aopu.aop_str[offset], s) &&
1585           !bvolatile)
1586         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1587       break;
1588
1589     default:
1590       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1591               "aopPut got unsupported aop->type");
1592       exit (1);
1593     }
1594
1595     return accuse;
1596 }
1597
1598
1599 #if 0
1600 /*-----------------------------------------------------------------*/
1601 /* pointToEnd :- points to the last byte of the operand            */
1602 /*-----------------------------------------------------------------*/
1603 static void
1604 pointToEnd (asmop * aop)
1605 {
1606   int count;
1607   if (!aop)
1608     return;
1609
1610   aop->coff = count = (aop->size - 1);
1611   switch (aop->type)
1612     {
1613     case AOP_R0:
1614     case AOP_R1:
1615       while (count--)
1616         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1617       break;
1618     case AOP_DPTR:
1619       while (count--)
1620         emitcode ("inc", "dptr");
1621       break;
1622     }
1623
1624 }
1625 #endif
1626
1627 /*-----------------------------------------------------------------*/
1628 /* reAdjustPreg - points a register back to where it should        */
1629 /*-----------------------------------------------------------------*/
1630 static void
1631 reAdjustPreg (asmop * aop)
1632 {
1633   if ((aop->coff==0) || aop->size <= 1)
1634     return;
1635
1636   switch (aop->type)
1637     {
1638     case AOP_R0:
1639     case AOP_R1:
1640       while (aop->coff--)
1641         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1642       break;
1643     case AOP_DPTR:
1644       while (aop->coff--)
1645         {
1646           emitcode ("lcall", "__decdptr");
1647         }
1648       break;
1649     }
1650   aop->coff = 0;
1651 }
1652
1653 /*-----------------------------------------------------------------*/
1654 /* opIsGptr: returns non-zero if the passed operand is       */
1655 /* a generic pointer type.             */
1656 /*-----------------------------------------------------------------*/
1657 static int
1658 opIsGptr (operand * op)
1659 {
1660   sym_link *type = operandType (op);
1661
1662   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1663     {
1664       return 1;
1665     }
1666   return 0;
1667 }
1668
1669 /*-----------------------------------------------------------------*/
1670 /* getDataSize - get the operand data size                         */
1671 /*-----------------------------------------------------------------*/
1672 static int
1673 getDataSize (operand * op)
1674 {
1675   int size;
1676   size = AOP_SIZE (op);
1677   if (size == GPTRSIZE)
1678     {
1679       sym_link *type = operandType (op);
1680       if (IS_GENPTR (type))
1681         {
1682           /* generic pointer; arithmetic operations
1683            * should ignore the high byte (pointer type).
1684            */
1685           size--;
1686         }
1687     }
1688   return size;
1689 }
1690
1691 /*-----------------------------------------------------------------*/
1692 /* outAcc - output Acc                                             */
1693 /*-----------------------------------------------------------------*/
1694 static void
1695 outAcc (operand * result)
1696 {
1697   int size, offset;
1698   size = getDataSize (result);
1699   if (size)
1700     {
1701       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
1702       size--;
1703       offset = 1;
1704       /* unsigned or positive */
1705       while (size--)
1706         {
1707           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
1708         }
1709     }
1710 }
1711
1712 /*-----------------------------------------------------------------*/
1713 /* outBitC - output a bit C                                        */
1714 /*-----------------------------------------------------------------*/
1715 static void
1716 outBitC (operand * result)
1717 {
1718   /* if the result is bit */
1719   if (AOP_TYPE (result) == AOP_CRY)
1720     aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
1721   else
1722     {
1723       emitcode ("clr", "a");
1724       emitcode ("rlc", "a");
1725       outAcc (result);
1726     }
1727 }
1728
1729 /*-----------------------------------------------------------------*/
1730 /* toBoolean - emit code for orl a,operator(sizeop)                */
1731 /*-----------------------------------------------------------------*/
1732 static void
1733 toBoolean (operand * oper)
1734 {
1735   int size = AOP_SIZE (oper) - 1;
1736   int offset = 1;
1737   bool AccUsed = FALSE;
1738   bool pushedB;
1739
1740   while (!AccUsed && size--)
1741     {
1742       AccUsed |= aopGetUsesAcc(oper, offset++);
1743     }
1744
1745   size = AOP_SIZE (oper) - 1;
1746   offset = 1;
1747   MOVA (aopGet (oper, 0, FALSE, FALSE));
1748   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1749     {
1750       pushedB = pushB ();
1751       emitcode("mov", "b,a");
1752       while (--size)
1753         {
1754           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1755           emitcode ("orl", "b,a");
1756         }
1757       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1758       emitcode ("orl", "a,b");
1759       popB (pushedB);
1760     }
1761   else
1762     {
1763       while (size--)
1764         {
1765           emitcode ("orl", "a,%s", aopGet (oper, offset++, FALSE, FALSE));
1766         }
1767     }
1768 }
1769
1770
1771 /*-----------------------------------------------------------------*/
1772 /* genNot - generate code for ! operation                          */
1773 /*-----------------------------------------------------------------*/
1774 static void
1775 genNot (iCode * ic)
1776 {
1777   symbol *tlbl;
1778
1779   D(emitcode (";     genNot",""));
1780
1781   /* assign asmOps to operand & result */
1782   aopOp (IC_LEFT (ic), ic, FALSE);
1783   aopOp (IC_RESULT (ic), ic, TRUE);
1784
1785   /* if in bit space then a special case */
1786   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1787     {
1788       /* if left==result then cpl bit */
1789       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1790         {
1791           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1792         }
1793       else
1794         {
1795           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1796           emitcode ("cpl", "c");
1797           outBitC (IC_RESULT (ic));
1798         }
1799       goto release;
1800     }
1801
1802   toBoolean (IC_LEFT (ic));
1803
1804   /* set C, if a == 0 */
1805   tlbl = newiTempLabel (NULL);
1806   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1807   emitcode ("", "%05d$:", tlbl->key + 100);
1808   outBitC (IC_RESULT (ic));
1809
1810 release:
1811   /* release the aops */
1812   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1813   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1814 }
1815
1816
1817 /*-----------------------------------------------------------------*/
1818 /* genCpl - generate code for complement                           */
1819 /*-----------------------------------------------------------------*/
1820 static void
1821 genCpl (iCode * ic)
1822 {
1823   int offset = 0;
1824   int size;
1825   symbol *tlbl;
1826   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1827
1828   D(emitcode (";", "genCpl"));
1829
1830   /* assign asmOps to operand & result */
1831   aopOp (IC_LEFT (ic), ic, FALSE);
1832   aopOp (IC_RESULT (ic), ic, TRUE);
1833
1834   /* special case if in bit space */
1835   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
1836     {
1837       char *l;
1838
1839       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
1840           (SPEC_USIGN (letype) && IS_CHAR (letype)))
1841         {
1842           /* promotion rules are responsible for this strange result:
1843              bit -> int -> ~int -> bit
1844              uchar -> int -> ~int -> bit
1845           */
1846           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
1847           goto release;
1848         }
1849
1850       tlbl=newiTempLabel(NULL);
1851       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
1852       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
1853           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
1854           IS_AOP_PREG (IC_LEFT (ic)))
1855         {
1856           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
1857         }
1858       else
1859         {
1860           MOVA (l);
1861           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
1862         }
1863       emitcode ("", "%05d$:", tlbl->key + 100);
1864       outBitC (IC_RESULT(ic));
1865       goto release;
1866     }
1867
1868   size = AOP_SIZE (IC_RESULT (ic));
1869   while (size--)
1870     {
1871       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1872       MOVA (l);
1873       emitcode ("cpl", "a");
1874       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1875     }
1876
1877
1878 release:
1879   /* release the aops */
1880   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1881   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1882 }
1883
1884 /*-----------------------------------------------------------------*/
1885 /* genUminusFloat - unary minus for floating points                */
1886 /*-----------------------------------------------------------------*/
1887 static void
1888 genUminusFloat (operand * op, operand * result)
1889 {
1890   int size, offset = 0;
1891   char *l;
1892
1893   D(emitcode (";     genUminusFloat",""));
1894
1895   /* for this we just copy and then flip the bit */
1896
1897   size = AOP_SIZE (op) - 1;
1898
1899   while (size--)
1900     {
1901       aopPut (result,
1902               aopGet (op, offset, FALSE, FALSE),
1903               offset,
1904               isOperandVolatile (result, FALSE));
1905       offset++;
1906     }
1907
1908   l = aopGet (op, offset, FALSE, FALSE);
1909
1910   MOVA (l);
1911
1912   emitcode ("cpl", "acc.7");
1913   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
1914 }
1915
1916 /*-----------------------------------------------------------------*/
1917 /* genUminus - unary minus code generation                         */
1918 /*-----------------------------------------------------------------*/
1919 static void
1920 genUminus (iCode * ic)
1921 {
1922   int offset, size;
1923   sym_link *optype, *rtype;
1924
1925
1926   D(emitcode (";     genUminus",""));
1927
1928   /* assign asmops */
1929   aopOp (IC_LEFT (ic), ic, FALSE);
1930   aopOp (IC_RESULT (ic), ic, TRUE);
1931
1932   /* if both in bit space then special
1933      case */
1934   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1935       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1936     {
1937
1938       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1939       emitcode ("cpl", "c");
1940       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1941       goto release;
1942     }
1943
1944   optype = operandType (IC_LEFT (ic));
1945   rtype = operandType (IC_RESULT (ic));
1946
1947   /* if float then do float stuff */
1948   if (IS_FLOAT (optype))
1949     {
1950       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
1951       goto release;
1952     }
1953
1954   /* otherwise subtract from zero */
1955   size = AOP_SIZE (IC_LEFT (ic));
1956   offset = 0;
1957   //CLRC ;
1958   while (size--)
1959     {
1960       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
1961       if (!strcmp (l, "a"))
1962         {
1963           if (offset == 0)
1964             SETC;
1965           emitcode ("cpl", "a");
1966           emitcode ("addc", "a,#0");
1967         }
1968       else
1969         {
1970           if (offset == 0)
1971             CLRC;
1972           emitcode ("clr", "a");
1973           emitcode ("subb", "a,%s", l);
1974         }
1975       aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1976     }
1977
1978   /* if any remaining bytes in the result */
1979   /* we just need to propagate the sign   */
1980   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
1981     {
1982       emitcode ("rlc", "a");
1983       emitcode ("subb", "a,acc");
1984       while (size--)
1985         aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
1986     }
1987
1988 release:
1989   /* release the aops */
1990   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1991   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1992 }
1993
1994 /*-----------------------------------------------------------------*/
1995 /* saveRegisters - will look for a call and save the registers     */
1996 /*-----------------------------------------------------------------*/
1997 static void
1998 saveRegisters (iCode * lic)
1999 {
2000   int i;
2001   iCode *ic;
2002   bitVect *rsave;
2003
2004   /* look for call */
2005   for (ic = lic; ic; ic = ic->next)
2006     if (ic->op == CALL || ic->op == PCALL)
2007       break;
2008
2009   if (!ic)
2010     {
2011       fprintf (stderr, "found parameter push with no function call\n");
2012       return;
2013     }
2014
2015   /* if the registers have been saved already or don't need to be then
2016      do nothing */
2017   if (ic->regsSaved)
2018     return;
2019   if (IS_SYMOP(IC_LEFT(ic)) &&
2020       (IFFUNC_CALLEESAVES(OP_SYMBOL(IC_LEFT(ic))->type) ||
2021        IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT (ic)))))
2022     return;
2023
2024   /* save the registers in use at this time but skip the
2025      ones for the result */
2026   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2027                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2028
2029   ic->regsSaved = 1;
2030   if (options.useXstack)
2031     {
2032       int count = bitVectnBitsOn (rsave);
2033
2034       if (count == 1)
2035         {
2036           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2037           if (reg->type == REG_BIT)
2038             {
2039               emitcode ("mov", "a,%s", reg->base);
2040             }
2041           else
2042             {
2043               emitcode ("mov", "a,%s", reg->name);
2044             }
2045           emitcode ("mov", "r0,%s", spname);
2046           emitcode ("inc", "%s", spname);// allocate before use
2047           emitcode ("movx", "@r0,a");
2048           if (bitVectBitValue (rsave, R0_IDX))
2049             emitcode ("mov", "r0,a");
2050         }
2051       else if (count != 0)
2052         {
2053           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2054           int nBits = bitVectnBitsOn (rsavebits);
2055
2056           if (nBits != 0)
2057             {
2058               count = count - nBits + 1;
2059               /* remove all but the first bits as they are pushed all at once */
2060               rsave = bitVectCplAnd (rsave, rsavebits);
2061               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2062             }
2063
2064           if (bitVectBitValue (rsave, R0_IDX))
2065             {
2066               emitcode ("push", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2067             }
2068           emitcode ("mov", "r0,%s", spname);
2069           MOVA ("r0");
2070           emitcode ("add", "a,#%d", count);
2071           emitcode ("mov", "%s,a", spname);
2072           for (i = 0; i < mcs51_nRegs; i++)
2073             {
2074               if (bitVectBitValue (rsave, i))
2075                 {
2076                   regs * reg = mcs51_regWithIdx (i);
2077                   if (i == R0_IDX)
2078                     {
2079                       emitcode ("pop", "acc");
2080                       emitcode ("push", "acc");
2081                     }
2082                   else if (reg->type == REG_BIT)
2083                     {
2084                       emitcode ("mov", "a,%s", reg->base);
2085                     }
2086                   else
2087                     {
2088                       emitcode ("mov", "a,%s", reg->name);
2089                     }
2090                   emitcode ("movx", "@r0,a");
2091                   if (--count)
2092                     {
2093                       emitcode ("inc", "r0");
2094                     }
2095                 }
2096             }
2097           if (bitVectBitValue (rsave, R0_IDX))
2098             {
2099               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
2100             }
2101         }
2102     }
2103   else
2104     {
2105       bool bits_pushed = FALSE;
2106       for (i = 0; i < mcs51_nRegs; i++)
2107         {
2108           if (bitVectBitValue (rsave, i))
2109             {
2110               bits_pushed = pushReg (i, bits_pushed);
2111             }
2112         }
2113     }
2114 }
2115
2116 /*-----------------------------------------------------------------*/
2117 /* unsaveRegisters - pop the pushed registers                      */
2118 /*-----------------------------------------------------------------*/
2119 static void
2120 unsaveRegisters (iCode * ic)
2121 {
2122   int i;
2123   bitVect *rsave;
2124
2125   /* restore the registers in use at this time but skip the
2126      ones for the result */
2127   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2128                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2129
2130   if (options.useXstack)
2131     {
2132       int count = bitVectnBitsOn (rsave);
2133
2134       if (count == 1)
2135         {
2136           regs * reg = mcs51_regWithIdx (bitVectFirstBit (rsave));
2137           emitcode ("mov", "r0,%s", spname);
2138           emitcode ("dec", "r0");
2139           emitcode ("movx", "a,@r0");
2140           if (reg->type == REG_BIT)
2141             {
2142               emitcode ("mov", "%s,a", reg->base);
2143             }
2144           else
2145             {
2146               emitcode ("mov", "%s,a", reg->name);
2147             }
2148           emitcode ("dec", "%s", spname);
2149         }
2150       else if (count != 0)
2151         {
2152           bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2153           int nBits = bitVectnBitsOn (rsavebits);
2154
2155           if (nBits != 0)
2156             {
2157               count = count - nBits + 1;
2158               /* remove all but the first bits as they are popped all at once */
2159               rsave = bitVectCplAnd (rsave, rsavebits);
2160               rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2161             }
2162
2163           emitcode ("mov", "r0,%s", spname);
2164           for (i = mcs51_nRegs; i >= 0; i--)
2165             {
2166               if (bitVectBitValue (rsave, i))
2167                 {
2168                   regs * reg = mcs51_regWithIdx (i);
2169                   emitcode ("dec", "r0");
2170                   emitcode ("movx", "a,@r0");
2171                   if (i == R0_IDX)
2172                     {
2173                       emitcode ("push", "acc");
2174                     }
2175                   else if (reg->type == REG_BIT)
2176                     {
2177                       emitcode ("mov", "%s,a", reg->base);
2178                     }
2179                   else
2180                     {
2181                       emitcode ("mov", "%s,a", reg->name);
2182                     }
2183                 }
2184             }
2185           emitcode ("mov", "%s,r0", spname);
2186           if (bitVectBitValue (rsave, R0_IDX))
2187             {
2188               emitcode ("pop", "ar0");
2189             }
2190         }
2191     }
2192   else
2193     {
2194       bool bits_popped = FALSE;
2195       for (i = mcs51_nRegs; i >= 0; i--)
2196         {
2197           if (bitVectBitValue (rsave, i))
2198             {
2199               bits_popped = popReg (i, bits_popped);
2200             }
2201         }
2202     }
2203 }
2204
2205
2206 /*-----------------------------------------------------------------*/
2207 /* pushSide -                                                      */
2208 /*-----------------------------------------------------------------*/
2209 static void
2210 pushSide (operand * oper, int size)
2211 {
2212   int offset = 0;
2213   while (size--)
2214     {
2215       char *l = aopGet (oper, offset++, FALSE, TRUE);
2216       if (AOP_TYPE (oper) != AOP_REG &&
2217           AOP_TYPE (oper) != AOP_DIR &&
2218           strcmp (l, "a"))
2219         {
2220           MOVA (l);
2221           emitcode ("push", "acc");
2222         }
2223       else
2224         {
2225           emitcode ("push", "%s", l);
2226         }
2227     }
2228 }
2229
2230 /*-----------------------------------------------------------------*/
2231 /* assignResultValue - also indicates if acc is in use afterwards  */
2232 /*-----------------------------------------------------------------*/
2233 static bool
2234 assignResultValue (operand * oper, operand * func)
2235 {
2236   int offset = 0;
2237   int size = AOP_SIZE (oper);
2238   bool accuse = FALSE;
2239   bool pushedA = FALSE;
2240
2241   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2242     {
2243       outBitC (oper);
2244       return FALSE;
2245     }
2246
2247   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2248     {
2249       emitcode ("push", "acc");
2250       pushedA = TRUE;
2251     }
2252   while (size--)
2253     {
2254       if ((offset == 3) && pushedA)
2255         emitcode ("pop", "acc");
2256       accuse |= aopPut (oper, fReturn[offset], offset, isOperandVolatile (oper, FALSE));
2257       offset++;
2258     }
2259   return accuse;
2260 }
2261
2262
2263 /*-----------------------------------------------------------------*/
2264 /* genXpush - pushes onto the external stack                       */
2265 /*-----------------------------------------------------------------*/
2266 static void
2267 genXpush (iCode * ic)
2268 {
2269   asmop *aop = newAsmop (0);
2270   regs *r;
2271   int size, offset = 0;
2272
2273   D(emitcode (";     genXpush",""));
2274
2275   aopOp (IC_LEFT (ic), ic, FALSE);
2276   r = getFreePtr (ic, &aop, FALSE);
2277
2278   size = AOP_SIZE (IC_LEFT (ic));
2279
2280   if (size == 1)
2281     {
2282       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2283       emitcode ("mov", "%s,%s", r->name, spname);
2284       emitcode ("inc", "%s", spname); // allocate space first
2285       emitcode ("movx", "@%s,a", r->name);
2286     }
2287   else
2288     {
2289       // allocate space first
2290       emitcode ("mov", "%s,%s", r->name, spname);
2291       MOVA (r->name);
2292       emitcode ("add", "a,#%d", size);
2293       emitcode ("mov", "%s,a", spname);
2294
2295       while (size--)
2296         {
2297           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2298           emitcode ("movx", "@%s,a", r->name);
2299           emitcode ("inc", "%s", r->name);
2300         }
2301     }
2302
2303   freeAsmop (NULL, aop, ic, TRUE);
2304   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2305 }
2306
2307 /*-----------------------------------------------------------------*/
2308 /* genIpush - generate code for pushing this gets a little complex */
2309 /*-----------------------------------------------------------------*/
2310 static void
2311 genIpush (iCode * ic)
2312 {
2313   int size, offset = 0;
2314   char *l;
2315   char *prev = "";
2316
2317   D(emitcode (";     genIpush",""));
2318
2319   /* if this is not a parm push : ie. it is spill push
2320      and spill push is always done on the local stack */
2321   if (!ic->parmPush)
2322     {
2323
2324       /* and the item is spilt then do nothing */
2325       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2326         return;
2327
2328       aopOp (IC_LEFT (ic), ic, FALSE);
2329       size = AOP_SIZE (IC_LEFT (ic));
2330       /* push it on the stack */
2331       while (size--)
2332         {
2333           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2334           if (*l == '#')
2335             {
2336               MOVA (l);
2337               l = "acc";
2338             }
2339           emitcode ("push", "%s", l);
2340         }
2341       return;
2342     }
2343
2344   /* this is a parameter push: in this case we call
2345      the routine to find the call and save those
2346      registers that need to be saved */
2347   saveRegisters (ic);
2348
2349   /* if use external stack then call the external
2350      stack pushing routine */
2351   if (options.useXstack)
2352     {
2353       genXpush (ic);
2354       return;
2355     }
2356
2357   /* then do the push */
2358   aopOp (IC_LEFT (ic), ic, FALSE);
2359
2360   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2361   size = AOP_SIZE (IC_LEFT (ic));
2362
2363   while (size--)
2364     {
2365       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2366       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2367           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2368           strcmp (l, "a"))
2369         {
2370           if (strcmp (l, prev) || *l == '@')
2371             MOVA (l);
2372           emitcode ("push", "acc");
2373         }
2374       else
2375         {
2376           emitcode ("push", "%s", l);
2377         }
2378       prev = l;
2379     }
2380
2381   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* genIpop - recover the registers: can happen only for spilling   */
2386 /*-----------------------------------------------------------------*/
2387 static void
2388 genIpop (iCode * ic)
2389 {
2390   int size, offset;
2391
2392   D(emitcode (";     genIpop",""));
2393
2394   /* if the temp was not pushed then */
2395   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2396     return;
2397
2398   aopOp (IC_LEFT (ic), ic, FALSE);
2399   size = AOP_SIZE (IC_LEFT (ic));
2400   offset = (size - 1);
2401   while (size--)
2402     emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2403                                    FALSE, TRUE));
2404
2405   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2406 }
2407
2408 /*-----------------------------------------------------------------*/
2409 /* saveRBank - saves an entire register bank on the stack          */
2410 /*-----------------------------------------------------------------*/
2411 static void
2412 saveRBank (int bank, iCode * ic, bool pushPsw)
2413 {
2414   int i;
2415   int count = 8 + ((mcs51_nRegs > 8) ? 1 : 0) + (pushPsw ? 1 : 0);
2416   asmop *aop = NULL;
2417   regs *r = NULL;
2418
2419   if (options.useXstack)
2420     {
2421       if (!ic)
2422       {
2423           /* Assume r0 is available for use. */
2424           r = mcs51_regWithIdx (R0_IDX);;
2425       }
2426       else
2427       {
2428           aop = newAsmop (0);
2429           r = getFreePtr (ic, &aop, FALSE);
2430       }
2431       // allocate space first
2432       emitcode ("mov", "%s,%s", r->name, spname);
2433       MOVA (r->name);
2434       emitcode ("add", "a,#%d", count);
2435       emitcode ("mov", "%s,a", spname);
2436     }
2437
2438   for (i = 0; i < 8; i++)
2439     {
2440       if (options.useXstack)
2441         {
2442           emitcode ("mov", "a,(%s+%d)",
2443                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2444           emitcode ("movx", "@%s,a", r->name);
2445           if (--count)
2446             emitcode ("inc", "%s", r->name);
2447         }
2448       else
2449         emitcode ("push", "(%s+%d)",
2450                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2451     }
2452
2453   if (mcs51_nRegs > 8)
2454     {
2455       if (options.useXstack)
2456         {
2457           emitcode ("mov", "a,bits");
2458           emitcode ("movx", "@%s,a", r->name);
2459           if (--count)
2460             emitcode ("inc", "%s", r->name);
2461         }
2462       else
2463         {
2464           emitcode ("push", "bits");
2465         }
2466       BitBankUsed = 1;
2467     }
2468
2469   if (pushPsw)
2470     {
2471       if (options.useXstack)
2472         {
2473           emitcode ("mov", "a,psw");
2474           emitcode ("movx", "@%s,a", r->name);
2475
2476         }
2477       else
2478         {
2479           emitcode ("push", "psw");
2480         }
2481
2482       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2483     }
2484
2485   if (aop)
2486     {
2487       freeAsmop (NULL, aop, ic, TRUE);
2488     }
2489
2490   if (ic)
2491   {
2492     ic->bankSaved = 1;
2493   }
2494 }
2495
2496 /*-----------------------------------------------------------------*/
2497 /* unsaveRBank - restores the register bank from stack             */
2498 /*-----------------------------------------------------------------*/
2499 static void
2500 unsaveRBank (int bank, iCode * ic, bool popPsw)
2501 {
2502   int i;
2503   asmop *aop = NULL;
2504   regs *r = NULL;
2505
2506   if (options.useXstack)
2507     {
2508       if (!ic)
2509         {
2510           /* Assume r0 is available for use. */
2511           r = mcs51_regWithIdx (R0_IDX);;
2512         }
2513       else
2514         {
2515           aop = newAsmop (0);
2516           r = getFreePtr (ic, &aop, FALSE);
2517         }
2518       emitcode ("mov", "%s,%s", r->name, spname);
2519     }
2520
2521   if (popPsw)
2522     {
2523       if (options.useXstack)
2524         {
2525           emitcode ("dec", "%s", r->name);
2526           emitcode ("movx", "a,@%s", r->name);
2527           emitcode ("mov", "psw,a");
2528         }
2529       else
2530         {
2531           emitcode ("pop", "psw");
2532         }
2533     }
2534
2535   if (mcs51_nRegs > 8)
2536     {
2537       if (options.useXstack)
2538         {
2539           emitcode ("dec", "%s", r->name);
2540           emitcode ("movx", "a,@%s", r->name);
2541           emitcode ("mov", "bits,a");
2542         }
2543       else
2544         {
2545           emitcode ("pop", "bits");
2546         }
2547     }
2548
2549   for (i = 7; i >= 0; i--)
2550     {
2551       if (options.useXstack)
2552         {
2553           emitcode ("dec", "%s", r->name);
2554           emitcode ("movx", "a,@%s", r->name);
2555           emitcode ("mov", "(%s+%d),a",
2556                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2557         }
2558       else
2559         {
2560           emitcode ("pop", "(%s+%d)",
2561                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2562         }
2563     }
2564
2565   if (options.useXstack)
2566     {
2567       emitcode ("mov", "%s,%s", spname, r->name);
2568     }
2569
2570   if (aop)
2571     {
2572       freeAsmop (NULL, aop, ic, TRUE);
2573     }
2574 }
2575
2576 /*-----------------------------------------------------------------*/
2577 /* genSend - gen code for SEND                                     */
2578 /*-----------------------------------------------------------------*/
2579 static void genSend(set *sendSet)
2580 {
2581   iCode *sic;
2582   int bit_count = 0;
2583
2584   /* first we do all bit parameters */
2585   for (sic = setFirstItem (sendSet); sic;
2586        sic = setNextItem (sendSet))
2587     {
2588       aopOp (IC_LEFT (sic), sic, FALSE);
2589
2590       if (sic->argreg > 12)
2591         {
2592           int bit = sic->argreg-13;
2593
2594           /* if left is a literal then
2595              we know what the value is */
2596           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2597             {
2598               if (((int) operandLitValue (IC_LEFT (sic))))
2599                   emitcode ("setb", "b[%d]", bit);
2600               else
2601                   emitcode ("clr", "b[%d]", bit);
2602             }
2603           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2604             {
2605               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2606                 if (strcmp (l, "c"))
2607                     emitcode ("mov", "c,%s", l);
2608                 emitcode ("mov", "b[%d],c", bit);
2609             }
2610           else
2611             {
2612               /* we need to or */
2613               toBoolean (IC_LEFT (sic));
2614               /* set C, if a >= 1 */
2615               emitcode ("add", "a,#0xff");
2616               emitcode ("mov", "b[%d],c", bit);
2617             }
2618           bit_count++;
2619           BitBankUsed = 1;
2620         }
2621       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2622     }
2623
2624   if (bit_count)
2625     {
2626       saveRegisters (setFirstItem (sendSet));
2627       emitcode ("mov", "bits,b");
2628     }
2629
2630   /* then we do all other parameters */
2631   for (sic = setFirstItem (sendSet); sic;
2632        sic = setNextItem (sendSet))
2633     {
2634       int size, offset = 0;
2635       aopOp (IC_LEFT (sic), sic, FALSE);
2636       size = AOP_SIZE (IC_LEFT (sic));
2637
2638       if (sic->argreg == 1)
2639         {
2640           while (size--)
2641             {
2642               char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2643               if (strcmp (l, fReturn[offset]))
2644                   emitcode ("mov", "%s,%s", fReturn[offset], l);
2645               offset++;
2646             }
2647         }
2648       else if (sic->argreg <= 12)
2649         {
2650           while (size--)
2651             {
2652               emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2653                         aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2654               offset++;
2655             }
2656         }
2657       freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2658     }
2659 }
2660
2661 /*-----------------------------------------------------------------*/
2662 /* selectRegBank - emit code to select the register bank           */
2663 /*-----------------------------------------------------------------*/
2664 static void
2665 selectRegBank (short bank, bool keepFlags)
2666 {
2667   /* if f.e. result is in carry */
2668   if (keepFlags)
2669     {
2670       emitcode ("anl", "psw,#0xE7");
2671       if (bank)
2672         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2673     }
2674   else
2675     {
2676       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2677     }
2678 }
2679
2680 /*-----------------------------------------------------------------*/
2681 /* genCall - generates a call statement                            */
2682 /*-----------------------------------------------------------------*/
2683 static void
2684 genCall (iCode * ic)
2685 {
2686   sym_link *dtype;
2687   sym_link *etype;
2688 //  bool restoreBank = FALSE;
2689   bool swapBanks = FALSE;
2690   bool accuse = FALSE;
2691   bool accPushed = FALSE;
2692   bool resultInF0 = FALSE;
2693
2694   D(emitcode(";     genCall",""));
2695
2696   dtype = operandType (IC_LEFT (ic));
2697   etype = getSpec(dtype);
2698   /* if send set is not empty then assign */
2699   if (_G.sendSet)
2700     {
2701         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2702             genSend(reverseSet(_G.sendSet));
2703         } else {
2704             genSend(_G.sendSet);
2705         }
2706
2707       _G.sendSet = NULL;
2708     }
2709
2710   /* if we are calling a not _naked function that is not using
2711      the same register bank then we need to save the
2712      destination registers on the stack */
2713   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2714       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2715        !IFFUNC_ISISR (dtype))
2716     {
2717       swapBanks = TRUE;
2718     }
2719
2720   /* if caller saves & we have not saved then */
2721   if (!ic->regsSaved)
2722       saveRegisters (ic);
2723
2724   if (swapBanks)
2725     {
2726         emitcode ("mov", "psw,#0x%02x",
2727            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2728     }
2729
2730   /* make the call */
2731   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2732     {
2733       if (IFFUNC_CALLEESAVES(dtype))
2734         {
2735           werror (E_BANKED_WITH_CALLEESAVES);
2736         }
2737       else
2738         {
2739           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2740                      OP_SYMBOL (IC_LEFT (ic))->rname :
2741                      OP_SYMBOL (IC_LEFT (ic))->name);
2742
2743           emitcode ("mov", "r0,#%s", l);
2744           emitcode ("mov", "r1,#(%s >> 8)", l);
2745           emitcode ("mov", "r2,#(%s >> 16)", l);
2746           emitcode ("lcall", "__sdcc_banked_call");
2747         }
2748     }
2749   else
2750     {
2751       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2752                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2753                                 OP_SYMBOL (IC_LEFT (ic))->name));
2754     }
2755
2756   if (swapBanks)
2757     {
2758       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2759     }
2760
2761   /* if we need assign a result value */
2762   if ((IS_ITEMP (IC_RESULT (ic)) &&
2763        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2764        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2765         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2766         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2767       IS_TRUE_SYMOP (IC_RESULT (ic)))
2768     {
2769
2770       _G.accInUse++;
2771       aopOp (IC_RESULT (ic), ic, FALSE);
2772       _G.accInUse--;
2773
2774       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2775
2776       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2777     }
2778
2779   /* adjust the stack for parameters if required */
2780   if (ic->parmBytes)
2781     {
2782       int i;
2783       if (ic->parmBytes > 3)
2784         {
2785           if (accuse)
2786             {
2787               emitcode ("push", "acc");
2788               accPushed = TRUE;
2789             }
2790           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2791               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2792             {
2793               emitcode ("mov", "F0,c");
2794               resultInF0 = TRUE;
2795             }
2796
2797           emitcode ("mov", "a,%s", spname);
2798           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2799           emitcode ("mov", "%s,a", spname);
2800
2801           /* unsaveRegisters from xstack needs acc, but */
2802           /* unsaveRegisters from stack needs this popped */
2803           if (accPushed && !options.useXstack)
2804             {
2805               emitcode ("pop", "acc");
2806               accPushed = FALSE;
2807             }
2808         }
2809       else
2810         for (i = 0; i < ic->parmBytes; i++)
2811           emitcode ("dec", "%s", spname);
2812     }
2813
2814   /* if we had saved some registers then unsave them */
2815   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2816     {
2817       if (accuse && !accPushed && options.useXstack)
2818         {
2819           /* xstack needs acc, but doesn't touch normal stack */
2820           emitcode ("push", "acc");
2821           accPushed = TRUE;
2822         }
2823       unsaveRegisters (ic);
2824     }
2825
2826 //  /* if register bank was saved then pop them */
2827 //  if (restoreBank)
2828 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2829
2830   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
2831     {
2832       if (resultInF0)
2833           emitcode ("mov", "c,F0");
2834
2835       aopOp (IC_RESULT (ic), ic, FALSE);
2836       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2837       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2838     }
2839
2840   if (accPushed)
2841     emitcode ("pop", "acc");
2842 }
2843
2844 /*-----------------------------------------------------------------*/
2845 /* -10l - generates a call by pointer statement                */
2846 /*-----------------------------------------------------------------*/
2847 static void
2848 genPcall (iCode * ic)
2849 {
2850   sym_link *dtype;
2851   sym_link *etype;
2852   symbol *rlbl = newiTempLabel (NULL);
2853 //  bool restoreBank=FALSE;
2854   bool swapBanks = FALSE;
2855   bool resultInF0 = FALSE;
2856
2857   D(emitcode(";     genPCall",""));
2858
2859   dtype = operandType (IC_LEFT (ic))->next;
2860   etype = getSpec(dtype);
2861   /* if caller saves & we have not saved then */
2862   if (!ic->regsSaved)
2863     saveRegisters (ic);
2864
2865   /* if we are calling a not _naked function that is not using
2866      the same register bank then we need to save the
2867      destination registers on the stack */
2868   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2869       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2870       !IFFUNC_ISISR (dtype))
2871     {
2872 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2873 //    restoreBank=TRUE;
2874       swapBanks = TRUE;
2875       // need caution message to user here
2876     }
2877
2878   if (IS_LITERAL(etype))
2879     {
2880       /* if send set is not empty then assign */
2881       if (_G.sendSet)
2882         {
2883           genSend(reverseSet(_G.sendSet));
2884           _G.sendSet = NULL;
2885         }
2886
2887       if (swapBanks)
2888         {
2889           emitcode ("mov", "psw,#0x%02x",
2890            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2891         }
2892
2893       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2894         {
2895           if (IFFUNC_CALLEESAVES(dtype))
2896             {
2897               werror (E_BANKED_WITH_CALLEESAVES);
2898             }
2899           else
2900             {
2901               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
2902
2903               emitcode ("mov", "r0,#%s", l);
2904               emitcode ("mov", "r1,#(%s >> 8)", l);
2905               emitcode ("mov", "r2,#(%s >> 16)", l);
2906               emitcode ("lcall", "__sdcc_banked_call");
2907             }
2908         }
2909       else
2910         {
2911           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
2912         }
2913     }
2914   else
2915     {
2916       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2917         {
2918           if (IFFUNC_CALLEESAVES(dtype))
2919             {
2920               werror (E_BANKED_WITH_CALLEESAVES);
2921             }
2922           else
2923             {
2924               aopOp (IC_LEFT (ic), ic, FALSE);
2925
2926               if (!swapBanks)
2927                 {
2928                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2929                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2930                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2931                 }
2932               else
2933                 {
2934                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
2935                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
2936                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
2937                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
2938                 }
2939
2940               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2941
2942               /* if send set is not empty then assign */
2943               if (_G.sendSet)
2944                 {
2945                   genSend(reverseSet(_G.sendSet));
2946                   _G.sendSet = NULL;
2947                 }
2948
2949               if (swapBanks)
2950                 {
2951                   emitcode ("mov", "psw,#0x%02x",
2952                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2953                 }
2954
2955               /* make the call */
2956               emitcode ("lcall", "__sdcc_banked_call");
2957             }
2958         }
2959       else
2960         {
2961           /* push the return address on to the stack */
2962           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
2963           emitcode ("push", "acc");
2964           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
2965           emitcode ("push", "acc");
2966
2967           /* now push the calling address */
2968           aopOp (IC_LEFT (ic), ic, FALSE);
2969
2970           pushSide (IC_LEFT (ic), FPTRSIZE);
2971
2972           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2973
2974           /* if send set is not empty the assign */
2975           if (_G.sendSet)
2976             {
2977               genSend(reverseSet(_G.sendSet));
2978               _G.sendSet = NULL;
2979             }
2980
2981           if (swapBanks)
2982             {
2983               emitcode ("mov", "psw,#0x%02x",
2984                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2985             }
2986
2987           /* make the call */
2988           emitcode ("ret", "");
2989           emitcode ("", "%05d$:", (rlbl->key + 100));
2990         }
2991     }
2992   if (swapBanks)
2993     {
2994       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2995     }
2996
2997   /* if we need assign a result value */
2998   if ((IS_ITEMP (IC_RESULT (ic)) &&
2999        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3000        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3001         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3002       IS_TRUE_SYMOP (IC_RESULT (ic)))
3003     {
3004
3005       _G.accInUse++;
3006       aopOp (IC_RESULT (ic), ic, FALSE);
3007       _G.accInUse--;
3008
3009       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3010
3011       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3012     }
3013
3014   /* adjust the stack for parameters if required */
3015   if (ic->parmBytes)
3016     {
3017       int i;
3018       if (ic->parmBytes > 3)
3019         {
3020           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3021               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3022             {
3023               emitcode ("mov", "F0,c");
3024               resultInF0 = TRUE;
3025             }
3026
3027           emitcode ("mov", "a,%s", spname);
3028           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3029           emitcode ("mov", "%s,a", spname);
3030         }
3031       else
3032         for (i = 0; i < ic->parmBytes; i++)
3033           emitcode ("dec", "%s", spname);
3034
3035     }
3036
3037 //  /* if register bank was saved then unsave them */
3038 //  if (restoreBank)
3039 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3040
3041   /* if we had saved some registers then unsave them */
3042   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3043     unsaveRegisters (ic);
3044
3045   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3046     {
3047       if (resultInF0)
3048           emitcode ("mov", "c,F0");
3049
3050       aopOp (IC_RESULT (ic), ic, FALSE);
3051       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3052       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3053     }
3054 }
3055
3056 /*-----------------------------------------------------------------*/
3057 /* resultRemat - result  is rematerializable                       */
3058 /*-----------------------------------------------------------------*/
3059 static int
3060 resultRemat (iCode * ic)
3061 {
3062   if (SKIP_IC (ic) || ic->op == IFX)
3063     return 0;
3064
3065   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3066     {
3067       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3068       if (sym->remat && !POINTER_SET (ic))
3069         return 1;
3070     }
3071
3072   return 0;
3073 }
3074
3075 #if defined(__BORLANDC__) || defined(_MSC_VER)
3076 #define STRCASECMP stricmp
3077 #else
3078 #define STRCASECMP strcasecmp
3079 #endif
3080
3081 /*-----------------------------------------------------------------*/
3082 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3083 /*-----------------------------------------------------------------*/
3084 static int
3085 regsCmp(void *p1, void *p2)
3086 {
3087   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3088 }
3089
3090 static bool
3091 inExcludeList (char *s)
3092 {
3093   const char *p = setFirstItem(options.excludeRegsSet);
3094
3095   if (p == NULL || STRCASECMP(p, "none") == 0)
3096     return FALSE;
3097
3098
3099   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3100 }
3101
3102 /*-----------------------------------------------------------------*/
3103 /* genFunction - generated code for function entry                 */
3104 /*-----------------------------------------------------------------*/
3105 static void
3106 genFunction (iCode * ic)
3107 {
3108   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3109   sym_link *ftype;
3110   bool     switchedPSW = FALSE;
3111   int      calleesaves_saved_register = -1;
3112   int      stackAdjust = sym->stack;
3113   int      accIsFree = sym->recvSize < 4;
3114   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3115   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3116
3117   _G.nRegsSaved = 0;
3118   /* create the function header */
3119   emitcode (";", "-----------------------------------------");
3120   emitcode (";", " function %s", sym->name);
3121   emitcode (";", "-----------------------------------------");
3122
3123   emitcode ("", "%s:", sym->rname);
3124   ftype = operandType (IC_LEFT (ic));
3125   _G.currentFunc = sym;
3126
3127   if (IFFUNC_ISNAKED(ftype))
3128   {
3129       emitcode(";", "naked function: no prologue.");
3130       return;
3131   }
3132
3133   /* here we need to generate the equates for the
3134      register bank if required */
3135   if (FUNC_REGBANK (ftype) != rbank)
3136     {
3137       int i;
3138
3139       rbank = FUNC_REGBANK (ftype);
3140       for (i = 0; i < mcs51_nRegs; i++)
3141         {
3142           if (regs8051[i].type != REG_BIT)
3143             {
3144               if (strcmp (regs8051[i].base, "0") == 0)
3145                 emitcode ("", "%s = 0x%02x",
3146                           regs8051[i].dname,
3147                           8 * rbank + regs8051[i].offset);
3148               else
3149                 emitcode ("", "%s = %s + 0x%02x",
3150                           regs8051[i].dname,
3151                           regs8051[i].base,
3152                           8 * rbank + regs8051[i].offset);
3153             }
3154         }
3155     }
3156
3157   /* if this is an interrupt service routine then
3158      save acc, b, dpl, dph  */
3159   if (IFFUNC_ISISR (sym->type))
3160     {
3161
3162       if (!inExcludeList ("acc"))
3163         emitcode ("push", "acc");
3164       if (!inExcludeList ("b"))
3165         emitcode ("push", "b");
3166       if (!inExcludeList ("dpl"))
3167         emitcode ("push", "dpl");
3168       if (!inExcludeList ("dph"))
3169         emitcode ("push", "dph");
3170       /* if this isr has no bank i.e. is going to
3171          run with bank 0 , then we need to save more
3172          registers :-) */
3173       if (!FUNC_REGBANK (sym->type))
3174         {
3175
3176           /* if this function does not call any other
3177              function then we can be economical and
3178              save only those registers that are used */
3179           if (!IFFUNC_HASFCALL(sym->type))
3180             {
3181               int i;
3182
3183               /* if any registers used */
3184               if (sym->regsUsed)
3185                 {
3186                   bool bits_pushed = FALSE;
3187                   /* save the registers used */
3188                   for (i = 0; i < sym->regsUsed->size; i++)
3189                     {
3190                       if (bitVectBitValue (sym->regsUsed, i))
3191                         bits_pushed = pushReg (i, bits_pushed);
3192                     }
3193                 }
3194             }
3195           else
3196             {
3197
3198               /* this function has a function call. We cannot
3199                  determines register usage so we will have to push the
3200                  entire bank */
3201                 saveRBank (0, ic, FALSE);
3202                 if (options.parms_in_bank1) {
3203                     int i;
3204                     for (i=0; i < 8 ; i++ ) {
3205                         emitcode ("push","%s",rb1regs[i]);
3206                     }
3207                 }
3208             }
3209         }
3210         else
3211         {
3212             /* This ISR uses a non-zero bank.
3213              *
3214              * We assume that the bank is available for our
3215              * exclusive use.
3216              *
3217              * However, if this ISR calls a function which uses some
3218              * other bank, we must save that bank entirely.
3219              */
3220             unsigned long banksToSave = 0;
3221
3222             if (IFFUNC_HASFCALL(sym->type))
3223             {
3224
3225 #define MAX_REGISTER_BANKS 4
3226
3227                 iCode *i;
3228                 int ix;
3229
3230                 for (i = ic; i; i = i->next)
3231                 {
3232                     if (i->op == ENDFUNCTION)
3233                     {
3234                         /* we got to the end OK. */
3235                         break;
3236                     }
3237
3238                     if (i->op == CALL)
3239                     {
3240                         sym_link *dtype;
3241
3242                         dtype = operandType (IC_LEFT(i));
3243                         if (dtype
3244                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3245                         {
3246                              /* Mark this bank for saving. */
3247                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3248                              {
3249                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3250                              }
3251                              else
3252                              {
3253                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3254                              }
3255
3256                              /* And note that we don't need to do it in
3257                               * genCall.
3258                               */
3259                              i->bankSaved = 1;
3260                         }
3261                     }
3262                     if (i->op == PCALL)
3263                     {
3264                         /* This is a mess; we have no idea what
3265                          * register bank the called function might
3266                          * use.
3267                          *
3268                          * The only thing I can think of to do is
3269                          * throw a warning and hope.
3270                          */
3271                         werror(W_FUNCPTR_IN_USING_ISR);
3272                     }
3273                 }
3274
3275                 if (banksToSave && options.useXstack)
3276                 {
3277                     /* Since we aren't passing it an ic,
3278                      * saveRBank will assume r0 is available to abuse.
3279                      *
3280                      * So switch to our (trashable) bank now, so
3281                      * the caller's R0 isn't trashed.
3282                      */
3283                     emitcode ("push", "psw");
3284                     emitcode ("mov", "psw,#0x%02x",
3285                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3286                     switchedPSW = TRUE;
3287                 }
3288
3289                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3290                 {
3291                      if (banksToSave & (1 << ix))
3292                      {
3293                          saveRBank(ix, NULL, FALSE);
3294                      }
3295                 }
3296             }
3297             // TODO: this needs a closer look
3298             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3299         }
3300
3301       /* Set the register bank to the desired value if nothing else */
3302       /* has done so yet. */
3303       if (!switchedPSW)
3304         {
3305           emitcode ("push", "psw");
3306           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3307         }
3308     }
3309   else
3310     {
3311       /* This is a non-ISR function. The caller has already switched register */
3312       /* banks, if necessary, so just handle the callee-saves option. */
3313
3314       /* if callee-save to be used for this function
3315          then save the registers being used in this function */
3316       if (IFFUNC_CALLEESAVES(sym->type))
3317         {
3318           int i;
3319
3320           /* if any registers used */
3321           if (sym->regsUsed)
3322             {
3323               bool bits_pushed = FALSE;
3324               /* save the registers used */
3325               for (i = 0; i < sym->regsUsed->size; i++)
3326                 {
3327                   if (bitVectBitValue (sym->regsUsed, i))
3328                     {
3329                       /* remember one saved register for later usage */
3330                       if (calleesaves_saved_register < 0)
3331                         calleesaves_saved_register = i;
3332                       bits_pushed = pushReg (i, bits_pushed);
3333                       _G.nRegsSaved++;
3334                     }
3335                 }
3336             }
3337         }
3338     }
3339
3340
3341   if (fReentrant)
3342     {
3343       if (options.useXstack)
3344         {
3345           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3346             {
3347               emitcode ("mov", "r0,%s", spname);
3348               emitcode ("inc", "%s", spname);
3349               emitcode ("xch", "a,_bpx");
3350               emitcode ("movx", "@r0,a");
3351               emitcode ("inc", "r0");
3352               emitcode ("mov", "a,r0");
3353               emitcode ("xch", "a,_bpx");
3354             }
3355           if (sym->stack)
3356             {
3357               emitcode ("push", "_bp");     /* save the callers stack  */
3358               emitcode ("mov", "_bp,sp");
3359             }
3360         }
3361       else
3362         {
3363           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3364             {
3365               /* set up the stack */
3366               emitcode ("push", "_bp");     /* save the callers stack  */
3367               emitcode ("mov", "_bp,sp");
3368             }
3369         }
3370     }
3371
3372   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3373   /* before setting up the stack frame completely. */
3374   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3375     {
3376       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3377
3378       if (rsym->isitmp)
3379         {
3380           if (rsym && rsym->regType == REG_CND)
3381             rsym = NULL;
3382           if (rsym && (rsym->accuse || rsym->ruonly))
3383             rsym = NULL;
3384           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3385             rsym = rsym->usl.spillLoc;
3386         }
3387
3388       /* If the RECEIVE operand immediately spills to the first entry on the */
3389       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3390       /* rather than the usual @r0/r1 machinations. */
3391       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3392         {
3393           int ofs;
3394
3395           _G.current_iCode = ric;
3396           D(emitcode (";     genReceive",""));
3397           for (ofs=0; ofs < sym->recvSize; ofs++)
3398             {
3399               if (!strcmp (fReturn[ofs], "a"))
3400                 emitcode ("push", "acc");
3401               else
3402                 emitcode ("push", fReturn[ofs]);
3403             }
3404           stackAdjust -= sym->recvSize;
3405           if (stackAdjust<0)
3406             {
3407               assert (stackAdjust>=0);
3408               stackAdjust = 0;
3409             }
3410           _G.current_iCode = ic;
3411           ric->generated = 1;
3412           accIsFree = 1;
3413         }
3414       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3415       /* to free up the accumulator. */
3416       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3417         {
3418           int ofs;
3419
3420           _G.current_iCode = ric;
3421           D(emitcode (";     genReceive",""));
3422           for (ofs=0; ofs < sym->recvSize; ofs++)
3423             {
3424               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3425             }
3426           _G.current_iCode = ic;
3427           ric->generated = 1;
3428           accIsFree = 1;
3429         }
3430     }
3431
3432   /* adjust the stack for the function */
3433   if (stackAdjust)
3434     {
3435       int i = stackAdjust;
3436       if (i > 256)
3437         werror (W_STACK_OVERFLOW, sym->name);
3438
3439       if (i > 3 && accIsFree)
3440         {
3441           emitcode ("mov", "a,sp");
3442           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3443           emitcode ("mov", "sp,a");
3444         }
3445       else if (i > 5)
3446         {
3447           /* The accumulator is not free, so we will need another register */
3448           /* to clobber. No need to worry about a possible conflict with */
3449           /* the above early RECEIVE optimizations since they would have */
3450           /* freed the accumulator if they were generated. */
3451
3452           if (IFFUNC_CALLEESAVES(sym->type))
3453             {
3454               /* if it's a callee-saves function we need a saved register */
3455               if (calleesaves_saved_register >= 0)
3456                 {
3457                   emitcode ("mov", "%s,a", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3458                   emitcode ("mov", "a,sp");
3459                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3460                   emitcode ("mov", "sp,a");
3461                   emitcode ("mov", "a,%s", mcs51_regWithIdx (calleesaves_saved_register)->dname);
3462                 }
3463               else
3464                 /* do it the hard way */
3465                 while (i--)
3466                   emitcode ("inc", "sp");
3467             }
3468           else
3469             {
3470               /* not callee-saves, we can clobber r0 */
3471               emitcode ("mov", "r0,a");
3472               emitcode ("mov", "a,sp");
3473               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3474               emitcode ("mov", "sp,a");
3475               emitcode ("mov", "a,r0");
3476             }
3477         }
3478       else
3479         while (i--)
3480           emitcode ("inc", "sp");
3481     }
3482
3483   if (sym->xstack)
3484     {
3485       char i = ((char) sym->xstack & 0xff);
3486
3487       if (i > 3 && accIsFree)
3488         {
3489           emitcode ("mov", "a,_spx");
3490           emitcode ("add", "a,#0x%02x", i);
3491           emitcode ("mov", "_spx,a");
3492         }
3493       else if (i > 5)
3494         {
3495           emitcode ("push", "acc");
3496           emitcode ("mov", "a,_spx");
3497           emitcode ("add", "a,#0x%02x", i);
3498           emitcode ("mov", "_spx,a");
3499           emitcode ("pop", "acc");
3500         }
3501       else
3502         {
3503           while (i--)
3504             emitcode ("inc", "_spx");
3505         }
3506     }
3507
3508   /* if critical function then turn interrupts off */
3509   if (IFFUNC_ISCRITICAL (ftype))
3510     {
3511       symbol *tlbl = newiTempLabel (NULL);
3512       emitcode ("setb", "c");
3513       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3514       emitcode ("clr", "c");
3515       emitcode ("", "%05d$:", (tlbl->key + 100));
3516       emitcode ("push", "psw"); /* save old ea via c in psw */
3517     }
3518 }
3519
3520 /*-----------------------------------------------------------------*/
3521 /* genEndFunction - generates epilogue for functions               */
3522 /*-----------------------------------------------------------------*/
3523 static void
3524 genEndFunction (iCode * ic)
3525 {
3526   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3527   lineNode *lnp = lineCurr;
3528   bitVect  *regsUsed;
3529   bitVect  *regsUsedPrologue;
3530   bitVect  *regsUnneeded;
3531   int      idx;
3532
3533   _G.currentFunc = NULL;
3534   if (IFFUNC_ISNAKED(sym->type))
3535   {
3536       emitcode(";", "naked function: no epilogue.");
3537       if (options.debug && currFunc)
3538         debugFile->writeEndFunction (currFunc, ic, 0);
3539       return;
3540   }
3541
3542   if (IFFUNC_ISCRITICAL (sym->type))
3543     {
3544       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3545         {
3546           emitcode ("rlc", "a");   /* save c in a */
3547           emitcode ("pop", "psw"); /* restore ea via c in psw */
3548           emitcode ("mov", "ea,c");
3549           emitcode ("rrc", "a");   /* restore c from a */
3550         }
3551       else
3552         {
3553           emitcode ("pop", "psw"); /* restore ea via c in psw */
3554           emitcode ("mov", "ea,c");
3555         }
3556     }
3557
3558   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3559     {
3560       if (options.useXstack)
3561         {
3562           if (sym->stack)
3563             {
3564               emitcode ("mov", "sp,_bp");
3565               emitcode ("pop", "_bp");
3566             }
3567           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3568             {
3569               emitcode ("xch", "a,_bpx");
3570               emitcode ("mov", "r0,a");
3571               emitcode ("dec", "r0");
3572               emitcode ("movx", "a,@r0");
3573               emitcode ("xch", "a,_bpx");
3574               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3575             }
3576         }
3577       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3578         {
3579           emitcode ("mov", "sp,_bp");
3580           emitcode ("pop", "_bp");
3581         }
3582     }
3583
3584   /* restore the register bank  */
3585   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3586   {
3587     if (/* !FUNC_REGBANK (sym->type) || */ !IFFUNC_ISISR (sym->type)
3588      || !options.useXstack)
3589     {
3590         /* Special case of ISR using non-zero bank with useXstack
3591          * is handled below.
3592          */
3593         emitcode ("pop", "psw");
3594     }
3595   }
3596
3597   if (IFFUNC_ISISR (sym->type))
3598     {
3599
3600       /* now we need to restore the registers */
3601       /* if this isr has no bank i.e. is going to
3602          run with bank 0 , then we need to save more
3603          registers :-) */
3604       if (!FUNC_REGBANK (sym->type))
3605         {
3606           /* if this function does not call any other
3607              function then we can be economical and
3608              save only those registers that are used */
3609           if (!IFFUNC_HASFCALL(sym->type))
3610             {
3611               int i;
3612
3613               /* if any registers used */
3614               if (sym->regsUsed)
3615                 {
3616                   bool bits_popped = FALSE;
3617                   /* save the registers used */
3618                   for (i = sym->regsUsed->size; i >= 0; i--)
3619                     {
3620                       if (bitVectBitValue (sym->regsUsed, i))
3621                         bits_popped = popReg (i, bits_popped);
3622                     }
3623                 }
3624             }
3625           else
3626             {
3627               if (options.parms_in_bank1) {
3628                   int i;
3629                   for (i = 7 ; i >= 0 ; i-- ) {
3630                       emitcode ("pop","%s",rb1regs[i]);
3631                   }
3632               }
3633               /* this function has  a function call cannot
3634                  determines register usage so we will have to pop the
3635                  entire bank */
3636               unsaveRBank (0, ic, FALSE);
3637             }
3638         }
3639         else
3640         {
3641             /* This ISR uses a non-zero bank.
3642              *
3643              * Restore any register banks saved by genFunction
3644              * in reverse order.
3645              */
3646             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3647             int ix;
3648
3649             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3650             {
3651                 if (savedBanks & (1 << ix))
3652                 {
3653                     unsaveRBank(ix, NULL, FALSE);
3654                 }
3655             }
3656
3657             if (options.useXstack)
3658             {
3659                 /* Restore bank AFTER calling unsaveRBank,
3660                  * since it can trash r0.
3661                  */
3662                 emitcode ("pop", "psw");
3663             }
3664         }
3665
3666       if (!inExcludeList ("dph"))
3667         emitcode ("pop", "dph");
3668       if (!inExcludeList ("dpl"))
3669         emitcode ("pop", "dpl");
3670       if (!inExcludeList ("b"))
3671         emitcode ("pop", "b");
3672       if (!inExcludeList ("acc"))
3673         emitcode ("pop", "acc");
3674
3675       /* if debug then send end of function */
3676       if (options.debug && currFunc)
3677         {
3678           debugFile->writeEndFunction (currFunc, ic, 1);
3679         }
3680
3681       emitcode ("reti", "");
3682     }
3683   else
3684     {
3685       if (IFFUNC_CALLEESAVES(sym->type))
3686         {
3687           int i;
3688
3689           /* if any registers used */
3690           if (sym->regsUsed)
3691             {
3692               /* save the registers used */
3693               for (i = sym->regsUsed->size; i >= 0; i--)
3694                 {
3695                   if (bitVectBitValue (sym->regsUsed, i) ||
3696                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3697                     emitcode ("pop", "%s", mcs51_regWithIdx (i)->dname);
3698                 }
3699             }
3700           else if (mcs51_ptrRegReq)
3701             {
3702               emitcode ("pop", "%s", mcs51_regWithIdx (R1_IDX)->dname);
3703               emitcode ("pop", "%s", mcs51_regWithIdx (R0_IDX)->dname);
3704             }
3705
3706         }
3707
3708       /* if debug then send end of function */
3709       if (options.debug && currFunc)
3710         {
3711           debugFile->writeEndFunction (currFunc, ic, 1);
3712         }
3713
3714       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3715         {
3716           emitcode ("ljmp", "__sdcc_banked_ret");
3717         }
3718       else
3719         {
3720           emitcode ("ret", "");
3721         }
3722     }
3723
3724   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3725     return;
3726
3727   /* If this was an interrupt handler using bank 0 that called another */
3728   /* function, then all registers must be saved; nothing to optimized. */
3729   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3730       && !FUNC_REGBANK(sym->type))
3731     return;
3732
3733   /* There are no push/pops to optimize if not callee-saves or ISR */
3734   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3735     return;
3736
3737   /* If there were stack parameters, we cannot optimize without also    */
3738   /* fixing all of the stack offsets; this is too dificult to consider. */
3739   if (FUNC_HASSTACKPARM(sym->type))
3740     return;
3741
3742   /* Compute the registers actually used */
3743   regsUsed = newBitVect (mcs51_nRegs);
3744   regsUsedPrologue = newBitVect (mcs51_nRegs);
3745   while (lnp)
3746     {
3747       if (lnp->ic && lnp->ic->op == FUNCTION)
3748         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3749       else
3750         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3751
3752       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3753           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3754         break;
3755       if (!lnp->prev)
3756         break;
3757       lnp = lnp->prev;
3758     }
3759
3760   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3761       && !bitVectBitValue (regsUsed, CND_IDX))
3762     {
3763       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3764       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3765           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3766         bitVectUnSetBit (regsUsed, CND_IDX);
3767     }
3768   else
3769     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3770
3771   /* If this was an interrupt handler that called another function */
3772   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3773   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3774     {
3775       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3776       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3777       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3778       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3779       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3780     }
3781
3782   /* Remove the unneeded push/pops */
3783   regsUnneeded = newBitVect (mcs51_nRegs);
3784   while (lnp)
3785     {
3786       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3787         {
3788           if (!strncmp(lnp->line, "push", 4))
3789             {
3790               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3791               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3792                 {
3793                   connectLine (lnp->prev, lnp->next);
3794                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3795                 }
3796             }
3797           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3798             {
3799               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3800               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3801                 {
3802                   connectLine (lnp->prev, lnp->next);
3803                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3804                 }
3805             }
3806         }
3807       lnp = lnp->next;
3808     }
3809
3810   for (idx = 0; idx < regsUnneeded->size; idx++)
3811     if (bitVectBitValue (regsUnneeded, idx))
3812       emitcode ("", ";\teliminated unneeded push/pop %s", mcs51_regWithIdx (idx)->dname);
3813
3814   freeBitVect (regsUnneeded);
3815   freeBitVect (regsUsed);
3816   freeBitVect (regsUsedPrologue);
3817 }
3818
3819 /*-----------------------------------------------------------------*/
3820 /* genRet - generate code for return statement                     */
3821 /*-----------------------------------------------------------------*/
3822 static void
3823 genRet (iCode * ic)
3824 {
3825   int size, offset = 0, pushed = 0;
3826
3827   D(emitcode (";     genRet",""));
3828
3829   /* if we have no return value then
3830      just generate the "ret" */
3831   if (!IC_LEFT (ic))
3832     goto jumpret;
3833
3834   /* we have something to return then
3835      move the return value into place */
3836   aopOp (IC_LEFT (ic), ic, FALSE);
3837   size = AOP_SIZE (IC_LEFT (ic));
3838
3839
3840   if (IS_BIT(_G.currentFunc->etype))
3841     {
3842       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
3843       size = 0;
3844     }
3845
3846   while (size--)
3847     {
3848       char *l;
3849       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3850         {
3851           /* #NOCHANGE */
3852           l = aopGet (IC_LEFT (ic), offset++,
3853                       FALSE, TRUE);
3854           emitcode ("push", "%s", l);
3855           pushed++;
3856         }
3857       else
3858         {
3859           l = aopGet (IC_LEFT (ic), offset,
3860                       FALSE, FALSE);
3861           if (strcmp (fReturn[offset], l))
3862             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3863         }
3864     }
3865
3866   while (pushed)
3867     {
3868       pushed--;
3869       if (strcmp (fReturn[pushed], "a"))
3870         emitcode ("pop", fReturn[pushed]);
3871       else
3872         emitcode ("pop", "acc");
3873     }
3874   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3875
3876 jumpret:
3877   /* generate a jump to the return label
3878      if the next is not the return statement */
3879   if (!(ic->next && ic->next->op == LABEL &&
3880         IC_LABEL (ic->next) == returnLabel))
3881
3882     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
3883
3884 }
3885
3886 /*-----------------------------------------------------------------*/
3887 /* genLabel - generates a label                                    */
3888 /*-----------------------------------------------------------------*/
3889 static void
3890 genLabel (iCode * ic)
3891 {
3892   /* special case never generate */
3893   if (IC_LABEL (ic) == entryLabel)
3894     return;
3895
3896   emitcode ("", "%05d$:", (IC_LABEL (ic)->key + 100));
3897 }
3898
3899 /*-----------------------------------------------------------------*/
3900 /* genGoto - generates a ljmp                                      */
3901 /*-----------------------------------------------------------------*/
3902 static void
3903 genGoto (iCode * ic)
3904 {
3905   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
3906 }
3907
3908 /*-----------------------------------------------------------------*/
3909 /* findLabelBackwards: walks back through the iCode chain looking  */
3910 /* for the given label. Returns number of iCode instructions     */
3911 /* between that label and given ic.          */
3912 /* Returns zero if label not found.          */
3913 /*-----------------------------------------------------------------*/
3914 static int
3915 findLabelBackwards (iCode * ic, int key)
3916 {
3917   int count = 0;
3918
3919   while (ic->prev)
3920     {
3921       ic = ic->prev;
3922       count++;
3923
3924       /* If we have any pushes or pops, we cannot predict the distance.
3925          I don't like this at all, this should be dealt with in the
3926          back-end */
3927       if (ic->op == IPUSH || ic->op == IPOP) {
3928         return 0;
3929       }
3930
3931       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3932         {
3933           return count;
3934         }
3935     }
3936
3937   return 0;
3938 }
3939
3940 /*-----------------------------------------------------------------*/
3941 /* genPlusIncr :- does addition with increment if possible         */
3942 /*-----------------------------------------------------------------*/
3943 static bool
3944 genPlusIncr (iCode * ic)
3945 {
3946   unsigned int icount;
3947   unsigned int size = getDataSize (IC_RESULT (ic));
3948
3949   /* will try to generate an increment */
3950   /* if the right side is not a literal
3951      we cannot */
3952   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3953     return FALSE;
3954
3955   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3956
3957   D(emitcode (";     genPlusIncr",""));
3958
3959   /* if increment >=16 bits in register or direct space */
3960   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) &&
3961       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3962       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
3963       (size > 1) &&
3964       (icount == 1))
3965     {
3966       symbol *tlbl;
3967       int emitTlbl;
3968       int labelRange;
3969
3970       /* If the next instruction is a goto and the goto target
3971        * is < 10 instructions previous to this, we can generate
3972        * jumps straight to that target.
3973        */
3974       if (ic->next && ic->next->op == GOTO
3975           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3976           && labelRange <= 10)
3977         {
3978           emitcode (";", "tail increment optimized");
3979           tlbl = IC_LABEL (ic->next);
3980           emitTlbl = 0;
3981         }
3982       else
3983         {
3984           tlbl = newiTempLabel (NULL);
3985           emitTlbl = 1;
3986         }
3987       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
3988       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3989           IS_AOP_PREG (IC_RESULT (ic)))
3990         emitcode ("cjne", "%s,#0x00,%05d$",
3991                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3992                   tlbl->key + 100);
3993       else
3994         {
3995           emitcode ("clr", "a");
3996           emitcode ("cjne", "a,%s,%05d$",
3997                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
3998                     tlbl->key + 100);
3999         }
4000
4001       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4002       if (size > 2)
4003         {
4004           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4005               IS_AOP_PREG (IC_RESULT (ic)))
4006             emitcode ("cjne", "%s,#0x00,%05d$",
4007                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4008                       tlbl->key + 100);
4009           else
4010             emitcode ("cjne", "a,%s,%05d$",
4011                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4012                       tlbl->key + 100);
4013
4014           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4015         }
4016       if (size > 3)
4017         {
4018           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4019               IS_AOP_PREG (IC_RESULT (ic)))
4020             emitcode ("cjne", "%s,#0x00,%05d$",
4021                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4022                       tlbl->key + 100);
4023           else
4024             {
4025               emitcode ("cjne", "a,%s,%05d$",
4026                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4027                         tlbl->key + 100);
4028             }
4029           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4030         }
4031
4032       if (emitTlbl)
4033         {
4034           emitcode ("", "%05d$:", tlbl->key + 100);
4035         }
4036       return TRUE;
4037     }
4038
4039   /* if result is dptr */
4040   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4041       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4042       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4043       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4044     {
4045       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4046         return FALSE;
4047
4048       if (icount > 9)
4049         return FALSE;
4050
4051       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4052         return FALSE;
4053
4054       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0, FALSE);
4055       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1, FALSE);
4056       while (icount--)
4057         emitcode ("inc", "dptr");
4058
4059       return TRUE;
4060     }
4061
4062   /* if the literal value of the right hand side
4063      is greater than 4 then it is not worth it */
4064   if (icount > 4)
4065     return FALSE;
4066
4067   /* if the sizes are greater than 1 then we cannot */
4068   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4069       AOP_SIZE (IC_LEFT (ic)) > 1)
4070     return FALSE;
4071
4072   /* we can if the aops of the left & result match or
4073      if they are in registers and the registers are the
4074      same */
4075   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4076     {
4077
4078       if (icount > 3)
4079         {
4080           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4081           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4082           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4083         }
4084       else
4085         {
4086
4087           while (icount--)
4088             emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4089         }
4090
4091       return TRUE;
4092     }
4093
4094   return FALSE;
4095 }
4096
4097 /*-----------------------------------------------------------------*/
4098 /* outBitAcc - output a bit in acc                                 */
4099 /*-----------------------------------------------------------------*/
4100 static void
4101 outBitAcc (operand * result)
4102 {
4103   symbol *tlbl = newiTempLabel (NULL);
4104   /* if the result is a bit */
4105   if (AOP_TYPE (result) == AOP_CRY)
4106     {
4107       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4108     }
4109   else
4110     {
4111       emitcode ("jz", "%05d$", tlbl->key + 100);
4112       emitcode ("mov", "a,%s", one);
4113       emitcode ("", "%05d$:", tlbl->key + 100);
4114       outAcc (result);
4115     }
4116 }
4117
4118 /*-----------------------------------------------------------------*/
4119 /* genPlusBits - generates code for addition of two bits           */
4120 /*-----------------------------------------------------------------*/
4121 static void
4122 genPlusBits (iCode * ic)
4123 {
4124   D(emitcode (";     genPlusBits",""));
4125
4126   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4127     {
4128       symbol *lbl = newiTempLabel (NULL);
4129       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4130       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4131       emitcode ("cpl", "c");
4132       emitcode ("", "%05d$:", (lbl->key + 100));
4133       outBitC (IC_RESULT (ic));
4134     }
4135   else
4136     {
4137       emitcode ("clr", "a");
4138       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4139       emitcode ("rlc", "a");
4140       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4141       emitcode ("addc", "a,#0x00");
4142       outAcc (IC_RESULT (ic));
4143     }
4144 }
4145
4146 #if 0
4147 /* This is the original version of this code.
4148
4149  * This is being kept around for reference,
4150  * because I am not entirely sure I got it right...
4151  */
4152 static void
4153 adjustArithmeticResult (iCode * ic)
4154 {
4155   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4156       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4157       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4158     aopPut (IC_RESULT (ic),
4159             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4160             2,
4161             isOperandVolatile (IC_RESULT (ic), FALSE));
4162
4163   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4164       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4165       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4166     aopPut (IC_RESULT (ic),
4167             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4168             2,
4169             isOperandVolatile (IC_RESULT (ic), FALSE));
4170
4171   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4172       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4173       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4174       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4175       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4176     {
4177       char buffer[5];
4178       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4179       aopPut (IC_RESULT (ic), buffer, 2, isOperandVolatile (IC_RESULT (ic), FALSE));
4180     }
4181 }
4182 #else
4183 /* This is the pure and virtuous version of this code.
4184  * I'm pretty certain it's right, but not enough to toss the old
4185  * code just yet...
4186  */
4187 static void
4188 adjustArithmeticResult (iCode * ic)
4189 {
4190   if (opIsGptr (IC_RESULT (ic)) &&
4191       opIsGptr (IC_LEFT (ic)) &&
4192       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4193     {
4194       aopPut (IC_RESULT (ic),
4195               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4196               GPTRSIZE - 1,
4197               isOperandVolatile (IC_RESULT (ic), FALSE));
4198     }
4199
4200   if (opIsGptr (IC_RESULT (ic)) &&
4201       opIsGptr (IC_RIGHT (ic)) &&
4202       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4203     {
4204       aopPut (IC_RESULT (ic),
4205               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4206               GPTRSIZE - 1,
4207               isOperandVolatile (IC_RESULT (ic), FALSE));
4208     }
4209
4210   if (opIsGptr (IC_RESULT (ic)) &&
4211       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4212       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4213       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4214       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4215     {
4216       char buffer[5];
4217       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4218       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4219     }
4220 }
4221 #endif
4222
4223 /*-----------------------------------------------------------------*/
4224 /* genPlus - generates code for addition                           */
4225 /*-----------------------------------------------------------------*/
4226 static void
4227 genPlus (iCode * ic)
4228 {
4229   int size, offset = 0;
4230   int skip_bytes = 0;
4231   char *add = "add";
4232   operand *leftOp, *rightOp;
4233   operand * op;
4234
4235   /* special cases :- */
4236
4237   D(emitcode (";     genPlus",""));
4238
4239   aopOp (IC_LEFT (ic), ic, FALSE);
4240   aopOp (IC_RIGHT (ic), ic, FALSE);
4241   aopOp (IC_RESULT (ic), ic, TRUE);
4242
4243   /* if literal, literal on the right or
4244      if left requires ACC or right is already
4245      in ACC */
4246   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4247       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4248       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4249     {
4250       operand *t = IC_RIGHT (ic);
4251       IC_RIGHT (ic) = IC_LEFT (ic);
4252       IC_LEFT (ic) = t;
4253     }
4254
4255   /* if both left & right are in bit
4256      space */
4257   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4258       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4259     {
4260       genPlusBits (ic);
4261       goto release;
4262     }
4263
4264   /* if left in bit space & right literal */
4265   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4266       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4267     {
4268       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4269       /* if result in bit space */
4270       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4271         {
4272           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4273             emitcode ("cpl", "c");
4274           outBitC (IC_RESULT (ic));
4275         }
4276       else
4277         {
4278           size = getDataSize (IC_RESULT (ic));
4279           while (size--)
4280             {
4281               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4282               emitcode ("addc", "a,#00");
4283               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4284             }
4285         }
4286       goto release;
4287     }
4288
4289   /* if I can do an increment instead
4290      of add then GOOD for ME */
4291   if (genPlusIncr (ic) == TRUE)
4292     goto release;
4293
4294   size = getDataSize (IC_RESULT (ic));
4295   leftOp = IC_LEFT(ic);
4296   rightOp = IC_RIGHT(ic);
4297   op=IC_LEFT(ic);
4298
4299   /* if this is an add for an array access
4300      at a 256 byte boundary */
4301   if ( 2 == size
4302        && AOP_TYPE (op) == AOP_IMMD
4303        && IS_SYMOP (op)
4304        && IS_SPEC (OP_SYM_ETYPE (op))
4305        && SPEC_ABSA (OP_SYM_ETYPE (op))
4306        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4307      )
4308     {
4309       D(emitcode (";     genPlus aligned array",""));
4310       aopPut (IC_RESULT (ic),
4311               aopGet (rightOp, 0, FALSE, FALSE),
4312               0,
4313               isOperandVolatile (IC_RESULT (ic), FALSE));
4314
4315       if( 1 == getDataSize (IC_RIGHT (ic)) )
4316         {
4317           aopPut (IC_RESULT (ic),
4318                   aopGet (leftOp, 1, FALSE, FALSE),
4319                   1,
4320                   isOperandVolatile (IC_RESULT (ic), FALSE));
4321         }
4322       else
4323         {
4324           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4325           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4326           aopPut (IC_RESULT (ic), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
4327         }
4328       goto release;
4329     }
4330
4331   /* if the lower bytes of a literal are zero skip the addition */
4332   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4333     {
4334        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4335               (skip_bytes+1 < size))
4336          {
4337            skip_bytes++;
4338          }
4339        if (skip_bytes)
4340          D(emitcode (";     genPlus shortcut",""));
4341     }
4342
4343   while (size--)
4344     {
4345       if( offset >= skip_bytes )
4346         {
4347           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4348             {
4349               bool pushedB;
4350               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4351               pushedB = pushB ();
4352               emitcode("xch", "a,b");
4353               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4354               emitcode (add, "a,b");
4355               popB (pushedB);
4356             }
4357           else if (aopGetUsesAcc (leftOp, offset))
4358             {
4359               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4360               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4361             }
4362           else
4363             {
4364               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4365               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4366             }
4367           aopPut (IC_RESULT (ic), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4368           add = "addc";  /* further adds must propagate carry */
4369         }
4370       else
4371         {
4372           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4373               isOperandVolatile (IC_RESULT (ic), FALSE))
4374             {
4375               /* just move */
4376               aopPut (IC_RESULT (ic),
4377                       aopGet (leftOp, offset, FALSE, FALSE),
4378                       offset,
4379                       isOperandVolatile (IC_RESULT (ic), FALSE));
4380             }
4381         }
4382       offset++;
4383     }
4384
4385   adjustArithmeticResult (ic);
4386
4387 release:
4388   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4389   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4390   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4391 }
4392
4393 /*-----------------------------------------------------------------*/
4394 /* genMinusDec :- does subtraction with decrement if possible      */
4395 /*-----------------------------------------------------------------*/
4396 static bool
4397 genMinusDec (iCode * ic)
4398 {
4399   unsigned int icount;
4400   unsigned int size = getDataSize (IC_RESULT (ic));
4401
4402   /* will try to generate an increment */
4403   /* if the right side is not a literal
4404      we cannot */
4405   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4406     return FALSE;
4407
4408   /* if the literal value of the right hand side
4409      is greater than 4 then it is not worth it */
4410   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4411     return FALSE;
4412
4413   D(emitcode (";     genMinusDec",""));
4414
4415   /* if decrement >=16 bits in register or direct space */
4416   if ((AOP_TYPE(IC_LEFT(ic)) == AOP_REG || AOP_TYPE(IC_LEFT(ic)) == AOP_DIR) &&
4417       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4418       (size > 1) &&
4419       (icount == 1))
4420     {
4421       symbol *tlbl;
4422       int emitTlbl;
4423       int labelRange;
4424
4425       /* If the next instruction is a goto and the goto target
4426        * is <= 10 instructions previous to this, we can generate
4427        * jumps straight to that target.
4428        */
4429       if (ic->next && ic->next->op == GOTO
4430           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4431           && labelRange <= 10)
4432         {
4433           emitcode (";", "tail decrement optimized");
4434           tlbl = IC_LABEL (ic->next);
4435           emitTlbl = 0;
4436         }
4437       else
4438         {
4439           tlbl = newiTempLabel (NULL);
4440           emitTlbl = 1;
4441         }
4442
4443       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4444       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4445           IS_AOP_PREG (IC_RESULT (ic)))
4446         emitcode ("cjne", "%s,#0xff,%05d$"
4447                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4448                   ,tlbl->key + 100);
4449       else
4450         {
4451           emitcode ("mov", "a,#0xff");
4452           emitcode ("cjne", "a,%s,%05d$"
4453                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4454                     ,tlbl->key + 100);
4455         }
4456       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4457       if (size > 2)
4458         {
4459           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4460               IS_AOP_PREG (IC_RESULT (ic)))
4461             emitcode ("cjne", "%s,#0xff,%05d$"
4462                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4463                       ,tlbl->key + 100);
4464           else
4465             {
4466               emitcode ("cjne", "a,%s,%05d$"
4467                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4468                         ,tlbl->key + 100);
4469             }
4470           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4471         }
4472       if (size > 3)
4473         {
4474           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4475               IS_AOP_PREG (IC_RESULT (ic)))
4476             emitcode ("cjne", "%s,#0xff,%05d$"
4477                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4478                       ,tlbl->key + 100);
4479           else
4480             {
4481               emitcode ("cjne", "a,%s,%05d$"
4482                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4483                         ,tlbl->key + 100);
4484             }
4485           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4486         }
4487       if (emitTlbl)
4488         {
4489           emitcode ("", "%05d$:", tlbl->key + 100);
4490         }
4491       return TRUE;
4492     }
4493
4494   /* if the sizes are greater than 1 then we cannot */
4495   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4496       AOP_SIZE (IC_LEFT (ic)) > 1)
4497     return FALSE;
4498
4499   /* we can if the aops of the left & result match or
4500      if they are in registers and the registers are the
4501      same */
4502   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4503     {
4504       char *l;
4505
4506       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4507         {
4508           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4509           l = "a";
4510         }
4511       else
4512         {
4513           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4514         }
4515
4516       while (icount--)
4517         emitcode ("dec", "%s", l);
4518
4519       if (AOP_NEEDSACC (IC_RESULT (ic)))
4520         aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4521
4522       return TRUE;
4523     }
4524
4525   return FALSE;
4526 }
4527
4528 /*-----------------------------------------------------------------*/
4529 /* addSign - complete with sign                                    */
4530 /*-----------------------------------------------------------------*/
4531 static void
4532 addSign (operand * result, int offset, int sign)
4533 {
4534   int size = (getDataSize (result) - offset);
4535   if (size > 0)
4536     {
4537       if (sign)
4538         {
4539           emitcode ("rlc", "a");
4540           emitcode ("subb", "a,acc");
4541           while (size--)
4542             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
4543         }
4544       else
4545         while (size--)
4546           aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4547     }
4548 }
4549
4550 /*-----------------------------------------------------------------*/
4551 /* genMinusBits - generates code for subtraction  of two bits      */
4552 /*-----------------------------------------------------------------*/
4553 static void
4554 genMinusBits (iCode * ic)
4555 {
4556   symbol *lbl = newiTempLabel (NULL);
4557
4558   D(emitcode (";     genMinusBits",""));
4559
4560   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4561     {
4562       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4563       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4564       emitcode ("cpl", "c");
4565       emitcode ("", "%05d$:", (lbl->key + 100));
4566       outBitC (IC_RESULT (ic));
4567     }
4568   else
4569     {
4570       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4571       emitcode ("subb", "a,acc");
4572       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4573       emitcode ("inc", "a");
4574       emitcode ("", "%05d$:", (lbl->key + 100));
4575       aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
4576       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4577     }
4578 }
4579
4580 /*-----------------------------------------------------------------*/
4581 /* genMinus - generates code for subtraction                       */
4582 /*-----------------------------------------------------------------*/
4583 static void
4584 genMinus (iCode * ic)
4585 {
4586   int size, offset = 0;
4587
4588   D(emitcode (";     genMinus",""));
4589
4590   aopOp (IC_LEFT (ic), ic, FALSE);
4591   aopOp (IC_RIGHT (ic), ic, FALSE);
4592   aopOp (IC_RESULT (ic), ic, TRUE);
4593
4594   /* special cases :- */
4595   /* if both left & right are in bit space */
4596   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4597       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4598     {
4599       genMinusBits (ic);
4600       goto release;
4601     }
4602
4603   /* if I can do an decrement instead
4604      of subtract then GOOD for ME */
4605   if (genMinusDec (ic) == TRUE)
4606     goto release;
4607
4608   size = getDataSize (IC_RESULT (ic));
4609
4610   /* if literal, add a,#-lit, else normal subb */
4611   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4612     {
4613       unsigned long lit = 0L;
4614       bool useCarry = FALSE;
4615
4616       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4617       lit = -(long) lit;
4618
4619       while (size--)
4620         {
4621           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4622             {
4623             MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4624               if (!offset && !size && lit== (unsigned long) -1)
4625                 {
4626                   emitcode ("dec", "a");
4627                 }
4628               else if (!useCarry)
4629                 {
4630                   /* first add without previous c */
4631                   emitcode ("add", "a,#0x%02x",
4632                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4633                   useCarry = TRUE;
4634                 }
4635               else
4636                 {
4637                   emitcode ("addc", "a,#0x%02x",
4638                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4639                 }
4640               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4641             }
4642           else
4643             {
4644               /* no need to add zeroes */
4645               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4646                 {
4647                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4648                           offset, isOperandVolatile (IC_RESULT (ic), FALSE));
4649                 }
4650               offset++;
4651             }
4652         }
4653     }
4654   else
4655     {
4656       operand *leftOp, *rightOp;
4657
4658       leftOp = IC_LEFT(ic);
4659       rightOp = IC_RIGHT(ic);
4660
4661       while (size--)
4662         {
4663           if (aopGetUsesAcc(rightOp, offset)) {
4664             if (aopGetUsesAcc(leftOp, offset)) {
4665               bool pushedB;
4666
4667               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4668               pushedB = pushB ();
4669               emitcode ("mov", "b,a");
4670               if (offset == 0)
4671                 CLRC;
4672               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4673               emitcode ("subb", "a,b");
4674               popB (pushedB);
4675             } else {
4676               /* reverse subtraction with 2's complement */
4677               if (offset == 0)
4678                 emitcode( "setb", "c");
4679                else
4680                 emitcode( "cpl", "c");
4681               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4682               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4683               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4684               emitcode("cpl", "a");
4685               if (size) /* skip if last byte */
4686                 emitcode( "cpl", "c");
4687             }
4688           } else {
4689             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4690             if (offset == 0)
4691               CLRC;
4692             emitcode ("subb", "a,%s",
4693                       aopGet(rightOp, offset, FALSE, TRUE));
4694           }
4695
4696           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4697         }
4698     }
4699
4700
4701   adjustArithmeticResult (ic);
4702
4703 release:
4704   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4705   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4706   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4707 }
4708
4709
4710 /*-----------------------------------------------------------------*/
4711 /* genMultbits :- multiplication of bits                           */
4712 /*-----------------------------------------------------------------*/
4713 static void
4714 genMultbits (operand * left,
4715              operand * right,
4716              operand * result)
4717 {
4718   D(emitcode (";     genMultbits",""));
4719
4720   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4721   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4722   outBitC (result);
4723 }
4724
4725 /*-----------------------------------------------------------------*/
4726 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4727 /*-----------------------------------------------------------------*/
4728 static void
4729 genMultOneByte (operand * left,
4730                 operand * right,
4731                 operand * result)
4732 {
4733   symbol *lbl;
4734   int size = AOP_SIZE (result);
4735   bool runtimeSign, compiletimeSign;
4736   bool lUnsigned, rUnsigned, pushedB;
4737
4738   D(emitcode (";     genMultOneByte",""));
4739
4740   if (size < 1 || size > 2)
4741     {
4742       /* this should never happen */
4743       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4744                AOP_SIZE(result), __FILE__, lineno);
4745       exit (1);
4746     }
4747
4748   /* (if two literals: the value is computed before) */
4749   /* if one literal, literal on the right */
4750   if (AOP_TYPE (left) == AOP_LIT)
4751     {
4752       operand *t = right;
4753       right = left;
4754       left = t;
4755       /* emitcode (";", "swapped left and right"); */
4756     }
4757   /* if no literal, unsigned on the right: shorter code */
4758   if (   AOP_TYPE (right) != AOP_LIT
4759       && SPEC_USIGN (getSpec (operandType (left))))
4760     {
4761       operand *t = right;
4762       right = left;
4763       left = t;
4764     }
4765
4766   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4767   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4768
4769   pushedB = pushB ();
4770
4771   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4772                    no need to take care about the signedness! */
4773       || (lUnsigned && rUnsigned))
4774     {
4775       /* just an unsigned 8 * 8 = 8 multiply
4776          or 8u * 8u = 16u */
4777       /* emitcode (";","unsigned"); */
4778       /* TODO: check for accumulator clash between left & right aops? */
4779
4780       if (AOP_TYPE (right) == AOP_LIT)
4781         {
4782           /* moving to accumulator first helps peepholes */
4783           MOVA (aopGet (left, 0, FALSE, FALSE));
4784           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4785         }
4786       else
4787         {
4788           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4789           MOVA (aopGet (left, 0, FALSE, FALSE));
4790         }
4791
4792       emitcode ("mul", "ab");
4793       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4794       if (size == 2)
4795         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4796
4797       popB (pushedB);
4798       return;
4799     }
4800
4801   /* we have to do a signed multiply */
4802   /* emitcode (";", "signed"); */
4803
4804   /* now sign adjust for both left & right */
4805
4806   /* let's see what's needed: */
4807   /* apply negative sign during runtime */
4808   runtimeSign = FALSE;
4809   /* negative sign from literals */
4810   compiletimeSign = FALSE;
4811
4812   if (!lUnsigned)
4813     {
4814       if (AOP_TYPE(left) == AOP_LIT)
4815         {
4816           /* signed literal */
4817           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4818           if (val < 0)
4819             compiletimeSign = TRUE;
4820         }
4821       else
4822         /* signed but not literal */
4823         runtimeSign = TRUE;
4824     }
4825
4826   if (!rUnsigned)
4827     {
4828       if (AOP_TYPE(right) == AOP_LIT)
4829         {
4830           /* signed literal */
4831           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4832           if (val < 0)
4833             compiletimeSign ^= TRUE;
4834         }
4835       else
4836         /* signed but not literal */
4837         runtimeSign = TRUE;
4838     }
4839
4840   /* initialize F0, which stores the runtime sign */
4841   if (runtimeSign)
4842     {
4843       if (compiletimeSign)
4844         emitcode ("setb", "F0"); /* set sign flag */
4845       else
4846         emitcode ("clr", "F0"); /* reset sign flag */
4847     }
4848
4849   /* save the signs of the operands */
4850   if (AOP_TYPE(right) == AOP_LIT)
4851     {
4852       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4853
4854       if (!rUnsigned && val < 0)
4855         emitcode ("mov", "b,#0x%02x", -val);
4856       else
4857         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4858     }
4859   else /* ! literal */
4860     {
4861       if (rUnsigned)  /* emitcode (";", "signed"); */
4862
4863         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4864       else
4865         {
4866           MOVA (aopGet (right, 0, FALSE, FALSE));
4867           lbl = newiTempLabel (NULL);
4868           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4869           emitcode ("cpl", "F0"); /* complement sign flag */
4870           emitcode ("cpl", "a");  /* 2's complement */
4871           emitcode ("inc", "a");
4872           emitcode ("", "%05d$:", (lbl->key + 100));
4873           emitcode ("mov", "b,a");
4874         }
4875     }
4876
4877   if (AOP_TYPE(left) == AOP_LIT)
4878     {
4879       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4880
4881       if (!lUnsigned && val < 0)
4882         emitcode ("mov", "a,#0x%02x", -val);
4883       else
4884         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4885     }
4886   else /* ! literal */
4887     {
4888       MOVA (aopGet (left, 0, FALSE, FALSE));
4889
4890       if (!lUnsigned)
4891         {
4892           lbl = newiTempLabel (NULL);
4893           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4894           emitcode ("cpl", "F0"); /* complement sign flag */
4895           emitcode ("cpl", "a"); /* 2's complement */
4896           emitcode ("inc", "a");
4897           emitcode ("", "%05d$:", (lbl->key + 100));
4898         }
4899     }
4900
4901   /* now the multiplication */
4902   emitcode ("mul", "ab");
4903   if (runtimeSign || compiletimeSign)
4904     {
4905       lbl = newiTempLabel (NULL);
4906       if (runtimeSign)
4907         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4908       emitcode ("cpl", "a"); /* lsb 2's complement */
4909       if (size != 2)
4910         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4911       else
4912         {
4913           emitcode ("add", "a,#1"); /* this sets carry flag */
4914           emitcode ("xch", "a,b");
4915           emitcode ("cpl", "a"); /* msb 2's complement */
4916           emitcode ("addc", "a,#0");
4917           emitcode ("xch", "a,b");
4918         }
4919       emitcode ("", "%05d$:", (lbl->key + 100));
4920     }
4921   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4922   if (size == 2)
4923     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4924
4925   popB (pushedB);
4926 }
4927
4928 /*-----------------------------------------------------------------*/
4929 /* genMult - generates code for multiplication                     */
4930 /*-----------------------------------------------------------------*/
4931 static void
4932 genMult (iCode * ic)
4933 {
4934   operand *left = IC_LEFT (ic);
4935   operand *right = IC_RIGHT (ic);
4936   operand *result = IC_RESULT (ic);
4937
4938   D(emitcode (";     genMult",""));
4939
4940   /* assign the asmops */
4941   aopOp (left, ic, FALSE);
4942   aopOp (right, ic, FALSE);
4943   aopOp (result, ic, TRUE);
4944
4945   /* special cases first */
4946   /* both are bits */
4947   if (AOP_TYPE (left) == AOP_CRY &&
4948       AOP_TYPE (right) == AOP_CRY)
4949     {
4950       genMultbits (left, right, result);
4951       goto release;
4952     }
4953
4954   /* if both are of size == 1 */
4955 #if 0 // one of them can be a sloc shared with the result
4956     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4957 #else
4958   if (getSize(operandType(left)) == 1 &&
4959       getSize(operandType(right)) == 1)
4960 #endif
4961     {
4962       genMultOneByte (left, right, result);
4963       goto release;
4964     }
4965
4966   /* should have been converted to function call */
4967     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4968              getSize(OP_SYMBOL(right)->type));
4969   assert (0);
4970
4971 release:
4972   freeAsmop (result, NULL, ic, TRUE);
4973   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4974   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4975 }
4976
4977 /*-----------------------------------------------------------------*/
4978 /* genDivbits :- division of bits                                  */
4979 /*-----------------------------------------------------------------*/
4980 static void
4981 genDivbits (operand * left,
4982             operand * right,
4983             operand * result)
4984 {
4985   char *l;
4986   bool pushedB;
4987
4988   D(emitcode (";     genDivbits",""));
4989
4990   pushedB = pushB ();
4991
4992   /* the result must be bit */
4993   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4994   l = aopGet (left, 0, FALSE, FALSE);
4995
4996   MOVA (l);
4997
4998   emitcode ("div", "ab");
4999   emitcode ("rrc", "a");
5000
5001   popB (pushedB);
5002
5003   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5004 }
5005
5006 /*-----------------------------------------------------------------*/
5007 /* genDivOneByte : 8 bit division                                  */
5008 /*-----------------------------------------------------------------*/
5009 static void
5010 genDivOneByte (operand * left,
5011                operand * right,
5012                operand * result)
5013 {
5014   bool lUnsigned, rUnsigned, pushedB;
5015   bool runtimeSign, compiletimeSign;
5016   bool accuse = FALSE;
5017   bool pushedA = FALSE;
5018   symbol *lbl;
5019   int size, offset;
5020
5021   D(emitcode (";     genDivOneByte",""));
5022
5023   /* Why is it necessary that genDivOneByte() can return an int result?
5024      Have a look at:
5025
5026         volatile unsigned char uc;
5027         volatile signed char sc1, sc2;
5028         volatile int i;
5029
5030         uc  = 255;
5031         sc1 = -1;
5032         i = uc / sc1;
5033
5034      Or:
5035
5036         sc1 = -128;
5037         sc2 = -1;
5038         i = sc1 / sc2;
5039
5040      In all cases a one byte result would overflow, the following cast to int
5041      would return the wrong result.
5042
5043      Two possible solution:
5044         a) cast operands to int, if ((unsigned) / (signed)) or
5045            ((signed) / (signed))
5046         b) return an 16 bit signed int; this is what we're doing here!
5047   */
5048
5049   size = AOP_SIZE (result) - 1;
5050   offset = 1;
5051   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5052   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5053
5054   pushedB = pushB ();
5055
5056   /* signed or unsigned */
5057   if (lUnsigned && rUnsigned)
5058     {
5059       /* unsigned is easy */
5060       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5061       MOVA (aopGet (left, 0, FALSE, FALSE));
5062       emitcode ("div", "ab");
5063       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5064       while (size--)
5065         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5066
5067       popB (pushedB);
5068       return;
5069     }
5070
5071   /* signed is a little bit more difficult */
5072
5073   /* now sign adjust for both left & right */
5074
5075   /* let's see what's needed: */
5076   /* apply negative sign during runtime */
5077   runtimeSign = FALSE;
5078   /* negative sign from literals */
5079   compiletimeSign = FALSE;
5080
5081   if (!lUnsigned)
5082     {
5083       if (AOP_TYPE(left) == AOP_LIT)
5084         {
5085           /* signed literal */
5086           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5087           if (val < 0)
5088             compiletimeSign = TRUE;
5089         }
5090       else
5091         /* signed but not literal */
5092         runtimeSign = TRUE;
5093     }
5094
5095   if (!rUnsigned)
5096     {
5097       if (AOP_TYPE(right) == AOP_LIT)
5098         {
5099           /* signed literal */
5100           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5101           if (val < 0)
5102             compiletimeSign ^= TRUE;
5103         }
5104       else
5105         /* signed but not literal */
5106         runtimeSign = TRUE;
5107     }
5108
5109   /* initialize F0, which stores the runtime sign */
5110   if (runtimeSign)
5111     {
5112       if (compiletimeSign)
5113         emitcode ("setb", "F0"); /* set sign flag */
5114       else
5115         emitcode ("clr", "F0"); /* reset sign flag */
5116     }
5117
5118   /* save the signs of the operands */
5119   if (AOP_TYPE(right) == AOP_LIT)
5120     {
5121       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5122
5123       if (!rUnsigned && val < 0)
5124         emitcode ("mov", "b,#0x%02x", -val);
5125       else
5126         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5127     }
5128   else /* ! literal */
5129     {
5130       if (rUnsigned)
5131         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5132       else
5133         {
5134           MOVA (aopGet (right, 0, FALSE, FALSE));
5135           lbl = newiTempLabel (NULL);
5136           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5137           emitcode ("cpl", "F0"); /* complement sign flag */
5138           emitcode ("cpl", "a");  /* 2's complement */
5139           emitcode ("inc", "a");
5140           emitcode ("", "%05d$:", (lbl->key + 100));
5141           emitcode ("mov", "b,a");
5142         }
5143     }
5144
5145   if (AOP_TYPE(left) == AOP_LIT)
5146     {
5147       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5148
5149       if (!lUnsigned && val < 0)
5150         emitcode ("mov", "a,#0x%02x", -val);
5151       else
5152         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5153     }
5154   else /* ! literal */
5155     {
5156       MOVA (aopGet (left, 0, FALSE, FALSE));
5157
5158       if (!lUnsigned)
5159         {
5160           lbl = newiTempLabel (NULL);
5161           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5162           emitcode ("cpl", "F0"); /* complement sign flag */
5163           emitcode ("cpl", "a");  /* 2's complement */
5164           emitcode ("inc", "a");
5165           emitcode ("", "%05d$:", (lbl->key + 100));
5166         }
5167     }
5168
5169   /* now the division */
5170   emitcode ("div", "ab");
5171
5172   if (runtimeSign || compiletimeSign)
5173     {
5174       lbl = newiTempLabel (NULL);
5175       if (runtimeSign)
5176         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5177       emitcode ("cpl", "a"); /* lsb 2's complement */
5178       emitcode ("inc", "a");
5179       emitcode ("", "%05d$:", (lbl->key + 100));
5180
5181       accuse = aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5182       if (size > 0)
5183         {
5184           /* msb is 0x00 or 0xff depending on the sign */
5185           if (runtimeSign)
5186             {
5187               if (accuse)
5188                 {
5189                   emitcode ("push", "acc");
5190                   pushedA = TRUE;
5191                 }
5192               emitcode ("mov", "c,F0");
5193               emitcode ("subb", "a,acc");
5194               while (size--)
5195                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5196             }
5197           else /* compiletimeSign */
5198             {
5199               if (aopPutUsesAcc (result, "#0xFF", offset))
5200                 {
5201                   emitcode ("push", "acc");
5202                   pushedA = TRUE;
5203                 }
5204               while (size--)
5205                 aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5206             }
5207         }
5208     }
5209   else
5210     {
5211       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5212       while (size--)
5213         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5214     }
5215
5216   if (pushedA)
5217     emitcode ("pop", "acc");
5218   popB (pushedB);
5219 }
5220
5221 /*-----------------------------------------------------------------*/
5222 /* genDiv - generates code for division                            */
5223 /*-----------------------------------------------------------------*/
5224 static void
5225 genDiv (iCode * ic)
5226 {
5227   operand *left = IC_LEFT (ic);
5228   operand *right = IC_RIGHT (ic);
5229   operand *result = IC_RESULT (ic);
5230
5231   D(emitcode (";     genDiv",""));
5232
5233   /* assign the amsops */
5234   aopOp (left, ic, FALSE);
5235   aopOp (right, ic, FALSE);
5236   aopOp (result, ic, TRUE);
5237
5238   /* special cases first */
5239   /* both are bits */
5240   if (AOP_TYPE (left) == AOP_CRY &&
5241       AOP_TYPE (right) == AOP_CRY)
5242     {
5243       genDivbits (left, right, result);
5244       goto release;
5245     }
5246
5247   /* if both are of size == 1 */
5248   if (AOP_SIZE (left) == 1 &&
5249       AOP_SIZE (right) == 1)
5250     {
5251       genDivOneByte (left, right, result);
5252       goto release;
5253     }
5254
5255   /* should have been converted to function call */
5256   assert (0);
5257 release:
5258   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5259   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5260   freeAsmop (result, NULL, ic, TRUE);
5261 }
5262
5263 /*-----------------------------------------------------------------*/
5264 /* genModbits :- modulus of bits                                   */
5265 /*-----------------------------------------------------------------*/
5266 static void
5267 genModbits (operand * left,
5268             operand * right,
5269             operand * result)
5270 {
5271   char *l;
5272   bool pushedB;
5273
5274   D(emitcode (";     genModbits",""));
5275
5276   pushedB = pushB ();
5277
5278   /* the result must be bit */
5279   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5280   l = aopGet (left, 0, FALSE, FALSE);
5281
5282   MOVA (l);
5283
5284   emitcode ("div", "ab");
5285   emitcode ("mov", "a,b");
5286   emitcode ("rrc", "a");
5287
5288   popB (pushedB);
5289
5290   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5291 }
5292
5293 /*-----------------------------------------------------------------*/
5294 /* genModOneByte : 8 bit modulus                                   */
5295 /*-----------------------------------------------------------------*/
5296 static void
5297 genModOneByte (operand * left,
5298                operand * right,
5299                operand * result)
5300 {
5301   bool lUnsigned, rUnsigned, pushedB;
5302   bool runtimeSign, compiletimeSign;
5303   symbol *lbl;
5304   int size, offset;
5305
5306   D(emitcode (";     genModOneByte",""));
5307
5308   size = AOP_SIZE (result) - 1;
5309   offset = 1;
5310   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5311   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5312
5313   /* if right is a literal, check it for 2^n */
5314   if (AOP_TYPE(right) == AOP_LIT)
5315     {
5316       unsigned char val = abs((int) operandLitValue(right));
5317       symbol *lbl2 = NULL;
5318
5319       switch (val)
5320         {
5321           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5322           case 2:
5323           case 4:
5324           case 8:
5325           case 16:
5326           case 32:
5327           case 64:
5328           case 128:
5329             if (lUnsigned)
5330               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5331                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5332               /* because iCode should have been changed to genAnd  */
5333               /* see file "SDCCopt.c", function "convertToFcall()" */
5334
5335             MOVA (aopGet (left, 0, FALSE, FALSE));
5336             emitcode ("mov", "c,acc.7");
5337             emitcode ("anl", "a,#0x%02x", val - 1);
5338             lbl = newiTempLabel (NULL);
5339             emitcode ("jz", "%05d$", (lbl->key + 100));
5340             emitcode ("jnc", "%05d$", (lbl->key + 100));
5341             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5342             if (size)
5343               {
5344                 int size2 = size;
5345                 int offs2 = offset;
5346
5347                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5348                 while (size2--)
5349                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
5350                 lbl2 = newiTempLabel (NULL);
5351                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5352               }
5353             emitcode ("", "%05d$:", (lbl->key + 100));
5354             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5355             while (size--)
5356               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5357             if (lbl2)
5358               {
5359                 emitcode ("", "%05d$:", (lbl2->key + 100));
5360               }
5361             return;
5362
5363           default:
5364             break;
5365         }
5366     }
5367
5368   pushedB = pushB ();
5369
5370   /* signed or unsigned */
5371   if (lUnsigned && rUnsigned)
5372     {
5373       /* unsigned is easy */
5374       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5375       MOVA (aopGet (left, 0, FALSE, FALSE));
5376       emitcode ("div", "ab");
5377       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5378       while (size--)
5379         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5380
5381       popB (pushedB);
5382       return;
5383     }
5384
5385   /* signed is a little bit more difficult */
5386
5387   /* now sign adjust for both left & right */
5388
5389   /* modulus: sign of the right operand has no influence on the result! */
5390   if (AOP_TYPE(right) == AOP_LIT)
5391     {
5392       signed char val = (char) operandLitValue(right);
5393
5394       if (!rUnsigned && val < 0)
5395         emitcode ("mov", "b,#0x%02x", -val);
5396       else
5397         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5398     }
5399   else /* not literal */
5400     {
5401       if (rUnsigned)
5402         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5403       else
5404         {
5405           MOVA (aopGet (right, 0, FALSE, FALSE));
5406           lbl = newiTempLabel (NULL);
5407           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5408           emitcode ("cpl", "a"); /* 2's complement */
5409           emitcode ("inc", "a");
5410           emitcode ("", "%05d$:", (lbl->key + 100));
5411           emitcode ("mov", "b,a");
5412         }
5413     }
5414
5415   /* let's see what's needed: */
5416   /* apply negative sign during runtime */
5417   runtimeSign = FALSE;
5418   /* negative sign from literals */
5419   compiletimeSign = FALSE;
5420
5421   /* sign adjust left side */
5422   if (AOP_TYPE(left) == AOP_LIT)
5423     {
5424       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5425
5426       if (!lUnsigned && val < 0)
5427         {
5428           compiletimeSign = TRUE; /* set sign flag */
5429           emitcode ("mov", "a,#0x%02x", -val);
5430         }
5431       else
5432         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5433     }
5434   else /* ! literal */
5435     {
5436       MOVA (aopGet (left, 0, FALSE, FALSE));
5437
5438       if (!lUnsigned)
5439         {
5440           runtimeSign = TRUE;
5441           emitcode ("clr", "F0"); /* clear sign flag */
5442
5443           lbl = newiTempLabel (NULL);
5444           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5445           emitcode ("setb", "F0"); /* set sign flag */
5446           emitcode ("cpl", "a");   /* 2's complement */
5447           emitcode ("inc", "a");
5448           emitcode ("", "%05d$:", (lbl->key + 100));
5449         }
5450     }
5451
5452   /* now the modulus */
5453   emitcode ("div", "ab");
5454
5455   if (runtimeSign || compiletimeSign)
5456     {
5457       emitcode ("mov", "a,b");
5458       lbl = newiTempLabel (NULL);
5459       if (runtimeSign)
5460         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5461       emitcode ("cpl", "a"); /* 2's complement */
5462       emitcode ("inc", "a");
5463       emitcode ("", "%05d$:", (lbl->key + 100));
5464
5465       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5466       if (size > 0)
5467         {
5468           /* msb is 0x00 or 0xff depending on the sign */
5469           if (runtimeSign)
5470             {
5471               emitcode ("mov", "c,F0");
5472               emitcode ("subb", "a,acc");
5473               while (size--)
5474                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5475             }
5476           else /* compiletimeSign */
5477             while (size--)
5478               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5479         }
5480     }
5481   else
5482     {
5483       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5484       while (size--)
5485         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5486     }
5487
5488   popB (pushedB);
5489 }
5490
5491 /*-----------------------------------------------------------------*/
5492 /* genMod - generates code for division                            */
5493 /*-----------------------------------------------------------------*/
5494 static void
5495 genMod (iCode * ic)
5496 {
5497   operand *left = IC_LEFT (ic);
5498   operand *right = IC_RIGHT (ic);
5499   operand *result = IC_RESULT (ic);
5500
5501   D(emitcode (";     genMod",""));
5502
5503   /* assign the asmops */
5504   aopOp (left, ic, FALSE);
5505   aopOp (right, ic, FALSE);
5506   aopOp (result, ic, TRUE);
5507
5508   /* special cases first */
5509   /* both are bits */
5510   if (AOP_TYPE (left) == AOP_CRY &&
5511       AOP_TYPE (right) == AOP_CRY)
5512     {
5513       genModbits (left, right, result);
5514       goto release;
5515     }
5516
5517   /* if both are of size == 1 */
5518   if (AOP_SIZE (left) == 1 &&
5519       AOP_SIZE (right) == 1)
5520     {
5521       genModOneByte (left, right, result);
5522       goto release;
5523     }
5524
5525   /* should have been converted to function call */
5526   assert (0);
5527
5528 release:
5529   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5530   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5531   freeAsmop (result, NULL, ic, TRUE);
5532 }
5533
5534 /*-----------------------------------------------------------------*/
5535 /* genIfxJump :- will create a jump depending on the ifx           */
5536 /*-----------------------------------------------------------------*/
5537 static void
5538 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5539 {
5540   symbol *jlbl;
5541   symbol *tlbl = newiTempLabel (NULL);
5542   char *inst;
5543
5544   D(emitcode (";     genIfxJump",""));
5545
5546   /* if true label then we jump if condition
5547      supplied is true */
5548   if (IC_TRUE (ic))
5549     {
5550       jlbl = IC_TRUE (ic);
5551       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5552                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5553     }
5554   else
5555     {
5556       /* false label is present */
5557       jlbl = IC_FALSE (ic);
5558       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5559                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5560     }
5561   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5562     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5563   else
5564     emitcode (inst, "%05d$", tlbl->key + 100);
5565   freeForBranchAsmop (result);
5566   freeForBranchAsmop (right);
5567   freeForBranchAsmop (left);
5568   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5569   emitcode ("", "%05d$:", tlbl->key + 100);
5570
5571   /* mark the icode as generated */
5572   ic->generated = 1;
5573 }
5574
5575 /*-----------------------------------------------------------------*/
5576 /* genCmp :- greater or less than comparison                       */
5577 /*-----------------------------------------------------------------*/
5578 static void
5579 genCmp (operand * left, operand * right,
5580         operand * result, iCode * ifx, int sign, iCode *ic)
5581 {
5582   int size, offset = 0;
5583   unsigned long lit = 0L;
5584   bool rightInB;
5585
5586   D(emitcode (";     genCmp",""));
5587
5588   /* if left & right are bit variables */
5589   if (AOP_TYPE (left) == AOP_CRY &&
5590       AOP_TYPE (right) == AOP_CRY)
5591     {
5592       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5593       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5594     }
5595   else
5596     {
5597       /* subtract right from left if at the
5598          end the carry flag is set then we know that
5599          left is greater than right */
5600       size = max (AOP_SIZE (left), AOP_SIZE (right));
5601
5602       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5603       if ((size == 1) && !sign &&
5604           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5605         {
5606           symbol *lbl = newiTempLabel (NULL);
5607           emitcode ("cjne", "%s,%s,%05d$",
5608                     aopGet (left, offset, FALSE, FALSE),
5609                     aopGet (right, offset, FALSE, FALSE),
5610                     lbl->key + 100);
5611           emitcode ("", "%05d$:", lbl->key + 100);
5612         }
5613       else
5614         {
5615           if (AOP_TYPE (right) == AOP_LIT)
5616             {
5617               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5618               /* optimize if(x < 0) or if(x >= 0) */
5619               if (lit == 0L)
5620                 {
5621                   if (!sign)
5622                     {
5623                       CLRC;
5624                     }
5625                   else
5626                     {
5627                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5628                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5629                         {
5630                           genIfxJump (ifx, "acc.7", left, right, result);
5631                           freeAsmop (right, NULL, ic, TRUE);
5632                           freeAsmop (left, NULL, ic, TRUE);
5633
5634                           return;
5635                         }
5636                       else
5637                         emitcode ("rlc", "a");
5638                     }
5639                   goto release;
5640                 }
5641             }
5642           CLRC;
5643           while (size--)
5644             {
5645               bool pushedB = FALSE;
5646               rightInB = aopGetUsesAcc(right, offset);
5647               if (rightInB)
5648                 {
5649                   pushedB = pushB ();
5650                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5651                 }
5652               MOVA (aopGet (left, offset, FALSE, FALSE));
5653               if (sign && size == 0)
5654                 {
5655                   emitcode ("xrl", "a,#0x80");
5656                   if (AOP_TYPE (right) == AOP_LIT)
5657                     {
5658                       unsigned long lit = (unsigned long)
5659                       floatFromVal (AOP (right)->aopu.aop_lit);
5660                       emitcode ("subb", "a,#0x%02x",
5661                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5662                     }
5663                   else
5664                     {
5665                       if (!rightInB)
5666                         {
5667                           pushedB = pushB ();
5668                           rightInB++;
5669                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5670                         }
5671                       emitcode ("xrl", "b,#0x80");
5672                       emitcode ("subb", "a,b");
5673                     }
5674                 }
5675               else
5676                 {
5677                   if (rightInB)
5678                     emitcode ("subb", "a,b");
5679                   else
5680                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5681                 }
5682               if (rightInB)
5683                 popB (pushedB);
5684               offset++;
5685             }
5686         }
5687     }
5688
5689 release:
5690   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5691   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5692   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5693     {
5694       outBitC (result);
5695     }
5696   else
5697     {
5698       /* if the result is used in the next
5699          ifx conditional branch then generate
5700          code a little differently */
5701       if (ifx)
5702         genIfxJump (ifx, "c", NULL, NULL, result);
5703       else
5704         outBitC (result);
5705       /* leave the result in acc */
5706     }
5707 }
5708
5709 /*-----------------------------------------------------------------*/
5710 /* genCmpGt :- greater than comparison                             */
5711 /*-----------------------------------------------------------------*/
5712 static void
5713 genCmpGt (iCode * ic, iCode * ifx)
5714 {
5715   operand *left, *right, *result;
5716   sym_link *letype, *retype;
5717   int sign;
5718
5719   D(emitcode (";     genCmpGt",""));
5720
5721   left = IC_LEFT (ic);
5722   right = IC_RIGHT (ic);
5723   result = IC_RESULT (ic);
5724
5725   letype = getSpec (operandType (left));
5726   retype = getSpec (operandType (right));
5727   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5728            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5729   /* assign the amsops */
5730   aopOp (left, ic, FALSE);
5731   aopOp (right, ic, FALSE);
5732   aopOp (result, ic, TRUE);
5733
5734   genCmp (right, left, result, ifx, sign, ic);
5735
5736   freeAsmop (result, NULL, ic, TRUE);
5737 }
5738
5739 /*-----------------------------------------------------------------*/
5740 /* genCmpLt - less than comparisons                                */
5741 /*-----------------------------------------------------------------*/
5742 static void
5743 genCmpLt (iCode * ic, iCode * ifx)
5744 {
5745   operand *left, *right, *result;
5746   sym_link *letype, *retype;
5747   int sign;
5748
5749   D(emitcode (";     genCmpLt",""));
5750
5751   left = IC_LEFT (ic);
5752   right = IC_RIGHT (ic);
5753   result = IC_RESULT (ic);
5754
5755   letype = getSpec (operandType (left));
5756   retype = getSpec (operandType (right));
5757   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5758            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5759   /* assign the amsops */
5760   aopOp (left, ic, FALSE);
5761   aopOp (right, ic, FALSE);
5762   aopOp (result, ic, TRUE);
5763
5764   genCmp (left, right, result, ifx, sign, ic);
5765
5766   freeAsmop (result, NULL, ic, TRUE);
5767 }
5768
5769 /*-----------------------------------------------------------------*/
5770 /* gencjneshort - compare and jump if not equal                    */
5771 /*-----------------------------------------------------------------*/
5772 static void
5773 gencjneshort (operand * left, operand * right, symbol * lbl)
5774 {
5775   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5776   int offset = 0;
5777   unsigned long lit = 0L;
5778
5779   /* if the left side is a literal or
5780      if the right is in a pointer register and left
5781      is not */
5782   if ((AOP_TYPE (left) == AOP_LIT) ||
5783       (AOP_TYPE (left) == AOP_IMMD) ||
5784       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5785     {
5786       operand *t = right;
5787       right = left;
5788       left = t;
5789     }
5790
5791   if (AOP_TYPE (right) == AOP_LIT)
5792     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5793
5794   /* if the right side is a literal then anything goes */
5795   if (AOP_TYPE (right) == AOP_LIT &&
5796       AOP_TYPE (left) != AOP_DIR  &&
5797       AOP_TYPE (left) != AOP_IMMD)
5798     {
5799       while (size--)
5800         {
5801           emitcode ("cjne", "%s,%s,%05d$",
5802                     aopGet (left, offset, FALSE, FALSE),
5803                     aopGet (right, offset, FALSE, FALSE),
5804                     lbl->key + 100);
5805           offset++;
5806         }
5807     }
5808
5809   /* if the right side is in a register or in direct space or
5810      if the left is a pointer register & right is not */
5811   else if (AOP_TYPE (right) == AOP_REG ||
5812            AOP_TYPE (right) == AOP_DIR ||
5813            AOP_TYPE (right) == AOP_LIT ||
5814            AOP_TYPE (right) == AOP_IMMD ||
5815            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5816            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5817     {
5818       while (size--)
5819         {
5820           MOVA (aopGet (left, offset, FALSE, FALSE));
5821           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5822               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5823             emitcode ("jnz", "%05d$", lbl->key + 100);
5824           else
5825             emitcode ("cjne", "a,%s,%05d$",
5826                       aopGet (right, offset, FALSE, TRUE),
5827                       lbl->key + 100);
5828           offset++;
5829         }
5830     }
5831   else
5832     {
5833       /* right is a pointer reg need both a & b */
5834       while (size--)
5835         {
5836           char *l;
5837           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5838           wassertl(!BINUSE, "B was in use");
5839           l = aopGet (left, offset, FALSE, FALSE);
5840           if (strcmp (l, "b"))
5841             emitcode ("mov", "b,%s", l);
5842           MOVA (aopGet (right, offset, FALSE, FALSE));
5843           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5844           offset++;
5845         }
5846     }
5847 }
5848
5849 /*-----------------------------------------------------------------*/
5850 /* gencjne - compare and jump if not equal                         */
5851 /*-----------------------------------------------------------------*/
5852 static void
5853 gencjne (operand * left, operand * right, symbol * lbl)
5854 {
5855   symbol *tlbl = newiTempLabel (NULL);
5856
5857   gencjneshort (left, right, lbl);
5858
5859   emitcode ("mov", "a,%s", one);
5860   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5861   emitcode ("", "%05d$:", lbl->key + 100);
5862   emitcode ("clr", "a");
5863   emitcode ("", "%05d$:", tlbl->key + 100);
5864 }
5865
5866 /*-----------------------------------------------------------------*/
5867 /* genCmpEq - generates code for equal to                          */
5868 /*-----------------------------------------------------------------*/
5869 static void
5870 genCmpEq (iCode * ic, iCode * ifx)
5871 {
5872   operand *left, *right, *result;
5873
5874   D(emitcode (";     genCmpEq",""));
5875
5876   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5877   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5878   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5879
5880   /* if literal, literal on the right or
5881      if the right is in a pointer register and left
5882      is not */
5883   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5884       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5885     {
5886       operand *t = IC_RIGHT (ic);
5887       IC_RIGHT (ic) = IC_LEFT (ic);
5888       IC_LEFT (ic) = t;
5889     }
5890
5891   if (ifx && !AOP_SIZE (result))
5892     {
5893       symbol *tlbl;
5894       /* if they are both bit variables */
5895       if (AOP_TYPE (left) == AOP_CRY &&
5896           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5897         {
5898           if (AOP_TYPE (right) == AOP_LIT)
5899             {
5900               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5901               if (lit == 0L)
5902                 {
5903                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5904                   emitcode ("cpl", "c");
5905                 }
5906               else if (lit == 1L)
5907                 {
5908                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5909                 }
5910               else
5911                 {
5912                   emitcode ("clr", "c");
5913                 }
5914               /* AOP_TYPE(right) == AOP_CRY */
5915             }
5916           else
5917             {
5918               symbol *lbl = newiTempLabel (NULL);
5919               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5920               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5921               emitcode ("cpl", "c");
5922               emitcode ("", "%05d$:", (lbl->key + 100));
5923             }
5924           /* if true label then we jump if condition
5925              supplied is true */
5926           tlbl = newiTempLabel (NULL);
5927           if (IC_TRUE (ifx))
5928             {
5929               emitcode ("jnc", "%05d$", tlbl->key + 100);
5930               freeForBranchAsmop (result);
5931               freeForBranchAsmop (right);
5932               freeForBranchAsmop (left);
5933               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5934             }
5935           else
5936             {
5937               emitcode ("jc", "%05d$", tlbl->key + 100);
5938               freeForBranchAsmop (result);
5939               freeForBranchAsmop (right);
5940               freeForBranchAsmop (left);
5941               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5942             }
5943           emitcode ("", "%05d$:", tlbl->key + 100);
5944         }
5945       else
5946         {
5947           tlbl = newiTempLabel (NULL);
5948           gencjneshort (left, right, tlbl);
5949           if (IC_TRUE (ifx))
5950             {
5951               freeForBranchAsmop (result);
5952               freeForBranchAsmop (right);
5953               freeForBranchAsmop (left);
5954               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5955               emitcode ("", "%05d$:", tlbl->key + 100);
5956             }
5957           else
5958             {
5959               symbol *lbl = newiTempLabel (NULL);
5960               emitcode ("sjmp", "%05d$", lbl->key + 100);
5961               emitcode ("", "%05d$:", tlbl->key + 100);
5962               freeForBranchAsmop (result);
5963               freeForBranchAsmop (right);
5964               freeForBranchAsmop (left);
5965               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5966               emitcode ("", "%05d$:", lbl->key + 100);
5967             }
5968         }
5969       /* mark the icode as generated */
5970       ifx->generated = 1;
5971       goto release;
5972     }
5973
5974   /* if they are both bit variables */
5975   if (AOP_TYPE (left) == AOP_CRY &&
5976       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5977     {
5978       if (AOP_TYPE (right) == AOP_LIT)
5979         {
5980           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5981           if (lit == 0L)
5982             {
5983               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5984               emitcode ("cpl", "c");
5985             }
5986           else if (lit == 1L)
5987             {
5988               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5989             }
5990           else
5991             {
5992               emitcode ("clr", "c");
5993             }
5994           /* AOP_TYPE(right) == AOP_CRY */
5995         }
5996       else
5997         {
5998           symbol *lbl = newiTempLabel (NULL);
5999           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6000           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6001           emitcode ("cpl", "c");
6002           emitcode ("", "%05d$:", (lbl->key + 100));
6003         }
6004       /* c = 1 if egal */
6005       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6006         {
6007           outBitC (result);
6008           goto release;
6009         }
6010       if (ifx)
6011         {
6012           genIfxJump (ifx, "c", left, right, result);
6013           goto release;
6014         }
6015       /* if the result is used in an arithmetic operation
6016          then put the result in place */
6017       outBitC (result);
6018     }
6019   else
6020     {
6021       gencjne (left, right, newiTempLabel (NULL));
6022       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6023         {
6024           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
6025           goto release;
6026         }
6027       if (ifx)
6028         {
6029           genIfxJump (ifx, "a", left, right, result);
6030           goto release;
6031         }
6032       /* if the result is used in an arithmetic operation
6033          then put the result in place */
6034       if (AOP_TYPE (result) != AOP_CRY)
6035         outAcc (result);
6036       /* leave the result in acc */
6037     }
6038
6039 release:
6040   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6041   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6042   freeAsmop (result, NULL, ic, TRUE);
6043 }
6044
6045 /*-----------------------------------------------------------------*/
6046 /* ifxForOp - returns the icode containing the ifx for operand     */
6047 /*-----------------------------------------------------------------*/
6048 static iCode *
6049 ifxForOp (operand * op, iCode * ic)
6050 {
6051   /* if true symbol then needs to be assigned */
6052   if (IS_TRUE_SYMOP (op))
6053     return NULL;
6054
6055   /* if this has register type condition and
6056      the next instruction is ifx with the same operand
6057      and live to of the operand is upto the ifx only then */
6058   if (ic->next &&
6059       ic->next->op == IFX &&
6060       IC_COND (ic->next)->key == op->key &&
6061       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6062     return ic->next;
6063
6064   return NULL;
6065 }
6066
6067 /*-----------------------------------------------------------------*/
6068 /* hasInc - operand is incremented before any other use            */
6069 /*-----------------------------------------------------------------*/
6070 static iCode *
6071 hasInc (operand *op, iCode *ic,int osize)
6072 {
6073   sym_link *type = operandType(op);
6074   sym_link *retype = getSpec (type);
6075   iCode *lic = ic->next;
6076   int isize ;
6077
6078   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6079   if (!IS_SYMOP(op)) return NULL;
6080
6081   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6082   if (IS_AGGREGATE(type->next)) return NULL;
6083   if (osize != (isize = getSize(type->next))) return NULL;
6084
6085   while (lic) {
6086     /* if operand of the form op = op + <sizeof *op> */
6087     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6088         isOperandEqual(IC_RESULT(lic),op) &&
6089         isOperandLiteral(IC_RIGHT(lic)) &&
6090         operandLitValue(IC_RIGHT(lic)) == isize) {
6091       return lic;
6092     }
6093     /* if the operand used or deffed */
6094     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6095       return NULL;
6096     }
6097     /* if GOTO or IFX */
6098     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6099     lic = lic->next;
6100   }
6101   return NULL;
6102 }
6103
6104 /*-----------------------------------------------------------------*/
6105 /* genAndOp - for && operation                                     */
6106 /*-----------------------------------------------------------------*/
6107 static void
6108 genAndOp (iCode * ic)
6109 {
6110   operand *left, *right, *result;
6111   symbol *tlbl;
6112
6113   D(emitcode (";     genAndOp",""));
6114
6115   /* note here that && operations that are in an
6116      if statement are taken away by backPatchLabels
6117      only those used in arthmetic operations remain */
6118   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6119   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6120   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6121
6122   /* if both are bit variables */
6123   if (AOP_TYPE (left) == AOP_CRY &&
6124       AOP_TYPE (right) == AOP_CRY)
6125     {
6126       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6127       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6128       outBitC (result);
6129     }
6130   else
6131     {
6132       tlbl = newiTempLabel (NULL);
6133       toBoolean (left);
6134       emitcode ("jz", "%05d$", tlbl->key + 100);
6135       toBoolean (right);
6136       emitcode ("", "%05d$:", tlbl->key + 100);
6137       outBitAcc (result);
6138     }
6139
6140   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6141   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6142   freeAsmop (result, NULL, ic, TRUE);
6143 }
6144
6145
6146 /*-----------------------------------------------------------------*/
6147 /* genOrOp - for || operation                                      */
6148 /*-----------------------------------------------------------------*/
6149 static void
6150 genOrOp (iCode * ic)
6151 {
6152   operand *left, *right, *result;
6153   symbol *tlbl;
6154
6155   D(emitcode (";     genOrOp",""));
6156
6157   /* note here that || operations that are in an
6158      if statement are taken away by backPatchLabels
6159      only those used in arthmetic operations remain */
6160   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6161   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6162   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6163
6164   /* if both are bit variables */
6165   if (AOP_TYPE (left) == AOP_CRY &&
6166       AOP_TYPE (right) == AOP_CRY)
6167     {
6168       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6169       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6170       outBitC (result);
6171     }
6172   else
6173     {
6174       tlbl = newiTempLabel (NULL);
6175       toBoolean (left);
6176       emitcode ("jnz", "%05d$", tlbl->key + 100);
6177       toBoolean (right);
6178       emitcode ("", "%05d$:", tlbl->key + 100);
6179       outBitAcc (result);
6180     }
6181
6182   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6183   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6184   freeAsmop (result, NULL, ic, TRUE);
6185 }
6186
6187 /*-----------------------------------------------------------------*/
6188 /* isLiteralBit - test if lit == 2^n                               */
6189 /*-----------------------------------------------------------------*/
6190 static int
6191 isLiteralBit (unsigned long lit)
6192 {
6193   unsigned long pw[32] =
6194   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6195    0x100L, 0x200L, 0x400L, 0x800L,
6196    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6197    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6198    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6199    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6200    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6201   int idx;
6202
6203   for (idx = 0; idx < 32; idx++)
6204     if (lit == pw[idx])
6205       return idx + 1;
6206   return 0;
6207 }
6208
6209 /*-----------------------------------------------------------------*/
6210 /* continueIfTrue -                                                */
6211 /*-----------------------------------------------------------------*/
6212 static void
6213 continueIfTrue (iCode * ic)
6214 {
6215   if (IC_TRUE (ic))
6216     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6217   ic->generated = 1;
6218 }
6219
6220 /*-----------------------------------------------------------------*/
6221 /* jmpIfTrue -                                                     */
6222 /*-----------------------------------------------------------------*/
6223 static void
6224 jumpIfTrue (iCode * ic)
6225 {
6226   if (!IC_TRUE (ic))
6227     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6228   ic->generated = 1;
6229 }
6230
6231 /*-----------------------------------------------------------------*/
6232 /* jmpTrueOrFalse -                                                */
6233 /*-----------------------------------------------------------------*/
6234 static void
6235 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6236 {
6237   // ugly but optimized by peephole
6238   if (IC_TRUE (ic))
6239     {
6240       symbol *nlbl = newiTempLabel (NULL);
6241       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6242       emitcode ("", "%05d$:", tlbl->key + 100);
6243       freeForBranchAsmop (result);
6244       freeForBranchAsmop (right);
6245       freeForBranchAsmop (left);
6246       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6247       emitcode ("", "%05d$:", nlbl->key + 100);
6248     }
6249   else
6250     {
6251       freeForBranchAsmop (result);
6252       freeForBranchAsmop (right);
6253       freeForBranchAsmop (left);
6254       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6255       emitcode ("", "%05d$:", tlbl->key + 100);
6256     }
6257   ic->generated = 1;
6258 }
6259
6260 /*-----------------------------------------------------------------*/
6261 /* genAnd  - code for and                                          */
6262 /*-----------------------------------------------------------------*/
6263 static void
6264 genAnd (iCode * ic, iCode * ifx)
6265 {
6266   operand *left, *right, *result;
6267   int size, offset = 0;
6268   unsigned long lit = 0L;
6269   int bytelit = 0;
6270   char buffer[10];
6271
6272   D(emitcode (";     genAnd",""));
6273
6274   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6275   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6276   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6277
6278 #ifdef DEBUG_TYPE
6279   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6280             AOP_TYPE (result),
6281             AOP_TYPE (left), AOP_TYPE (right));
6282   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6283             AOP_SIZE (result),
6284             AOP_SIZE (left), AOP_SIZE (right));
6285 #endif
6286
6287   /* if left is a literal & right is not then exchange them */
6288   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6289       AOP_NEEDSACC (left))
6290     {
6291       operand *tmp = right;
6292       right = left;
6293       left = tmp;
6294     }
6295
6296   /* if result = right then exchange left and right */
6297   if (sameRegs (AOP (result), AOP (right)))
6298     {
6299       operand *tmp = right;
6300       right = left;
6301       left = tmp;
6302     }
6303
6304   /* if right is bit then exchange them */
6305   if (AOP_TYPE (right) == AOP_CRY &&
6306       AOP_TYPE (left) != AOP_CRY)
6307     {
6308       operand *tmp = right;
6309       right = left;
6310       left = tmp;
6311     }
6312   if (AOP_TYPE (right) == AOP_LIT)
6313     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6314
6315   size = AOP_SIZE (result);
6316
6317   // if(bit & yy)
6318   // result = bit & yy;
6319   if (AOP_TYPE (left) == AOP_CRY)
6320     {
6321       // c = bit & literal;
6322       if (AOP_TYPE (right) == AOP_LIT)
6323         {
6324           if (lit & 1)
6325             {
6326               if (size && sameRegs (AOP (result), AOP (left)))
6327                 // no change
6328                 goto release;
6329               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6330             }
6331           else
6332             {
6333               // bit(result) = 0;
6334               if (size && (AOP_TYPE (result) == AOP_CRY))
6335                 {
6336                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6337                   goto release;
6338                 }
6339               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6340                 {
6341                   jumpIfTrue (ifx);
6342                   goto release;
6343                 }
6344               emitcode ("clr", "c");
6345             }
6346         }
6347       else
6348         {
6349           if (AOP_TYPE (right) == AOP_CRY)
6350             {
6351               // c = bit & bit;
6352               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6353               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6354             }
6355           else
6356             {
6357               // c = bit & val;
6358               MOVA (aopGet (right, 0, FALSE, FALSE));
6359               // c = lsb
6360               emitcode ("rrc", "a");
6361               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6362             }
6363         }
6364       // bit = c
6365       // val = c
6366       if (size)
6367         outBitC (result);
6368       // if(bit & ...)
6369       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6370         genIfxJump (ifx, "c", left, right, result);
6371       goto release;
6372     }
6373
6374   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6375   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6376   if ((AOP_TYPE (right) == AOP_LIT) &&
6377       (AOP_TYPE (result) == AOP_CRY) &&
6378       (AOP_TYPE (left) != AOP_CRY))
6379     {
6380       int posbit = isLiteralBit (lit);
6381       /* left &  2^n */
6382       if (posbit)
6383         {
6384           posbit--;
6385           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6386           // bit = left & 2^n
6387           if (size)
6388             {
6389               switch (posbit & 0x07)
6390                 {
6391                   case 0: emitcode ("rrc", "a");
6392                           break;
6393                   case 7: emitcode ("rlc", "a");
6394                           break;
6395                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6396                           break;
6397                 }
6398             }
6399           // if(left &  2^n)
6400           else
6401             {
6402               if (ifx)
6403                 {
6404                   SNPRINTF (buffer, sizeof(buffer),
6405                             "acc.%d", posbit & 0x07);
6406                   genIfxJump (ifx, buffer, left, right, result);
6407                 }
6408               else
6409                 {// what is this case? just found it in ds390/gen.c
6410                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6411                 }
6412               goto release;
6413             }
6414         }
6415       else
6416         {
6417           symbol *tlbl = newiTempLabel (NULL);
6418           int sizel = AOP_SIZE (left);
6419           if (size)
6420             emitcode ("setb", "c");
6421           while (sizel--)
6422             {
6423               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6424                 {
6425                   MOVA (aopGet (left, offset, FALSE, FALSE));
6426                   // byte ==  2^n ?
6427                   if ((posbit = isLiteralBit (bytelit)) != 0)
6428                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6429                   else
6430                     {
6431                       if (bytelit != 0x0FFL)
6432                         emitcode ("anl", "a,%s",
6433                                   aopGet (right, offset, FALSE, TRUE));
6434                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6435                     }
6436                 }
6437               offset++;
6438             }
6439           // bit = left & literal
6440           if (size)
6441             {
6442               emitcode ("clr", "c");
6443               emitcode ("", "%05d$:", tlbl->key + 100);
6444             }
6445           // if(left & literal)
6446           else
6447             {
6448               if (ifx)
6449                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6450               else
6451                 emitcode ("", "%05d$:", tlbl->key + 100);
6452               goto release;
6453             }
6454         }
6455       outBitC (result);
6456       goto release;
6457     }
6458
6459   /* if left is same as result */
6460   if (sameRegs (AOP (result), AOP (left)))
6461     {
6462       for (; size--; offset++)
6463         {
6464           if (AOP_TYPE (right) == AOP_LIT)
6465             {
6466               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6467               if (bytelit == 0x0FF)
6468                 {
6469                   /* dummy read of volatile operand */
6470                   if (isOperandVolatile (left, FALSE))
6471                     MOVA (aopGet (left, offset, FALSE, FALSE));
6472                   else
6473                     continue;
6474                 }
6475               else if (bytelit == 0)
6476                 {
6477                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6478                 }
6479               else if (IS_AOP_PREG (result))
6480                 {
6481                   MOVA (aopGet (left, offset, FALSE, TRUE));
6482                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6483                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6484                 }
6485               else
6486                 emitcode ("anl", "%s,%s",
6487                           aopGet (left, offset, FALSE, TRUE),
6488                           aopGet (right, offset, FALSE, FALSE));
6489             }
6490           else
6491             {
6492               if (AOP_TYPE (left) == AOP_ACC)
6493                 {
6494                   if (offset)
6495                     emitcode("mov", "a,b");
6496                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6497                 }
6498               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6499                 {
6500                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6501                   MOVA (aopGet (right, offset, FALSE, FALSE));
6502                   emitcode ("anl", "a,b");
6503                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6504                 }
6505               else if (aopGetUsesAcc (left, offset))
6506                 {
6507                   MOVA (aopGet (left, offset, FALSE, FALSE));
6508                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6509                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6510                 }
6511               else
6512                 {
6513                   MOVA (aopGet (right, offset, FALSE, FALSE));
6514                   if (IS_AOP_PREG (result))
6515                     {
6516                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6517                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6518                     }
6519                   else
6520                     emitcode ("anl", "%s,a",
6521                               aopGet (left, offset, FALSE, TRUE));
6522                 }
6523             }
6524         }
6525     }
6526   else
6527     {
6528       // left & result in different registers
6529       if (AOP_TYPE (result) == AOP_CRY)
6530         {
6531           // result = bit
6532           // if(size), result in bit
6533           // if(!size && ifx), conditional oper: if(left & right)
6534           symbol *tlbl = newiTempLabel (NULL);
6535           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6536           if (size)
6537             emitcode ("setb", "c");
6538           while (sizer--)
6539             {
6540               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6541                   && AOP_TYPE(left)==AOP_ACC)
6542                 {
6543                   if (offset)
6544                     emitcode("mov", "a,b");
6545                   emitcode ("anl", "a,%s",
6546                             aopGet (right, offset, FALSE, FALSE));
6547                 } else {
6548                   if (AOP_TYPE(left)==AOP_ACC)
6549                     {
6550                       if (!offset)
6551                         {
6552                           bool pushedB = pushB ();
6553                           emitcode("mov", "b,a");
6554                           MOVA (aopGet (right, offset, FALSE, FALSE));
6555                           emitcode("anl", "a,b");
6556                           popB (pushedB);
6557                         }
6558                       else
6559                         {
6560                           MOVA (aopGet (right, offset, FALSE, FALSE));
6561                           emitcode("anl", "a,b");
6562                         }
6563                     } else {
6564                       MOVA (aopGet (right, offset, FALSE, FALSE));
6565                       emitcode ("anl", "a,%s",
6566                                 aopGet (left, offset, FALSE, FALSE));
6567                     }
6568                 }
6569               emitcode ("jnz", "%05d$", tlbl->key + 100);
6570               offset++;
6571             }
6572           if (size)
6573             {
6574               CLRC;
6575               emitcode ("", "%05d$:", tlbl->key + 100);
6576               outBitC (result);
6577             }
6578           else if (ifx)
6579             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6580           else
6581             emitcode ("", "%05d$:", tlbl->key + 100);
6582         }
6583       else
6584         {
6585           for (; (size--); offset++)
6586             {
6587               // normal case
6588               // result = left & right
6589               if (AOP_TYPE (right) == AOP_LIT)
6590                 {
6591                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6592                   if (bytelit == 0x0FF)
6593                     {
6594                       aopPut (result,
6595                               aopGet (left, offset, FALSE, FALSE),
6596                               offset,
6597                               isOperandVolatile (result, FALSE));
6598                       continue;
6599                     }
6600                   else if (bytelit == 0)
6601                     {
6602                       /* dummy read of volatile operand */
6603                       if (isOperandVolatile (left, FALSE))
6604                         MOVA (aopGet (left, offset, FALSE, FALSE));
6605                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6606                       continue;
6607                     }
6608                   else if (AOP_TYPE (left) == AOP_ACC)
6609                     {
6610                       if (!offset)
6611                         {
6612                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6613                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6614                           continue;
6615                         }
6616                       else
6617                         {
6618                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6619                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6620                           continue;
6621                         }
6622                     }
6623                 }
6624               // faster than result <- left, anl result,right
6625               // and better if result is SFR
6626               if (AOP_TYPE (left) == AOP_ACC)
6627                 {
6628                   if (offset)
6629                     emitcode("mov", "a,b");
6630                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6631                 }
6632               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6633                 {
6634                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6635                   MOVA (aopGet (right, offset, FALSE, FALSE));
6636                   emitcode ("anl", "a,b");
6637                 }
6638               else if (aopGetUsesAcc (left, offset))
6639                 {
6640                   MOVA (aopGet (left, offset, FALSE, FALSE));
6641                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6642                 }
6643               else
6644                 {
6645                   MOVA (aopGet (right, offset, FALSE, FALSE));
6646                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6647                 }
6648               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6649             }
6650         }
6651     }
6652
6653 release:
6654   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6655   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6656   freeAsmop (result, NULL, ic, TRUE);
6657 }
6658
6659 /*-----------------------------------------------------------------*/
6660 /* genOr  - code for or                                            */
6661 /*-----------------------------------------------------------------*/
6662 static void
6663 genOr (iCode * ic, iCode * ifx)
6664 {
6665   operand *left, *right, *result;
6666   int size, offset = 0;
6667   unsigned long lit = 0L;
6668   int bytelit = 0;
6669
6670   D(emitcode (";     genOr",""));
6671
6672   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6673   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6674   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6675
6676 #ifdef DEBUG_TYPE
6677   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6678             AOP_TYPE (result),
6679             AOP_TYPE (left), AOP_TYPE (right));
6680   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6681             AOP_SIZE (result),
6682             AOP_SIZE (left), AOP_SIZE (right));
6683 #endif
6684
6685   /* if left is a literal & right is not then exchange them */
6686   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6687       AOP_NEEDSACC (left))
6688     {
6689       operand *tmp = right;
6690       right = left;
6691       left = tmp;
6692     }
6693
6694   /* if result = right then exchange them */
6695   if (sameRegs (AOP (result), AOP (right)))
6696     {
6697       operand *tmp = right;
6698       right = left;
6699       left = tmp;
6700     }
6701
6702   /* if right is bit then exchange them */
6703   if (AOP_TYPE (right) == AOP_CRY &&
6704       AOP_TYPE (left) != AOP_CRY)
6705     {
6706       operand *tmp = right;
6707       right = left;
6708       left = tmp;
6709     }
6710   if (AOP_TYPE (right) == AOP_LIT)
6711     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6712
6713   size = AOP_SIZE (result);
6714
6715   // if(bit | yy)
6716   // xx = bit | yy;
6717   if (AOP_TYPE (left) == AOP_CRY)
6718     {
6719       if (AOP_TYPE (right) == AOP_LIT)
6720         {
6721           // c = bit | literal;
6722           if (lit)
6723             {
6724               // lit != 0 => result = 1
6725               if (AOP_TYPE (result) == AOP_CRY)
6726                 {
6727                   if (size)
6728                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6729                   else if (ifx)
6730                     continueIfTrue (ifx);
6731                   goto release;
6732                 }
6733               emitcode ("setb", "c");
6734             }
6735           else
6736             {
6737               // lit == 0 => result = left
6738               if (size && sameRegs (AOP (result), AOP (left)))
6739                 goto release;
6740               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6741             }
6742         }
6743       else
6744         {
6745           if (AOP_TYPE (right) == AOP_CRY)
6746             {
6747               // c = bit | bit;
6748               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6749               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6750             }
6751           else
6752             {
6753               // c = bit | val;
6754               symbol *tlbl = newiTempLabel (NULL);
6755               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6756                 emitcode ("setb", "c");
6757               emitcode ("jb", "%s,%05d$",
6758                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6759               toBoolean (right);
6760               emitcode ("jnz", "%05d$", tlbl->key + 100);
6761               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6762                 {
6763                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6764                   goto release;
6765                 }
6766               else
6767                 {
6768                   CLRC;
6769                   emitcode ("", "%05d$:", tlbl->key + 100);
6770                 }
6771             }
6772         }
6773       // bit = c
6774       // val = c
6775       if (size)
6776         outBitC (result);
6777       // if(bit | ...)
6778       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6779         genIfxJump (ifx, "c", left, right, result);
6780       goto release;
6781     }
6782
6783   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6784   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6785   if ((AOP_TYPE (right) == AOP_LIT) &&
6786       (AOP_TYPE (result) == AOP_CRY) &&
6787       (AOP_TYPE (left) != AOP_CRY))
6788     {
6789       if (lit)
6790         {
6791           // result = 1
6792           if (size)
6793             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6794           else
6795             continueIfTrue (ifx);
6796           goto release;
6797         }
6798       else
6799         {
6800           // lit = 0, result = boolean(left)
6801           if (size)
6802             emitcode ("setb", "c");
6803           toBoolean (right);
6804           if (size)
6805             {
6806               symbol *tlbl = newiTempLabel (NULL);
6807               emitcode ("jnz", "%05d$", tlbl->key + 100);
6808               CLRC;
6809               emitcode ("", "%05d$:", tlbl->key + 100);
6810             }
6811           else
6812             {
6813               genIfxJump (ifx, "a", left, right, result);
6814               goto release;
6815             }
6816         }
6817       outBitC (result);
6818       goto release;
6819     }
6820
6821   /* if left is same as result */
6822   if (sameRegs (AOP (result), AOP (left)))
6823     {
6824       for (; size--; offset++)
6825         {
6826           if (AOP_TYPE (right) == AOP_LIT)
6827             {
6828               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6829               if (bytelit == 0)
6830                 {
6831                   /* dummy read of volatile operand */
6832                   if (isOperandVolatile (left, FALSE))
6833                     MOVA (aopGet (left, offset, FALSE, FALSE));
6834                   else
6835                     continue;
6836                 }
6837               else if (bytelit == 0x0FF)
6838                 {
6839                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6840                 }
6841               else if (IS_AOP_PREG (left))
6842                 {
6843                   MOVA (aopGet (left, offset, FALSE, TRUE));
6844                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6845                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6846                 }
6847               else
6848                 {
6849                   emitcode ("orl", "%s,%s",
6850                             aopGet (left, offset, FALSE, TRUE),
6851                             aopGet (right, offset, FALSE, FALSE));
6852                 }
6853             }
6854           else
6855             {
6856               if (AOP_TYPE (left) == AOP_ACC)
6857                 {
6858                   if (offset)
6859                     emitcode("mov", "a,b");
6860                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6861                 }
6862               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6863                 {
6864                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6865                   MOVA (aopGet (right, offset, FALSE, FALSE));
6866                   emitcode ("orl", "a,b");
6867                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6868                 }
6869               else if (aopGetUsesAcc (left, offset))
6870                 {
6871                   MOVA (aopGet (left, offset, FALSE, FALSE));
6872                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6873                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6874                 }
6875               else
6876                 {
6877                   MOVA (aopGet (right, offset, FALSE, FALSE));
6878                   if (IS_AOP_PREG (left))
6879                     {
6880                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6881                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6882                     }
6883                   else
6884                     {
6885                       emitcode ("orl", "%s,a",
6886                                 aopGet (left, offset, FALSE, TRUE));
6887                     }
6888                 }
6889             }
6890         }
6891     }
6892   else
6893     {
6894       // left & result in different registers
6895       if (AOP_TYPE (result) == AOP_CRY)
6896         {
6897           // result = bit
6898           // if(size), result in bit
6899           // if(!size && ifx), conditional oper: if(left | right)
6900           symbol *tlbl = newiTempLabel (NULL);
6901           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6902           if (size)
6903             emitcode ("setb", "c");
6904           while (sizer--)
6905             {
6906               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6907                 if (offset)
6908                   emitcode("mov", "a,b");
6909                 emitcode ("orl", "a,%s",
6910                           aopGet (right, offset, FALSE, FALSE));
6911               } else {
6912                 MOVA (aopGet (right, offset, FALSE, FALSE));
6913                 emitcode ("orl", "a,%s",
6914                           aopGet (left, offset, FALSE, FALSE));
6915               }
6916               emitcode ("jnz", "%05d$", tlbl->key + 100);
6917               offset++;
6918             }
6919           if (size)
6920             {
6921               CLRC;
6922               emitcode ("", "%05d$:", tlbl->key + 100);
6923               outBitC (result);
6924             }
6925           else if (ifx)
6926             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6927           else
6928             emitcode ("", "%05d$:", tlbl->key + 100);
6929         }
6930       else
6931         {
6932           for (; (size--); offset++)
6933             {
6934               // normal case
6935               // result = left | right
6936               if (AOP_TYPE (right) == AOP_LIT)
6937                 {
6938                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6939                   if (bytelit == 0)
6940                     {
6941                       aopPut (result,
6942                               aopGet (left, offset, FALSE, FALSE),
6943                               offset,
6944                               isOperandVolatile (result, FALSE));
6945                       continue;
6946                     }
6947                   else if (bytelit == 0x0FF)
6948                     {
6949                       /* dummy read of volatile operand */
6950                       if (isOperandVolatile (left, FALSE))
6951                         MOVA (aopGet (left, offset, FALSE, FALSE));
6952                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6953                       continue;
6954                     }
6955                 }
6956               // faster than result <- left, anl result,right
6957               // and better if result is SFR
6958               if (AOP_TYPE (left) == AOP_ACC)
6959                 {
6960                   if (offset)
6961                     emitcode("mov", "a,b");
6962                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6963                 }
6964               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6965                 {
6966                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
6967                   MOVA (aopGet (right, offset, FALSE, FALSE));
6968                   emitcode ("orl", "a,b");
6969                 }
6970               else if (aopGetUsesAcc (left, offset))
6971                 {
6972                   MOVA (aopGet (left, offset, FALSE, FALSE));
6973                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6974                 }
6975               else
6976                 {
6977                   MOVA (aopGet (right, offset, FALSE, FALSE));
6978                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6979                 }
6980               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6981             }
6982         }
6983     }
6984
6985 release:
6986   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6987   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6988   freeAsmop (result, NULL, ic, TRUE);
6989 }
6990
6991 /*-----------------------------------------------------------------*/
6992 /* genXor - code for xclusive or                                   */
6993 /*-----------------------------------------------------------------*/
6994 static void
6995 genXor (iCode * ic, iCode * ifx)
6996 {
6997   operand *left, *right, *result;
6998   int size, offset = 0;
6999   unsigned long lit = 0L;
7000   int bytelit = 0;
7001
7002   D(emitcode (";     genXor",""));
7003
7004   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7005   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7006   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7007
7008 #ifdef DEBUG_TYPE
7009   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7010             AOP_TYPE (result),
7011             AOP_TYPE (left), AOP_TYPE (right));
7012   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7013             AOP_SIZE (result),
7014             AOP_SIZE (left), AOP_SIZE (right));
7015 #endif
7016
7017   /* if left is a literal & right is not ||
7018      if left needs acc & right does not */
7019   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7020       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7021     {
7022       operand *tmp = right;
7023       right = left;
7024       left = tmp;
7025     }
7026
7027   /* if result = right then exchange them */
7028   if (sameRegs (AOP (result), AOP (right)))
7029     {
7030       operand *tmp = right;
7031       right = left;
7032       left = tmp;
7033     }
7034
7035   /* if right is bit then exchange them */
7036   if (AOP_TYPE (right) == AOP_CRY &&
7037       AOP_TYPE (left) != AOP_CRY)
7038     {
7039       operand *tmp = right;
7040       right = left;
7041       left = tmp;
7042     }
7043   if (AOP_TYPE (right) == AOP_LIT)
7044     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7045
7046   size = AOP_SIZE (result);
7047
7048   // if(bit ^ yy)
7049   // xx = bit ^ yy;
7050   if (AOP_TYPE (left) == AOP_CRY)
7051     {
7052       if (AOP_TYPE (right) == AOP_LIT)
7053         {
7054           // c = bit & literal;
7055           if (lit >> 1)
7056             {
7057               // lit>>1  != 0 => result = 1
7058               if (AOP_TYPE (result) == AOP_CRY)
7059                 {
7060                   if (size)
7061                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7062                   else if (ifx)
7063                     continueIfTrue (ifx);
7064                   goto release;
7065                 }
7066               emitcode ("setb", "c");
7067             }
7068           else
7069             {
7070               // lit == (0 or 1)
7071               if (lit == 0)
7072                 {
7073                   // lit == 0, result = left
7074                   if (size && sameRegs (AOP (result), AOP (left)))
7075                     goto release;
7076                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7077                 }
7078               else
7079                 {
7080                   // lit == 1, result = not(left)
7081                   if (size && sameRegs (AOP (result), AOP (left)))
7082                     {
7083                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7084                       goto release;
7085                     }
7086                   else
7087                     {
7088                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7089                       emitcode ("cpl", "c");
7090                     }
7091                 }
7092             }
7093
7094         }
7095       else
7096         {
7097           // right != literal
7098           symbol *tlbl = newiTempLabel (NULL);
7099           if (AOP_TYPE (right) == AOP_CRY)
7100             {
7101               // c = bit ^ bit;
7102               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7103             }
7104           else
7105             {
7106               int sizer = AOP_SIZE (right);
7107               // c = bit ^ val
7108               // if val>>1 != 0, result = 1
7109               emitcode ("setb", "c");
7110               while (sizer)
7111                 {
7112                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7113                   if (sizer == 1)
7114                     // test the msb of the lsb
7115                     emitcode ("anl", "a,#0xfe");
7116                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7117                   sizer--;
7118                 }
7119               // val = (0,1)
7120               emitcode ("rrc", "a");
7121             }
7122           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7123           emitcode ("cpl", "c");
7124           emitcode ("", "%05d$:", (tlbl->key + 100));
7125         }
7126       // bit = c
7127       // val = c
7128       if (size)
7129         outBitC (result);
7130       // if(bit | ...)
7131       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7132         genIfxJump (ifx, "c", left, right, result);
7133       goto release;
7134     }
7135
7136   /* if left is same as result */
7137   if (sameRegs (AOP (result), AOP (left)))
7138     {
7139       for (; size--; offset++)
7140         {
7141           if (AOP_TYPE (right) == AOP_LIT)
7142             {
7143               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7144               if (bytelit == 0)
7145                 {
7146                   /* dummy read of volatile operand */
7147                   if (isOperandVolatile (left, FALSE))
7148                     MOVA (aopGet (left, offset, FALSE, FALSE));
7149                   else
7150                     continue;
7151                 }
7152               else if (IS_AOP_PREG (left))
7153                 {
7154                   MOVA (aopGet (left, offset, FALSE, TRUE));
7155                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7156                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7157                 }
7158               else
7159                 {
7160                   emitcode ("xrl", "%s,%s",
7161                             aopGet (left, offset, FALSE, TRUE),
7162                             aopGet (right, offset, FALSE, FALSE));
7163                 }
7164             }
7165           else
7166             {
7167               if (AOP_TYPE (left) == AOP_ACC)
7168                 {
7169                   if (offset)
7170                     emitcode("mov", "a,b");
7171                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7172                 }
7173               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7174                 {
7175                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7176                   MOVA (aopGet (right, offset, FALSE, FALSE));
7177                   emitcode ("xrl", "a,b");
7178                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7179                 }
7180               else if (aopGetUsesAcc (left, offset))
7181                 {
7182                   MOVA (aopGet (left, offset, FALSE, FALSE));
7183                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7184                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7185                 }
7186               else
7187                 {
7188                   MOVA (aopGet (right, offset, FALSE, FALSE));
7189                   if (IS_AOP_PREG (left))
7190                     {
7191                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7192                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7193                     }
7194                   else
7195                     emitcode ("xrl", "%s,a",
7196                               aopGet (left, offset, FALSE, TRUE));
7197                 }
7198             }
7199         }
7200     }
7201   else
7202     {
7203       // left & result in different registers
7204       if (AOP_TYPE (result) == AOP_CRY)
7205         {
7206           // result = bit
7207           // if(size), result in bit
7208           // if(!size && ifx), conditional oper: if(left ^ right)
7209           symbol *tlbl = newiTempLabel (NULL);
7210           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7211           if (size)
7212             emitcode ("setb", "c");
7213           while (sizer--)
7214             {
7215               if ((AOP_TYPE (right) == AOP_LIT) &&
7216                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7217                 {
7218                   MOVA (aopGet (left, offset, FALSE, FALSE));
7219                 }
7220               else
7221                 {
7222                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7223                     if (offset)
7224                       emitcode("mov", "a,b");
7225                     emitcode ("xrl", "a,%s",
7226                               aopGet (right, offset, FALSE, FALSE));
7227                   } else {
7228                     MOVA (aopGet (right, offset, FALSE, FALSE));
7229                     emitcode ("xrl", "a,%s",
7230                               aopGet (left, offset, FALSE, FALSE));
7231                   }
7232                 }
7233               emitcode ("jnz", "%05d$", tlbl->key + 100);
7234               offset++;
7235             }
7236           if (size)
7237             {
7238               CLRC;
7239               emitcode ("", "%05d$:", tlbl->key + 100);
7240               outBitC (result);
7241             }
7242           else if (ifx)
7243             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7244         }
7245       else
7246         {
7247           for (; (size--); offset++)
7248             {
7249               // normal case
7250               // result = left & right
7251               if (AOP_TYPE (right) == AOP_LIT)
7252                 {
7253                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7254                   if (bytelit == 0)
7255                     {
7256                       aopPut (result,
7257                               aopGet (left, offset, FALSE, FALSE),
7258                               offset,
7259                               isOperandVolatile (result, FALSE));
7260                       continue;
7261                     }
7262                 }
7263               // faster than result <- left, anl result,right
7264               // and better if result is SFR
7265               if (AOP_TYPE (left) == AOP_ACC)
7266                 {
7267                   if (offset)
7268                     emitcode("mov", "a,b");
7269                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7270                 }
7271               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7272                 {
7273                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE));
7274                   MOVA (aopGet (right, offset, FALSE, FALSE));
7275                   emitcode ("xrl", "a,b");
7276                 }
7277               else if (aopGetUsesAcc (left, offset))
7278                 {
7279                   MOVA (aopGet (left, offset, FALSE, FALSE));
7280                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7281                 }
7282               else
7283                 {
7284                   MOVA (aopGet (right, offset, FALSE, FALSE));
7285                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7286                 }
7287               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7288             }
7289         }
7290     }
7291
7292 release:
7293   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7294   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7295   freeAsmop (result, NULL, ic, TRUE);
7296 }
7297
7298 /*-----------------------------------------------------------------*/
7299 /* genInline - write the inline code out                           */
7300 /*-----------------------------------------------------------------*/
7301 static void
7302 genInline (iCode * ic)
7303 {
7304   char *buffer, *bp, *bp1;
7305
7306   D(emitcode (";     genInline",""));
7307
7308   _G.inLine += (!options.asmpeep);
7309
7310   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
7311   strcpy (buffer, IC_INLINE (ic));
7312
7313   /* emit each line as a code */
7314   while (*bp)
7315     {
7316       if (*bp == '\n')
7317         {
7318           *bp++ = '\0';
7319           emitcode (bp1, "");
7320           bp1 = bp;
7321         }
7322       else
7323         {
7324           /* Add \n for labels, not dirs such as c:\mydir */
7325           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7326             {
7327               bp++;
7328               *bp = '\0';
7329               bp++;
7330               emitcode (bp1, "");
7331               bp1 = bp;
7332             }
7333           else
7334             bp++;
7335         }
7336     }
7337   if (bp1 != bp)
7338     emitcode (bp1, "");
7339   /*     emitcode("",buffer); */
7340   _G.inLine -= (!options.asmpeep);
7341 }
7342
7343 /*-----------------------------------------------------------------*/
7344 /* genRRC - rotate right with carry                                */
7345 /*-----------------------------------------------------------------*/
7346 static void
7347 genRRC (iCode * ic)
7348 {
7349   operand *left, *result;
7350   int size, offset = 0;
7351   char *l;
7352
7353   D(emitcode (";     genRRC",""));
7354
7355   /* rotate right with carry */
7356   left = IC_LEFT (ic);
7357   result = IC_RESULT (ic);
7358   aopOp (left, ic, FALSE);
7359   aopOp (result, ic, FALSE);
7360
7361   /* move it to the result */
7362   size = AOP_SIZE (result);
7363   offset = size - 1;
7364   if (size == 1) { /* special case for 1 byte */
7365       l = aopGet (left, offset, FALSE, FALSE);
7366       MOVA (l);
7367       emitcode ("rr", "a");
7368       goto release;
7369   }
7370   /* no need to clear carry, bit7 will be written later */
7371   while (size--)
7372     {
7373       l = aopGet (left, offset, FALSE, FALSE);
7374       MOVA (l);
7375       emitcode ("rrc", "a");
7376       if (AOP_SIZE (result) > 1)
7377         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
7378     }
7379   /* now we need to put the carry into the
7380      highest order byte of the result */
7381   if (AOP_SIZE (result) > 1)
7382     {
7383       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7384       MOVA (l);
7385     }
7386   emitcode ("mov", "acc.7,c");
7387  release:
7388   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
7389   freeAsmop (left, NULL, ic, TRUE);
7390   freeAsmop (result, NULL, ic, TRUE);
7391 }
7392
7393 /*-----------------------------------------------------------------*/
7394 /* genRLC - generate code for rotate left with carry               */
7395 /*-----------------------------------------------------------------*/
7396 static void
7397 genRLC (iCode * ic)
7398 {
7399   operand *left, *result;
7400   int size, offset = 0;
7401   char *l;
7402
7403   D(emitcode (";     genRLC",""));
7404
7405   /* rotate right with carry */
7406   left = IC_LEFT (ic);
7407   result = IC_RESULT (ic);
7408   aopOp (left, ic, FALSE);
7409   aopOp (result, ic, FALSE);
7410
7411   /* move it to the result */
7412   size = AOP_SIZE (result);
7413   offset = 0;
7414   if (size--)
7415     {
7416       l = aopGet (left, offset, FALSE, FALSE);
7417       MOVA (l);
7418       if (size == 0) { /* special case for 1 byte */
7419               emitcode("rl","a");
7420               goto release;
7421       }
7422       emitcode("rlc","a"); /* bit0 will be written later */
7423       if (AOP_SIZE (result) > 1)
7424         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7425       while (size--)
7426         {
7427           l = aopGet (left, offset, FALSE, FALSE);
7428           MOVA (l);
7429           emitcode ("rlc", "a");
7430           if (AOP_SIZE (result) > 1)
7431             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7432         }
7433     }
7434   /* now we need to put the carry into the
7435      highest order byte of the result */
7436   if (AOP_SIZE (result) > 1)
7437     {
7438       l = aopGet (result, 0, FALSE, FALSE);
7439       MOVA (l);
7440     }
7441   emitcode ("mov", "acc.0,c");
7442  release:
7443   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7444   freeAsmop (left, NULL, ic, TRUE);
7445   freeAsmop (result, NULL, ic, TRUE);
7446 }
7447
7448 /*-----------------------------------------------------------------*/
7449 /* genGetHbit - generates code get highest order bit               */
7450 /*-----------------------------------------------------------------*/
7451 static void
7452 genGetHbit (iCode * ic)
7453 {
7454   operand *left, *result;
7455
7456   D(emitcode (";     genGetHbit",""));
7457
7458   left = IC_LEFT (ic);
7459   result = IC_RESULT (ic);
7460   aopOp (left, ic, FALSE);
7461   aopOp (result, ic, FALSE);
7462
7463   /* get the highest order byte into a */
7464   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7465   if (AOP_TYPE (result) == AOP_CRY)
7466     {
7467       emitcode ("rlc", "a");
7468       outBitC (result);
7469     }
7470   else
7471     {
7472       emitcode ("rl", "a");
7473       emitcode ("anl", "a,#0x01");
7474       outAcc (result);
7475     }
7476
7477
7478   freeAsmop (left, NULL, ic, TRUE);
7479   freeAsmop (result, NULL, ic, TRUE);
7480 }
7481
7482 /*-----------------------------------------------------------------*/
7483 /* genGetAbit - generates code get a single bit                    */
7484 /*-----------------------------------------------------------------*/
7485 static void
7486 genGetAbit (iCode * ic)
7487 {
7488   operand *left, *right, *result;
7489   int shCount;
7490
7491   D(emitcode (";     genGetAbit",""));
7492
7493   left = IC_LEFT (ic);
7494   right = IC_RIGHT (ic);
7495   result = IC_RESULT (ic);
7496   aopOp (left, ic, FALSE);
7497   aopOp (right, ic, FALSE);
7498   aopOp (result, ic, FALSE);
7499
7500   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7501
7502   /* get the needed byte into a */
7503   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7504   shCount %= 8;
7505   if (AOP_TYPE (result) == AOP_CRY)
7506     {
7507       if ((shCount) == 7)
7508           emitcode ("rlc", "a");
7509       else if ((shCount) == 0)
7510           emitcode ("rrc", "a");
7511       else
7512           emitcode ("mov", "c,acc[%d]", shCount);
7513       outBitC (result);
7514     }
7515   else
7516     {
7517       switch (shCount)
7518         {
7519         case 2:
7520           emitcode ("rr", "a");
7521           //fallthrough
7522         case 1:
7523           emitcode ("rr", "a");
7524           //fallthrough
7525         case 0:
7526           emitcode ("anl", "a,#0x01");
7527           break;
7528         case 3:
7529         case 5:
7530           emitcode ("mov", "c,acc[%d]", shCount);
7531           emitcode ("clr", "a");
7532           emitcode ("rlc", "a");
7533           break;
7534         case 4:
7535           emitcode ("swap", "a");
7536           emitcode ("anl", "a,#0x01");
7537           break;
7538         case 6:
7539           emitcode ("rl", "a");
7540           //fallthrough
7541         case 7:
7542           emitcode ("rl", "a");
7543           emitcode ("anl", "a,#0x01");
7544           break;
7545         }
7546       outAcc (result);
7547     }
7548
7549   freeAsmop (left, NULL, ic, TRUE);
7550   freeAsmop (right, NULL, ic, TRUE);
7551   freeAsmop (result, NULL, ic, TRUE);
7552 }
7553
7554 /*-----------------------------------------------------------------*/
7555 /* genGetByte - generates code get a single byte                   */
7556 /*-----------------------------------------------------------------*/
7557 static void
7558 genGetByte (iCode * ic)
7559 {
7560   operand *left, *right, *result;
7561   int offset;
7562
7563   D(emitcode (";     genGetByte",""));
7564
7565   left = IC_LEFT (ic);
7566   right = IC_RIGHT (ic);
7567   result = IC_RESULT (ic);
7568   aopOp (left, ic, FALSE);
7569   aopOp (right, ic, FALSE);
7570   aopOp (result, ic, FALSE);
7571
7572   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7573   aopPut (result,
7574           aopGet (left, offset, FALSE, FALSE),
7575           0,
7576           isOperandVolatile (result, FALSE));
7577
7578   freeAsmop (left, NULL, ic, TRUE);
7579   freeAsmop (right, NULL, ic, TRUE);
7580   freeAsmop (result, NULL, ic, TRUE);
7581 }
7582
7583 /*-----------------------------------------------------------------*/
7584 /* genGetWord - generates code get two bytes                       */
7585 /*-----------------------------------------------------------------*/
7586 static void
7587 genGetWord (iCode * ic)
7588 {
7589   operand *left, *right, *result;
7590   int offset;
7591
7592   D(emitcode (";     genGetWord",""));
7593
7594   left = IC_LEFT (ic);
7595   right = IC_RIGHT (ic);
7596   result = IC_RESULT (ic);
7597   aopOp (left, ic, FALSE);
7598   aopOp (right, ic, FALSE);
7599   aopOp (result, ic, FALSE);
7600
7601   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7602   aopPut (result,
7603           aopGet (left, offset, FALSE, FALSE),
7604           0,
7605           isOperandVolatile (result, FALSE));
7606   aopPut (result,
7607           aopGet (left, offset+1, FALSE, FALSE),
7608           1,
7609           isOperandVolatile (result, FALSE));
7610
7611   freeAsmop (left, NULL, ic, TRUE);
7612   freeAsmop (right, NULL, ic, TRUE);
7613   freeAsmop (result, NULL, ic, TRUE);
7614 }
7615
7616 /*-----------------------------------------------------------------*/
7617 /* genSwap - generates code to swap nibbles or bytes               */
7618 /*-----------------------------------------------------------------*/
7619 static void
7620 genSwap (iCode * ic)
7621 {
7622   operand *left, *result;
7623
7624   D(emitcode (";     genSwap",""));
7625
7626   left = IC_LEFT (ic);
7627   result = IC_RESULT (ic);
7628   aopOp (left, ic, FALSE);
7629   aopOp (result, ic, FALSE);
7630
7631   switch (AOP_SIZE (left))
7632     {
7633     case 1: /* swap nibbles in byte */
7634       MOVA (aopGet (left, 0, FALSE, FALSE));
7635       emitcode ("swap", "a");
7636       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7637       break;
7638     case 2: /* swap bytes in word */
7639       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7640         {
7641           MOVA (aopGet (left, 0, FALSE, FALSE));
7642           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7643                   0, isOperandVolatile (result, FALSE));
7644           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7645         }
7646       else if (operandsEqu (left, result))
7647         {
7648           char * reg = "a";
7649           bool pushedB = FALSE, leftInB = FALSE;
7650
7651           MOVA (aopGet (left, 0, FALSE, FALSE));
7652           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7653             {
7654               pushedB = pushB ();
7655               emitcode ("mov", "b,a");
7656               reg = "b";
7657               leftInB = TRUE;
7658             }
7659           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7660                   0, isOperandVolatile (result, FALSE));
7661           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7662
7663           if (leftInB)
7664             popB (pushedB);
7665         }
7666       else
7667         {
7668           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7669                   0, isOperandVolatile (result, FALSE));
7670           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7671                   1, isOperandVolatile (result, FALSE));
7672         }
7673       break;
7674     default:
7675       wassertl(FALSE, "unsupported SWAP operand size");
7676     }
7677
7678   freeAsmop (left, NULL, ic, TRUE);
7679   freeAsmop (result, NULL, ic, TRUE);
7680 }
7681
7682
7683 /*-----------------------------------------------------------------*/
7684 /* AccRol - rotate left accumulator by known count                 */
7685 /*-----------------------------------------------------------------*/
7686 static void
7687 AccRol (int shCount)
7688 {
7689   shCount &= 0x0007;            // shCount : 0..7
7690
7691   switch (shCount)
7692     {
7693     case 0:
7694       break;
7695     case 1:
7696       emitcode ("rl", "a");
7697       break;
7698     case 2:
7699       emitcode ("rl", "a");
7700       emitcode ("rl", "a");
7701       break;
7702     case 3:
7703       emitcode ("swap", "a");
7704       emitcode ("rr", "a");
7705       break;
7706     case 4:
7707       emitcode ("swap", "a");
7708       break;
7709     case 5:
7710       emitcode ("swap", "a");
7711       emitcode ("rl", "a");
7712       break;
7713     case 6:
7714       emitcode ("rr", "a");
7715       emitcode ("rr", "a");
7716       break;
7717     case 7:
7718       emitcode ("rr", "a");
7719       break;
7720     }
7721 }
7722
7723 /*-----------------------------------------------------------------*/
7724 /* AccLsh - left shift accumulator by known count                  */
7725 /*-----------------------------------------------------------------*/
7726 static void
7727 AccLsh (int shCount)
7728 {
7729   if (shCount != 0)
7730     {
7731       if (shCount == 1)
7732         emitcode ("add", "a,acc");
7733       else if (shCount == 2)
7734         {
7735           emitcode ("add", "a,acc");
7736           emitcode ("add", "a,acc");
7737         }
7738       else
7739         {
7740           /* rotate left accumulator */
7741           AccRol (shCount);
7742           /* and kill the lower order bits */
7743           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7744         }
7745     }
7746 }
7747
7748 /*-----------------------------------------------------------------*/
7749 /* AccRsh - right shift accumulator by known count                 */
7750 /*-----------------------------------------------------------------*/
7751 static void
7752 AccRsh (int shCount)
7753 {
7754   if (shCount != 0)
7755     {
7756       if (shCount == 1)
7757         {
7758           CLRC;
7759           emitcode ("rrc", "a");
7760         }
7761       else
7762         {
7763           /* rotate right accumulator */
7764           AccRol (8 - shCount);
7765           /* and kill the higher order bits */
7766           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7767         }
7768     }
7769 }
7770
7771 /*-----------------------------------------------------------------*/
7772 /* AccSRsh - signed right shift accumulator by known count                 */
7773 /*-----------------------------------------------------------------*/
7774 static void
7775 AccSRsh (int shCount)
7776 {
7777   symbol *tlbl;
7778   if (shCount != 0)
7779     {
7780       if (shCount == 1)
7781         {
7782           emitcode ("mov", "c,acc.7");
7783           emitcode ("rrc", "a");
7784         }
7785       else if (shCount == 2)
7786         {
7787           emitcode ("mov", "c,acc.7");
7788           emitcode ("rrc", "a");
7789           emitcode ("mov", "c,acc.7");
7790           emitcode ("rrc", "a");
7791         }
7792       else
7793         {
7794           tlbl = newiTempLabel (NULL);
7795           /* rotate right accumulator */
7796           AccRol (8 - shCount);
7797           /* and kill the higher order bits */
7798           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7799           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7800           emitcode ("orl", "a,#0x%02x",
7801                     (unsigned char) ~SRMask[shCount]);
7802           emitcode ("", "%05d$:", tlbl->key + 100);
7803         }
7804     }
7805 }
7806
7807 /*-----------------------------------------------------------------*/
7808 /* shiftR1Left2Result - shift right one byte from left to result   */
7809 /*-----------------------------------------------------------------*/
7810 static void
7811 shiftR1Left2Result (operand * left, int offl,
7812                     operand * result, int offr,
7813                     int shCount, int sign)
7814 {
7815   MOVA (aopGet (left, offl, FALSE, FALSE));
7816   /* shift right accumulator */
7817   if (sign)
7818     AccSRsh (shCount);
7819   else
7820     AccRsh (shCount);
7821   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7822 }
7823
7824 /*-----------------------------------------------------------------*/
7825 /* shiftL1Left2Result - shift left one byte from left to result    */
7826 /*-----------------------------------------------------------------*/
7827 static void
7828 shiftL1Left2Result (operand * left, int offl,
7829                     operand * result, int offr, int shCount)
7830 {
7831   char *l;
7832   l = aopGet (left, offl, FALSE, FALSE);
7833   MOVA (l);
7834   /* shift left accumulator */
7835   AccLsh (shCount);
7836   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7837 }
7838
7839 /*-----------------------------------------------------------------*/
7840 /* movLeft2Result - move byte from left to result                  */
7841 /*-----------------------------------------------------------------*/
7842 static void
7843 movLeft2Result (operand * left, int offl,
7844                 operand * result, int offr, int sign)
7845 {
7846   char *l;
7847   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7848     {
7849       l = aopGet (left, offl, FALSE, FALSE);
7850
7851       if (*l == '@' && (IS_AOP_PREG (result)))
7852         {
7853           emitcode ("mov", "a,%s", l);
7854           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7855         }
7856       else
7857         {
7858           if (!sign)
7859             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7860           else
7861             {
7862               /* MSB sign in acc.7 ! */
7863               if (getDataSize (left) == offl + 1)
7864                 {
7865                   MOVA (l);
7866                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7867                 }
7868             }
7869         }
7870     }
7871 }
7872
7873 /*-----------------------------------------------------------------*/
7874 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7875 /*-----------------------------------------------------------------*/
7876 static void
7877 AccAXRrl1 (char *x)
7878 {
7879   emitcode ("rrc", "a");
7880   emitcode ("xch", "a,%s", x);
7881   emitcode ("rrc", "a");
7882   emitcode ("xch", "a,%s", x);
7883 }
7884
7885 /*-----------------------------------------------------------------*/
7886 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7887 /*-----------------------------------------------------------------*/
7888 static void
7889 AccAXLrl1 (char *x)
7890 {
7891   emitcode ("xch", "a,%s", x);
7892   emitcode ("rlc", "a");
7893   emitcode ("xch", "a,%s", x);
7894   emitcode ("rlc", "a");
7895 }
7896
7897 /*-----------------------------------------------------------------*/
7898 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7899 /*-----------------------------------------------------------------*/
7900 static void
7901 AccAXLsh1 (char *x)
7902 {
7903   emitcode ("xch", "a,%s", x);
7904   emitcode ("add", "a,acc");
7905   emitcode ("xch", "a,%s", x);
7906   emitcode ("rlc", "a");
7907 }
7908
7909 /*-----------------------------------------------------------------*/
7910 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7911 /*-----------------------------------------------------------------*/
7912 static void
7913 AccAXLsh (char *x, int shCount)
7914 {
7915   switch (shCount)
7916     {
7917     case 0:
7918       break;
7919     case 1:
7920       AccAXLsh1 (x);
7921       break;
7922     case 2:
7923       AccAXLsh1 (x);
7924       AccAXLsh1 (x);
7925       break;
7926     case 3:
7927     case 4:
7928     case 5:                     // AAAAABBB:CCCCCDDD
7929
7930       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7931
7932       emitcode ("anl", "a,#0x%02x",
7933                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7934
7935       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7936
7937       AccRol (shCount);         // DDDCCCCC:BBB00000
7938
7939       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7940
7941       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7942
7943       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7944
7945       emitcode ("anl", "a,#0x%02x",
7946                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7947
7948       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7949
7950       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7951
7952       break;
7953     case 6:                     // AAAAAABB:CCCCCCDD
7954       emitcode ("anl", "a,#0x%02x",
7955                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7956       emitcode ("mov", "c,acc.0");      // c = B
7957       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7958 #if 0 // REMOVE ME
7959       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7960       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7961 #else
7962       emitcode("rrc","a");
7963       emitcode("xch","a,%s", x);
7964       emitcode("rrc","a");
7965       emitcode("mov","c,acc.0"); //<< get correct bit
7966       emitcode("xch","a,%s", x);
7967
7968       emitcode("rrc","a");
7969       emitcode("xch","a,%s", x);
7970       emitcode("rrc","a");
7971       emitcode("xch","a,%s", x);
7972 #endif
7973       break;
7974     case 7:                     // a:x <<= 7
7975
7976       emitcode ("anl", "a,#0x%02x",
7977                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7978
7979       emitcode ("mov", "c,acc.0");      // c = B
7980
7981       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7982
7983       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7984
7985       break;
7986     default:
7987       break;
7988     }
7989 }
7990
7991 /*-----------------------------------------------------------------*/
7992 /* AccAXRsh - right shift a:x known count (0..7)                   */
7993 /*-----------------------------------------------------------------*/
7994 static void
7995 AccAXRsh (char *x, int shCount)
7996 {
7997   switch (shCount)
7998     {
7999     case 0:
8000       break;
8001     case 1:
8002       CLRC;
8003       AccAXRrl1 (x);            // 0->a:x
8004
8005       break;
8006     case 2:
8007       CLRC;
8008       AccAXRrl1 (x);            // 0->a:x
8009
8010       CLRC;
8011       AccAXRrl1 (x);            // 0->a:x
8012
8013       break;
8014     case 3:
8015     case 4:
8016     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8017
8018       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8019
8020       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8021
8022       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8023
8024       emitcode ("anl", "a,#0x%02x",
8025                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8026
8027       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8028
8029       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8030
8031       emitcode ("anl", "a,#0x%02x",
8032                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8033
8034       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8035
8036       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8037
8038       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8039
8040       break;
8041     case 6:                     // AABBBBBB:CCDDDDDD
8042
8043       emitcode ("mov", "c,acc.7");
8044       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8045
8046       emitcode ("mov", "c,acc.7");
8047       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8048
8049       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8050
8051       emitcode ("anl", "a,#0x%02x",
8052                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8053
8054       break;
8055     case 7:                     // ABBBBBBB:CDDDDDDD
8056
8057       emitcode ("mov", "c,acc.7");      // c = A
8058
8059       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8060
8061       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8062
8063       emitcode ("anl", "a,#0x%02x",
8064                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8065
8066       break;
8067     default:
8068       break;
8069     }
8070 }
8071
8072 /*-----------------------------------------------------------------*/
8073 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8074 /*-----------------------------------------------------------------*/
8075 static void
8076 AccAXRshS (char *x, int shCount)
8077 {
8078   symbol *tlbl;
8079   switch (shCount)
8080     {
8081     case 0:
8082       break;
8083     case 1:
8084       emitcode ("mov", "c,acc.7");
8085       AccAXRrl1 (x);            // s->a:x
8086
8087       break;
8088     case 2:
8089       emitcode ("mov", "c,acc.7");
8090       AccAXRrl1 (x);            // s->a:x
8091
8092       emitcode ("mov", "c,acc.7");
8093       AccAXRrl1 (x);            // s->a:x
8094
8095       break;
8096     case 3:
8097     case 4:
8098     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8099
8100       tlbl = newiTempLabel (NULL);
8101       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8102
8103       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8104
8105       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8106
8107       emitcode ("anl", "a,#0x%02x",
8108                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8109
8110       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8111
8112       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8113
8114       emitcode ("anl", "a,#0x%02x",
8115                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8116
8117       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8118
8119       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8120
8121       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8122
8123       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8124       emitcode ("orl", "a,#0x%02x",
8125                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8126
8127       emitcode ("", "%05d$:", tlbl->key + 100);
8128       break;                    // SSSSAAAA:BBBCCCCC
8129
8130     case 6:                     // AABBBBBB:CCDDDDDD
8131
8132       tlbl = newiTempLabel (NULL);
8133       emitcode ("mov", "c,acc.7");
8134       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8135
8136       emitcode ("mov", "c,acc.7");
8137       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8138
8139       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8140
8141       emitcode ("anl", "a,#0x%02x",
8142                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8143
8144       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8145       emitcode ("orl", "a,#0x%02x",
8146                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8147
8148       emitcode ("", "%05d$:", tlbl->key + 100);
8149       break;
8150     case 7:                     // ABBBBBBB:CDDDDDDD
8151
8152       tlbl = newiTempLabel (NULL);
8153       emitcode ("mov", "c,acc.7");      // c = A
8154
8155       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8156
8157       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8158
8159       emitcode ("anl", "a,#0x%02x",
8160                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8161
8162       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8163       emitcode ("orl", "a,#0x%02x",
8164                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8165
8166       emitcode ("", "%05d$:", tlbl->key + 100);
8167       break;
8168     default:
8169       break;
8170     }
8171 }
8172
8173 /*-----------------------------------------------------------------*/
8174 /* shiftL2Left2Result - shift left two bytes from left to result   */
8175 /*-----------------------------------------------------------------*/
8176 static void
8177 shiftL2Left2Result (operand * left, int offl,
8178                     operand * result, int offr, int shCount)
8179 {
8180   char * x;
8181   bool pushedB = FALSE;
8182   bool usedB = FALSE;
8183
8184   if (sameRegs (AOP (result), AOP (left)) &&
8185       ((offl + MSB16) == offr))
8186     {
8187       /* don't crash result[offr] */
8188       MOVA (aopGet (left, offl, FALSE, FALSE));
8189       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8190       x = aopGet (result, offr, FALSE, FALSE);
8191     }
8192   else if (aopGetUsesAcc (result, offr))
8193     {
8194       movLeft2Result (left, offl, result, offr, 0);
8195       pushedB = pushB ();
8196       usedB = TRUE;
8197       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8198       MOVA (aopGet (result, offr, FALSE, FALSE));
8199       emitcode ("xch", "a,b");
8200       x = "b";
8201     }
8202   else
8203     {
8204       movLeft2Result (left, offl, result, offr, 0);
8205       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8206       x = aopGet (result, offr, FALSE, FALSE);
8207     }
8208   /* ax << shCount (x = lsb(result)) */
8209   AccAXLsh (x, shCount);
8210   if (usedB)
8211     {
8212       emitcode ("xch", "a,b");
8213       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8214       aopPut (result, "b", offr + MSB16, isOperandVolatile (result, FALSE));
8215       popB (pushedB);
8216     }
8217   else
8218     {
8219       aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8220     }
8221 }
8222
8223
8224 /*-----------------------------------------------------------------*/
8225 /* shiftR2Left2Result - shift right two bytes from left to result  */
8226 /*-----------------------------------------------------------------*/
8227 static void
8228 shiftR2Left2Result (operand * left, int offl,
8229                     operand * result, int offr,
8230                     int shCount, int sign)
8231 {
8232   char * x;
8233   bool pushedB = FALSE;
8234   bool usedB = FALSE;
8235
8236   if (sameRegs (AOP (result), AOP (left)) &&
8237       ((offl + MSB16) == offr))
8238     {
8239       /* don't crash result[offr] */
8240       MOVA (aopGet (left, offl, FALSE, FALSE));
8241       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8242       x = aopGet (result, offr, FALSE, FALSE);
8243     }
8244   else if (aopGetUsesAcc (result, offr))
8245     {
8246       movLeft2Result (left, offl, result, offr, 0);
8247       pushedB = pushB ();
8248       usedB = TRUE;
8249       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8250       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8251       x = "b";
8252     }
8253   else
8254     {
8255       movLeft2Result (left, offl, result, offr, 0);
8256       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8257       x = aopGet (result, offr, FALSE, FALSE);
8258     }
8259   /* a:x >> shCount (x = lsb(result)) */
8260   if (sign)
8261     AccAXRshS (x, shCount);
8262   else
8263     AccAXRsh (x, shCount);
8264   if (usedB)
8265     {
8266       emitcode ("xch", "a,b");
8267       aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8268       emitcode ("xch", "a,b");
8269       popB (pushedB);
8270     }
8271   if (getDataSize (result) > 1)
8272     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8273 }
8274
8275 /*-----------------------------------------------------------------*/
8276 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8277 /*-----------------------------------------------------------------*/
8278 static void
8279 shiftLLeftOrResult (operand * left, int offl,
8280                     operand * result, int offr, int shCount)
8281 {
8282   MOVA (aopGet (left, offl, FALSE, FALSE));
8283   /* shift left accumulator */
8284   AccLsh (shCount);
8285   /* or with result */
8286   if (aopGetUsesAcc (result, offr))
8287     {
8288       emitcode ("xch", "a,b");
8289       MOVA (aopGet (result, offr, FALSE, FALSE));
8290       emitcode ("orl", "a,b");
8291     }
8292   else
8293     {
8294       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8295     }
8296   /* back to result */
8297   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8298 }
8299
8300 /*-----------------------------------------------------------------*/
8301 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8302 /*-----------------------------------------------------------------*/
8303 static void
8304 shiftRLeftOrResult (operand * left, int offl,
8305                     operand * result, int offr, int shCount)
8306 {
8307   MOVA (aopGet (left, offl, FALSE, FALSE));
8308   /* shift right accumulator */
8309   AccRsh (shCount);
8310   /* or with result */
8311   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8312   /* back to result */
8313   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8314 }
8315
8316 /*-----------------------------------------------------------------*/
8317 /* genlshOne - left shift a one byte quantity by known count       */
8318 /*-----------------------------------------------------------------*/
8319 static void
8320 genlshOne (operand * result, operand * left, int shCount)
8321 {
8322   D(emitcode (";     genlshOne",""));
8323
8324   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8325 }
8326
8327 /*-----------------------------------------------------------------*/
8328 /* genlshTwo - left shift two bytes by known amount != 0           */
8329 /*-----------------------------------------------------------------*/
8330 static void
8331 genlshTwo (operand * result, operand * left, int shCount)
8332 {
8333   int size;
8334
8335   D(emitcode (";     genlshTwo",""));
8336
8337   size = getDataSize (result);
8338
8339   /* if shCount >= 8 */
8340   if (shCount >= 8)
8341     {
8342       shCount -= 8;
8343
8344       if (size > 1)
8345         {
8346           if (shCount)
8347             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8348           else
8349             movLeft2Result (left, LSB, result, MSB16, 0);
8350         }
8351       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8352     }
8353
8354   /*  1 <= shCount <= 7 */
8355   else
8356     {
8357       if (size == 1)
8358         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8359       else
8360         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8361     }
8362 }
8363
8364 /*-----------------------------------------------------------------*/
8365 /* shiftLLong - shift left one long from left to result            */
8366 /* offl = LSB or MSB16                                             */
8367 /*-----------------------------------------------------------------*/
8368 static void
8369 shiftLLong (operand * left, operand * result, int offr)
8370 {
8371   char *l;
8372   int size = AOP_SIZE (result);
8373
8374   if (size >= LSB + offr)
8375     {
8376       l = aopGet (left, LSB, FALSE, FALSE);
8377       MOVA (l);
8378       emitcode ("add", "a,acc");
8379       if (sameRegs (AOP (left), AOP (result)) &&
8380           size >= MSB16 + offr && offr != LSB)
8381         emitcode ("xch", "a,%s",
8382                   aopGet (left, LSB + offr, FALSE, FALSE));
8383       else
8384         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
8385     }
8386
8387   if (size >= MSB16 + offr)
8388     {
8389       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8390         {
8391           l = aopGet (left, MSB16, FALSE, FALSE);
8392           MOVA (l);
8393         }
8394       emitcode ("rlc", "a");
8395       if (sameRegs (AOP (left), AOP (result)) &&
8396           size >= MSB24 + offr && offr != LSB)
8397         emitcode ("xch", "a,%s",
8398                   aopGet (left, MSB16 + offr, FALSE, FALSE));
8399       else
8400         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
8401     }
8402
8403   if (size >= MSB24 + offr)
8404     {
8405       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8406         {
8407           l = aopGet (left, MSB24, FALSE, FALSE);
8408           MOVA (l);
8409         }
8410       emitcode ("rlc", "a");
8411       if (sameRegs (AOP (left), AOP (result)) &&
8412           size >= MSB32 + offr && offr != LSB)
8413         emitcode ("xch", "a,%s",
8414                   aopGet (left, MSB24 + offr, FALSE, FALSE));
8415       else
8416         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
8417     }
8418
8419   if (size > MSB32 + offr)
8420     {
8421       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8422         {
8423           l = aopGet (left, MSB32, FALSE, FALSE);
8424           MOVA (l);
8425         }
8426       emitcode ("rlc", "a");
8427       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
8428     }
8429   if (offr != LSB)
8430     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8431 }
8432
8433 /*-----------------------------------------------------------------*/
8434 /* genlshFour - shift four byte by a known amount != 0             */
8435 /*-----------------------------------------------------------------*/
8436 static void
8437 genlshFour (operand * result, operand * left, int shCount)
8438 {
8439   int size;
8440
8441   D(emitcode (";     genlshFour",""));
8442
8443   size = AOP_SIZE (result);
8444
8445   /* if shifting more that 3 bytes */
8446   if (shCount >= 24)
8447     {
8448       shCount -= 24;
8449       if (shCount)
8450         /* lowest order of left goes to the highest
8451            order of the destination */
8452         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8453       else
8454         movLeft2Result (left, LSB, result, MSB32, 0);
8455       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8456       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8457       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
8458       return;
8459     }
8460
8461   /* more than two bytes */
8462   else if (shCount >= 16)
8463     {
8464       /* lower order two bytes goes to higher order two bytes */
8465       shCount -= 16;
8466       /* if some more remaining */
8467       if (shCount)
8468         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8469       else
8470         {
8471           movLeft2Result (left, MSB16, result, MSB32, 0);
8472           movLeft2Result (left, LSB, result, MSB24, 0);
8473         }
8474       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8475       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8476       return;
8477     }
8478
8479   /* if more than 1 byte */
8480   else if (shCount >= 8)
8481     {
8482       /* lower order three bytes goes to higher order  three bytes */
8483       shCount -= 8;
8484       if (size == 2)
8485         {
8486           if (shCount)
8487             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8488           else
8489             movLeft2Result (left, LSB, result, MSB16, 0);
8490         }
8491       else
8492         {                       /* size = 4 */
8493           if (shCount == 0)
8494             {
8495               movLeft2Result (left, MSB24, result, MSB32, 0);
8496               movLeft2Result (left, MSB16, result, MSB24, 0);
8497               movLeft2Result (left, LSB, result, MSB16, 0);
8498               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8499             }
8500           else if (shCount == 1)
8501             shiftLLong (left, result, MSB16);
8502           else
8503             {
8504               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8505               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8506               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8507               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8508             }
8509         }
8510     }
8511
8512   /* 1 <= shCount <= 7 */
8513   else if (shCount <= 2)
8514     {
8515       shiftLLong (left, result, LSB);
8516       if (shCount == 2)
8517         shiftLLong (result, result, LSB);
8518     }
8519   /* 3 <= shCount <= 7, optimize */
8520   else
8521     {
8522       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8523       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8524       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8525     }
8526 }
8527
8528 /*-----------------------------------------------------------------*/
8529 /* genLeftShiftLiteral - left shifting by known count              */
8530 /*-----------------------------------------------------------------*/
8531 static void
8532 genLeftShiftLiteral (operand * left,
8533                      operand * right,
8534                      operand * result,
8535                      iCode * ic)
8536 {
8537   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8538   int size;
8539
8540   D(emitcode (";     genLeftShiftLiteral",""));
8541
8542   freeAsmop (right, NULL, ic, TRUE);
8543
8544   aopOp (left, ic, FALSE);
8545   aopOp (result, ic, FALSE);
8546
8547   size = getSize (operandType (result));
8548
8549 #if VIEW_SIZE
8550   emitcode ("; shift left ", "result %d, left %d", size,
8551             AOP_SIZE (left));
8552 #endif
8553
8554   /* I suppose that the left size >= result size */
8555   if (shCount == 0)
8556     {
8557       while (size--)
8558         {
8559           movLeft2Result (left, size, result, size, 0);
8560         }
8561     }
8562
8563   else if (shCount >= (size * 8))
8564     while (size--)
8565       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
8566   else
8567     {
8568       switch (size)
8569         {
8570         case 1:
8571           genlshOne (result, left, shCount);
8572           break;
8573
8574         case 2:
8575           genlshTwo (result, left, shCount);
8576           break;
8577
8578         case 4:
8579           genlshFour (result, left, shCount);
8580           break;
8581         default:
8582           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8583                   "*** ack! mystery literal shift!\n");
8584           break;
8585         }
8586     }
8587   freeAsmop (left, NULL, ic, TRUE);
8588   freeAsmop (result, NULL, ic, TRUE);
8589 }
8590
8591 /*-----------------------------------------------------------------*/
8592 /* genLeftShift - generates code for left shifting                 */
8593 /*-----------------------------------------------------------------*/
8594 static void
8595 genLeftShift (iCode * ic)
8596 {
8597   operand *left, *right, *result;
8598   int size, offset;
8599   char *l;
8600   symbol *tlbl, *tlbl1;
8601   bool pushedB;
8602
8603   D(emitcode (";     genLeftShift",""));
8604
8605   right = IC_RIGHT (ic);
8606   left = IC_LEFT (ic);
8607   result = IC_RESULT (ic);
8608
8609   aopOp (right, ic, FALSE);
8610
8611   /* if the shift count is known then do it
8612      as efficiently as possible */
8613   if (AOP_TYPE (right) == AOP_LIT)
8614     {
8615       genLeftShiftLiteral (left, right, result, ic);
8616       return;
8617     }
8618
8619   /* shift count is unknown then we have to form
8620      a loop get the loop count in B : Note: we take
8621      only the lower order byte since shifting
8622      more that 32 bits make no sense anyway, ( the
8623      largest size of an object can be only 32 bits ) */
8624
8625   pushedB = pushB ();
8626   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8627   emitcode ("inc", "b");
8628   freeAsmop (right, NULL, ic, TRUE);
8629   aopOp (left, ic, FALSE);
8630   aopOp (result, ic, FALSE);
8631
8632   /* now move the left to the result if they are not the same */
8633   if (!sameRegs (AOP (left), AOP (result)) &&
8634       AOP_SIZE (result) > 1)
8635     {
8636
8637       size = AOP_SIZE (result);
8638       offset = 0;
8639       while (size--)
8640         {
8641           l = aopGet (left, offset, FALSE, TRUE);
8642           if (*l == '@' && (IS_AOP_PREG (result)))
8643             {
8644
8645               emitcode ("mov", "a,%s", l);
8646               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8647             }
8648           else
8649             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8650           offset++;
8651         }
8652     }
8653
8654   tlbl = newiTempLabel (NULL);
8655   size = AOP_SIZE (result);
8656   offset = 0;
8657   tlbl1 = newiTempLabel (NULL);
8658
8659   /* if it is only one byte then */
8660   if (size == 1)
8661     {
8662       symbol *tlbl1 = newiTempLabel (NULL);
8663
8664       l = aopGet (left, 0, FALSE, FALSE);
8665       MOVA (l);
8666       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8667       emitcode ("", "%05d$:", tlbl->key + 100);
8668       emitcode ("add", "a,acc");
8669       emitcode ("", "%05d$:", tlbl1->key + 100);
8670       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8671       popB (pushedB);
8672       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8673       goto release;
8674     }
8675
8676   reAdjustPreg (AOP (result));
8677
8678   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8679   emitcode ("", "%05d$:", tlbl->key + 100);
8680   l = aopGet (result, offset, FALSE, FALSE);
8681   MOVA (l);
8682   emitcode ("add", "a,acc");
8683   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8684   while (--size)
8685     {
8686       l = aopGet (result, offset, FALSE, FALSE);
8687       MOVA (l);
8688       emitcode ("rlc", "a");
8689       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8690     }
8691   reAdjustPreg (AOP (result));
8692
8693   emitcode ("", "%05d$:", tlbl1->key + 100);
8694   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8695   popB (pushedB);
8696 release:
8697   freeAsmop (left, NULL, ic, TRUE);
8698   freeAsmop (result, NULL, ic, TRUE);
8699 }
8700
8701 /*-----------------------------------------------------------------*/
8702 /* genrshOne - right shift a one byte quantity by known count      */
8703 /*-----------------------------------------------------------------*/
8704 static void
8705 genrshOne (operand * result, operand * left,
8706            int shCount, int sign)
8707 {
8708   D(emitcode (";     genrshOne",""));
8709
8710   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8711 }
8712
8713 /*-----------------------------------------------------------------*/
8714 /* genrshTwo - right shift two bytes by known amount != 0          */
8715 /*-----------------------------------------------------------------*/
8716 static void
8717 genrshTwo (operand * result, operand * left,
8718            int shCount, int sign)
8719 {
8720   D(emitcode (";     genrshTwo",""));
8721
8722   /* if shCount >= 8 */
8723   if (shCount >= 8)
8724     {
8725       shCount -= 8;
8726       if (shCount)
8727         shiftR1Left2Result (left, MSB16, result, LSB,
8728                             shCount, sign);
8729       else
8730         movLeft2Result (left, MSB16, result, LSB, sign);
8731       addSign (result, MSB16, sign);
8732     }
8733
8734   /*  1 <= shCount <= 7 */
8735   else
8736     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8737 }
8738
8739 /*-----------------------------------------------------------------*/
8740 /* shiftRLong - shift right one long from left to result           */
8741 /* offl = LSB or MSB16                                             */
8742 /*-----------------------------------------------------------------*/
8743 static void
8744 shiftRLong (operand * left, int offl,
8745             operand * result, int sign)
8746 {
8747   int isSameRegs = sameRegs (AOP (left), AOP (result));
8748
8749   if (isSameRegs && offl>1) {
8750     // we are in big trouble, but this shouldn't happen
8751     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8752   }
8753
8754   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8755
8756   if (offl==MSB16) {
8757     // shift is > 8
8758     if (sign) {
8759       emitcode ("rlc", "a");
8760       emitcode ("subb", "a,acc");
8761       if (isSameRegs)
8762         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8763       else {
8764         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8765         MOVA (aopGet (left, MSB32, FALSE, FALSE));
8766       }
8767     } else {
8768       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8769     }
8770   }
8771
8772   if (!sign) {
8773     emitcode ("clr", "c");
8774   } else {
8775     emitcode ("mov", "c,acc.7");
8776   }
8777
8778   emitcode ("rrc", "a");
8779
8780   if (isSameRegs && offl==MSB16) {
8781     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8782   } else {
8783     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8784     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8785   }
8786
8787   emitcode ("rrc", "a");
8788   if (isSameRegs && offl==1) {
8789     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8790   } else {
8791     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8792     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8793   }
8794   emitcode ("rrc", "a");
8795   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8796
8797   if (offl == LSB)
8798     {
8799       MOVA (aopGet (left, LSB, FALSE, FALSE));
8800       emitcode ("rrc", "a");
8801       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8802     }
8803 }
8804
8805 /*-----------------------------------------------------------------*/
8806 /* genrshFour - shift four byte by a known amount != 0             */
8807 /*-----------------------------------------------------------------*/
8808 static void
8809 genrshFour (operand * result, operand * left,
8810             int shCount, int sign)
8811 {
8812   D(emitcode (";     genrshFour",""));
8813
8814   /* if shifting more that 3 bytes */
8815   if (shCount >= 24)
8816     {
8817       shCount -= 24;
8818       if (shCount)
8819         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8820       else
8821         movLeft2Result (left, MSB32, result, LSB, sign);
8822       addSign (result, MSB16, sign);
8823     }
8824   else if (shCount >= 16)
8825     {
8826       shCount -= 16;
8827       if (shCount)
8828         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8829       else
8830         {
8831           movLeft2Result (left, MSB24, result, LSB, 0);
8832           movLeft2Result (left, MSB32, result, MSB16, sign);
8833         }
8834       addSign (result, MSB24, sign);
8835     }
8836   else if (shCount >= 8)
8837     {
8838       shCount -= 8;
8839       if (shCount == 1)
8840         shiftRLong (left, MSB16, result, sign);
8841       else if (shCount == 0)
8842         {
8843           movLeft2Result (left, MSB16, result, LSB, 0);
8844           movLeft2Result (left, MSB24, result, MSB16, 0);
8845           movLeft2Result (left, MSB32, result, MSB24, sign);
8846           addSign (result, MSB32, sign);
8847         }
8848       else
8849         {
8850           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8851           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8852           /* the last shift is signed */
8853           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8854           addSign (result, MSB32, sign);
8855         }
8856     }
8857   else
8858     {                           /* 1 <= shCount <= 7 */
8859       if (shCount <= 2)
8860         {
8861           shiftRLong (left, LSB, result, sign);
8862           if (shCount == 2)
8863             shiftRLong (result, LSB, result, sign);
8864         }
8865       else
8866         {
8867           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8868           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8869           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8870         }
8871     }
8872 }
8873
8874 /*-----------------------------------------------------------------*/
8875 /* genRightShiftLiteral - right shifting by known count            */
8876 /*-----------------------------------------------------------------*/
8877 static void
8878 genRightShiftLiteral (operand * left,
8879                       operand * right,
8880                       operand * result,
8881                       iCode * ic,
8882                       int sign)
8883 {
8884   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8885   int size;
8886
8887   D(emitcode (";     genRightShiftLiteral",""));
8888
8889   freeAsmop (right, NULL, ic, TRUE);
8890
8891   aopOp (left, ic, FALSE);
8892   aopOp (result, ic, FALSE);
8893
8894 #if VIEW_SIZE
8895   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8896             AOP_SIZE (left));
8897 #endif
8898
8899   size = getDataSize (left);
8900   /* test the LEFT size !!! */
8901
8902   /* I suppose that the left size >= result size */
8903   if (shCount == 0)
8904     {
8905       size = getDataSize (result);
8906       while (size--)
8907         movLeft2Result (left, size, result, size, 0);
8908     }
8909
8910   else if (shCount >= (size * 8))
8911     {
8912       if (sign) {
8913         /* get sign in acc.7 */
8914         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8915       }
8916       addSign (result, LSB, sign);
8917     }
8918   else
8919     {
8920       switch (size)
8921         {
8922         case 1:
8923           genrshOne (result, left, shCount, sign);
8924           break;
8925
8926         case 2:
8927           genrshTwo (result, left, shCount, sign);
8928           break;
8929
8930         case 4:
8931           genrshFour (result, left, shCount, sign);
8932           break;
8933         default:
8934           break;
8935         }
8936     }
8937   freeAsmop (left, NULL, ic, TRUE);
8938   freeAsmop (result, NULL, ic, TRUE);
8939 }
8940
8941 /*-----------------------------------------------------------------*/
8942 /* genSignedRightShift - right shift of signed number              */
8943 /*-----------------------------------------------------------------*/
8944 static void
8945 genSignedRightShift (iCode * ic)
8946 {
8947   operand *right, *left, *result;
8948   int size, offset;
8949   char *l;
8950   symbol *tlbl, *tlbl1;
8951   bool pushedB;
8952
8953   D(emitcode (";     genSignedRightShift",""));
8954
8955   /* we do it the hard way put the shift count in b
8956      and loop thru preserving the sign */
8957
8958   right = IC_RIGHT (ic);
8959   left = IC_LEFT (ic);
8960   result = IC_RESULT (ic);
8961
8962   aopOp (right, ic, FALSE);
8963
8964
8965   if (AOP_TYPE (right) == AOP_LIT)
8966     {
8967       genRightShiftLiteral (left, right, result, ic, 1);
8968       return;
8969     }
8970   /* shift count is unknown then we have to form
8971      a loop get the loop count in B : Note: we take
8972      only the lower order byte since shifting
8973      more that 32 bits make no sense anyway, ( the
8974      largest size of an object can be only 32 bits ) */
8975
8976   pushedB = pushB ();
8977   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8978   emitcode ("inc", "b");
8979   freeAsmop (right, NULL, ic, TRUE);
8980   aopOp (left, ic, FALSE);
8981   aopOp (result, ic, FALSE);
8982
8983   /* now move the left to the result if they are not the
8984      same */
8985   if (!sameRegs (AOP (left), AOP (result)) &&
8986       AOP_SIZE (result) > 1)
8987     {
8988
8989       size = AOP_SIZE (result);
8990       offset = 0;
8991       while (size--)
8992         {
8993           l = aopGet (left, offset, FALSE, TRUE);
8994           if (*l == '@' && IS_AOP_PREG (result))
8995             {
8996
8997               emitcode ("mov", "a,%s", l);
8998               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8999             }
9000           else
9001             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
9002           offset++;
9003         }
9004     }
9005
9006   /* mov the highest order bit to OVR */
9007   tlbl = newiTempLabel (NULL);
9008   tlbl1 = newiTempLabel (NULL);
9009
9010   size = AOP_SIZE (result);
9011   offset = size - 1;
9012   MOVA (aopGet (left, offset, FALSE, FALSE));
9013   emitcode ("rlc", "a");
9014   emitcode ("mov", "ov,c");
9015   /* if it is only one byte then */
9016   if (size == 1)
9017     {
9018       l = aopGet (left, 0, FALSE, FALSE);
9019       MOVA (l);
9020       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9021       emitcode ("", "%05d$:", tlbl->key + 100);
9022       emitcode ("mov", "c,ov");
9023       emitcode ("rrc", "a");
9024       emitcode ("", "%05d$:", tlbl1->key + 100);
9025       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9026       popB (pushedB);
9027       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9028       goto release;
9029     }
9030
9031   reAdjustPreg (AOP (result));
9032   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9033   emitcode ("", "%05d$:", tlbl->key + 100);
9034   emitcode ("mov", "c,ov");
9035   while (size--)
9036     {
9037       l = aopGet (result, offset, FALSE, FALSE);
9038       MOVA (l);
9039       emitcode ("rrc", "a");
9040       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9041     }
9042   reAdjustPreg (AOP (result));
9043   emitcode ("", "%05d$:", tlbl1->key + 100);
9044   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9045   popB (pushedB);
9046
9047 release:
9048   freeAsmop (left, NULL, ic, TRUE);
9049   freeAsmop (result, NULL, ic, TRUE);
9050 }
9051
9052 /*-----------------------------------------------------------------*/
9053 /* genRightShift - generate code for right shifting                */
9054 /*-----------------------------------------------------------------*/
9055 static void
9056 genRightShift (iCode * ic)
9057 {
9058   operand *right, *left, *result;
9059   sym_link *letype;
9060   int size, offset;
9061   char *l;
9062   symbol *tlbl, *tlbl1;
9063   bool pushedB;
9064
9065   D(emitcode (";     genRightShift",""));
9066
9067   /* if signed then we do it the hard way preserve the
9068      sign bit moving it inwards */
9069   letype = getSpec (operandType (IC_LEFT (ic)));
9070
9071   if (!SPEC_USIGN (letype))
9072     {
9073       genSignedRightShift (ic);
9074       return;
9075     }
9076
9077   /* signed & unsigned types are treated the same : i.e. the
9078      signed is NOT propagated inwards : quoting from the
9079      ANSI - standard : "for E1 >> E2, is equivalent to division
9080      by 2**E2 if unsigned or if it has a non-negative value,
9081      otherwise the result is implementation defined ", MY definition
9082      is that the sign does not get propagated */
9083
9084   right = IC_RIGHT (ic);
9085   left = IC_LEFT (ic);
9086   result = IC_RESULT (ic);
9087
9088   aopOp (right, ic, FALSE);
9089
9090   /* if the shift count is known then do it
9091      as efficiently as possible */
9092   if (AOP_TYPE (right) == AOP_LIT)
9093     {
9094       genRightShiftLiteral (left, right, result, ic, 0);
9095       return;
9096     }
9097
9098   /* shift count is unknown then we have to form
9099      a loop get the loop count in B : Note: we take
9100      only the lower order byte since shifting
9101      more that 32 bits make no sense anyway, ( the
9102      largest size of an object can be only 32 bits ) */
9103
9104   pushedB = pushB ();
9105   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
9106   emitcode ("inc", "b");
9107   freeAsmop (right, NULL, ic, TRUE);
9108   aopOp (left, ic, FALSE);
9109   aopOp (result, ic, FALSE);
9110
9111   /* now move the left to the result if they are not the
9112      same */
9113   if (!sameRegs (AOP (left), AOP (result)) &&
9114       AOP_SIZE (result) > 1)
9115     {
9116
9117       size = AOP_SIZE (result);
9118       offset = 0;
9119       while (size--)
9120         {
9121           l = aopGet (left, offset, FALSE, TRUE);
9122           if (*l == '@' && IS_AOP_PREG (result))
9123             {
9124
9125               emitcode ("mov", "a,%s", l);
9126               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9127             }
9128           else
9129             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
9130           offset++;
9131         }
9132     }
9133
9134   tlbl = newiTempLabel (NULL);
9135   tlbl1 = newiTempLabel (NULL);
9136   size = AOP_SIZE (result);
9137   offset = size - 1;
9138
9139   /* if it is only one byte then */
9140   if (size == 1)
9141     {
9142       l = aopGet (left, 0, FALSE, FALSE);
9143       MOVA (l);
9144       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9145       emitcode ("", "%05d$:", tlbl->key + 100);
9146       CLRC;
9147       emitcode ("rrc", "a");
9148       emitcode ("", "%05d$:", tlbl1->key + 100);
9149       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9150       popB (pushedB);
9151       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
9152       goto release;
9153     }
9154
9155   reAdjustPreg (AOP (result));
9156   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9157   emitcode ("", "%05d$:", tlbl->key + 100);
9158   CLRC;
9159   while (size--)
9160     {
9161       l = aopGet (result, offset, FALSE, FALSE);
9162       MOVA (l);
9163       emitcode ("rrc", "a");
9164       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
9165     }
9166   reAdjustPreg (AOP (result));
9167
9168   emitcode ("", "%05d$:", tlbl1->key + 100);
9169   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9170   popB (pushedB);
9171
9172 release:
9173   freeAsmop (left, NULL, ic, TRUE);
9174   freeAsmop (result, NULL, ic, TRUE);
9175 }
9176
9177 /*-----------------------------------------------------------------*/
9178 /* emitPtrByteGet - emits code to get a byte into A through a      */
9179 /*                  pointer register (R0, R1, or DPTR). The        */
9180 /*                  original value of A can be preserved in B.     */
9181 /*-----------------------------------------------------------------*/
9182 static void
9183 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9184 {
9185   switch (p_type)
9186     {
9187     case IPOINTER:
9188     case POINTER:
9189       if (preserveAinB)
9190         emitcode ("mov", "b,a");
9191       emitcode ("mov", "a,@%s", rname);
9192       break;
9193
9194     case PPOINTER:
9195       if (preserveAinB)
9196         emitcode ("mov", "b,a");
9197       emitcode ("movx", "a,@%s", rname);
9198       break;
9199
9200     case FPOINTER:
9201       if (preserveAinB)
9202         emitcode ("mov", "b,a");
9203       emitcode ("movx", "a,@dptr");
9204       break;
9205
9206     case CPOINTER:
9207       if (preserveAinB)
9208         emitcode ("mov", "b,a");
9209       emitcode ("clr", "a");
9210       emitcode ("movc", "a,@a+dptr");
9211       break;
9212
9213     case GPOINTER:
9214       if (preserveAinB)
9215         {
9216           emitcode ("push", "b");
9217           emitcode ("push", "acc");
9218         }
9219       emitcode ("lcall", "__gptrget");
9220       if (preserveAinB)
9221         emitcode ("pop", "b");
9222       break;
9223     }
9224 }
9225
9226 /*-----------------------------------------------------------------*/
9227 /* emitPtrByteSet - emits code to set a byte from src through a    */
9228 /*                  pointer register (R0, R1, or DPTR).            */
9229 /*-----------------------------------------------------------------*/
9230 static void
9231 emitPtrByteSet (char *rname, int p_type, char *src)
9232 {
9233   switch (p_type)
9234     {
9235     case IPOINTER:
9236     case POINTER:
9237       if (*src=='@')
9238         {
9239           MOVA (src);
9240           emitcode ("mov", "@%s,a", rname);
9241         }
9242       else
9243         emitcode ("mov", "@%s,%s", rname, src);
9244       break;
9245
9246     case PPOINTER:
9247       MOVA (src);
9248       emitcode ("movx", "@%s,a", rname);
9249       break;
9250
9251     case FPOINTER:
9252       MOVA (src);
9253       emitcode ("movx", "@dptr,a");
9254       break;
9255
9256     case GPOINTER:
9257       MOVA (src);
9258       emitcode ("lcall", "__gptrput");
9259       break;
9260     }
9261 }
9262
9263 /*-----------------------------------------------------------------*/
9264 /* genUnpackBits - generates code for unpacking bits               */
9265 /*-----------------------------------------------------------------*/
9266 static void
9267 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9268 {
9269   int offset = 0;       /* result byte offset */
9270   int rsize;            /* result size */
9271   int rlen = 0;         /* remaining bitfield length */
9272   sym_link *etype;      /* bitfield type information */
9273   int blen;             /* bitfield length */
9274   int bstr;             /* bitfield starting bit within byte */
9275   char buffer[10];
9276
9277   D(emitcode (";     genUnpackBits",""));
9278
9279   etype = getSpec (operandType (result));
9280   rsize = getSize (operandType (result));
9281   blen = SPEC_BLEN (etype);
9282   bstr = SPEC_BSTR (etype);
9283
9284   if (ifx && blen <= 8)
9285     {
9286       emitPtrByteGet (rname, ptype, FALSE);
9287       if (blen == 1)
9288         {
9289           SNPRINTF (buffer, sizeof(buffer),
9290                     "acc.%d", bstr);
9291           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9292         }
9293       else
9294         {
9295           if (blen < 8)
9296             emitcode ("anl", "a,#0x%02x",
9297                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9298           genIfxJump (ifx, "a", NULL, NULL, NULL);
9299         }
9300       return;
9301     }
9302   wassert (!ifx);
9303
9304   /* If the bitfield length is less than a byte */
9305   if (blen < 8)
9306     {
9307       emitPtrByteGet (rname, ptype, FALSE);
9308       AccRol (8 - bstr);
9309       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9310       if (!SPEC_USIGN (etype))
9311         {
9312           /* signed bitfield */
9313           symbol *tlbl = newiTempLabel (NULL);
9314
9315           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9316           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9317           emitcode ("", "%05d$:", tlbl->key + 100);
9318         }
9319       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9320       goto finish;
9321     }
9322
9323   /* Bit field did not fit in a byte. Copy all
9324      but the partial byte at the end.  */
9325   for (rlen=blen;rlen>=8;rlen-=8)
9326     {
9327       emitPtrByteGet (rname, ptype, FALSE);
9328       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9329       if (rlen>8)
9330         emitcode ("inc", "%s", rname);
9331     }
9332
9333   /* Handle the partial byte at the end */
9334   if (rlen)
9335     {
9336       emitPtrByteGet (rname, ptype, FALSE);
9337       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9338       if (!SPEC_USIGN (etype))
9339         {
9340           /* signed bitfield */
9341           symbol *tlbl = newiTempLabel (NULL);
9342
9343           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9344           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9345           emitcode ("", "%05d$:", tlbl->key + 100);
9346         }
9347       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9348     }
9349
9350 finish:
9351   if (offset < rsize)
9352     {
9353       char *source;
9354
9355       if (SPEC_USIGN (etype))
9356         source = zero;
9357       else
9358         {
9359           /* signed bitfield: sign extension with 0x00 or 0xff */
9360           emitcode ("rlc", "a");
9361           emitcode ("subb", "a,acc");
9362
9363           source = "a";
9364         }
9365       rsize -= offset;
9366       while (rsize--)
9367         aopPut (result, source, offset++, isOperandVolatile (result, FALSE));
9368     }
9369 }
9370
9371
9372 /*-----------------------------------------------------------------*/
9373 /* genDataPointerGet - generates code when ptr offset is known     */
9374 /*-----------------------------------------------------------------*/
9375 static void
9376 genDataPointerGet (operand * left,
9377                    operand * result,
9378                    iCode * ic)
9379 {
9380   char *l;
9381   char buffer[256];
9382   int size, offset = 0;
9383
9384   D(emitcode (";     genDataPointerGet",""));
9385
9386   aopOp (result, ic, TRUE);
9387
9388   /* get the string representation of the name */
9389   l = aopGet (left, 0, FALSE, TRUE);
9390   size = AOP_SIZE (result);
9391   while (size--)
9392     {
9393       if (offset)
9394         sprintf (buffer, "(%s + %d)", l + 1, offset);
9395       else
9396         sprintf (buffer, "%s", l + 1);
9397       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
9398     }
9399
9400   freeAsmop (left, NULL, ic, TRUE);
9401   freeAsmop (result, NULL, ic, TRUE);
9402 }
9403
9404 /*-----------------------------------------------------------------*/
9405 /* genNearPointerGet - emitcode for near pointer fetch             */
9406 /*-----------------------------------------------------------------*/
9407 static void
9408 genNearPointerGet (operand * left,
9409                    operand * result,
9410                    iCode * ic,
9411                    iCode * pi,
9412                    iCode * ifx)
9413 {
9414   asmop *aop = NULL;
9415   regs *preg = NULL;
9416   char *rname;
9417   sym_link *rtype, *retype;
9418   sym_link *ltype = operandType (left);
9419   char buffer[80];
9420
9421   D(emitcode (";     genNearPointerGet",""));
9422
9423   rtype = operandType (result);
9424   retype = getSpec (rtype);
9425
9426   aopOp (left, ic, FALSE);
9427
9428   /* if left is rematerialisable and
9429      result is not bitfield variable type and
9430      the left is pointer to data space i.e
9431      lower 128 bytes of space */
9432   if (AOP_TYPE (left) == AOP_IMMD &&
9433       !IS_BITFIELD (retype) &&
9434       DCL_TYPE (ltype) == POINTER)
9435     {
9436       genDataPointerGet (left, result, ic);
9437       return;
9438     }
9439
9440  /* if the value is already in a pointer register
9441      then don't need anything more */
9442   if (!AOP_INPREG (AOP (left)))
9443     {
9444       if (IS_AOP_PREG (left))
9445         {
9446           // Aha, it is a pointer, just in disguise.
9447           rname = aopGet (left, 0, FALSE, FALSE);
9448           if (*rname != '@')
9449             {
9450               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9451                       __FILE__, __LINE__);
9452             }
9453           else
9454             {
9455               // Expected case.
9456               emitcode ("mov", "a%s,%s", rname + 1, rname);
9457               rname++;  // skip the '@'.
9458             }
9459         }
9460       else
9461         {
9462           /* otherwise get a free pointer register */
9463           aop = newAsmop (0);
9464           preg = getFreePtr (ic, &aop, FALSE);
9465           emitcode ("mov", "%s,%s",
9466                     preg->name,
9467                     aopGet (left, 0, FALSE, TRUE));
9468           rname = preg->name;
9469         }
9470     }
9471   else
9472     rname = aopGet (left, 0, FALSE, FALSE);
9473
9474   //aopOp (result, ic, FALSE);
9475   aopOp (result, ic, result?TRUE:FALSE);
9476
9477   /* if bitfield then unpack the bits */
9478   if (IS_BITFIELD (retype))
9479     genUnpackBits (result, rname, POINTER, ifx);
9480   else
9481     {
9482       /* we have can just get the values */
9483       int size = AOP_SIZE (result);
9484       int offset = 0;
9485
9486       while (size--)
9487         {
9488           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9489             {
9490
9491               emitcode ("mov", "a,@%s", rname);
9492               if (!ifx)
9493               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9494             }
9495           else
9496             {
9497               sprintf (buffer, "@%s", rname);
9498               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
9499             }
9500           offset++;
9501           if (size || pi)
9502             emitcode ("inc", "%s", rname);
9503         }
9504     }
9505
9506   /* now some housekeeping stuff */
9507   if (aop)       /* we had to allocate for this iCode */
9508     {
9509       if (pi) { /* post increment present */
9510         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9511       }
9512       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9513     }
9514   else
9515     {
9516       /* we did not allocate which means left
9517          already in a pointer register, then
9518          if size > 0 && this could be used again
9519          we have to point it back to where it
9520          belongs */
9521       if ((AOP_SIZE (result) > 1 &&
9522            !OP_SYMBOL (left)->remat &&
9523            (OP_SYMBOL (left)->liveTo > ic->seq ||
9524             ic->depth)) &&
9525           !pi)
9526         {
9527           int size = AOP_SIZE (result) - 1;
9528           while (size--)
9529             emitcode ("dec", "%s", rname);
9530         }
9531     }
9532
9533   if (ifx && !ifx->generated)
9534     {
9535       genIfxJump (ifx, "a", left, NULL, result);
9536     }
9537
9538   /* done */
9539   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9540   freeAsmop (left, NULL, ic, TRUE);
9541   if (pi) pi->generated = 1;
9542 }
9543
9544 /*-----------------------------------------------------------------*/
9545 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9546 /*-----------------------------------------------------------------*/
9547 static void
9548 genPagedPointerGet (operand * left,
9549                     operand * result,
9550                     iCode * ic,
9551                     iCode *pi,
9552                     iCode *ifx)
9553 {
9554   asmop *aop = NULL;
9555   regs *preg = NULL;
9556   char *rname;
9557   sym_link *rtype, *retype;
9558
9559   D(emitcode (";     genPagedPointerGet",""));
9560
9561   rtype = operandType (result);
9562   retype = getSpec (rtype);
9563
9564   aopOp (left, ic, FALSE);
9565
9566   /* if the value is already in a pointer register
9567      then don't need anything more */
9568   if (!AOP_INPREG (AOP (left)))
9569     {
9570       /* otherwise get a free pointer register */
9571       aop = newAsmop (0);
9572       preg = getFreePtr (ic, &aop, FALSE);
9573       emitcode ("mov", "%s,%s",
9574                 preg->name,
9575                 aopGet (left, 0, FALSE, TRUE));
9576       rname = preg->name;
9577     }
9578   else
9579     rname = aopGet (left, 0, FALSE, FALSE);
9580
9581   aopOp (result, ic, FALSE);
9582
9583   /* if bitfield then unpack the bits */
9584   if (IS_BITFIELD (retype))
9585     genUnpackBits (result, rname, PPOINTER, ifx);
9586   else
9587     {
9588       /* we have can just get the values */
9589       int size = AOP_SIZE (result);
9590       int offset = 0;
9591
9592       while (size--)
9593         {
9594
9595           emitcode ("movx", "a,@%s", rname);
9596           if (!ifx)
9597           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9598
9599           offset++;
9600
9601           if (size || pi)
9602             emitcode ("inc", "%s", rname);
9603         }
9604     }
9605
9606   /* now some housekeeping stuff */
9607   if (aop) /* we had to allocate for this iCode */
9608     {
9609       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9610       freeAsmop (NULL, aop, ic, TRUE);
9611     }
9612   else
9613     {
9614       /* we did not allocate which means left
9615          already in a pointer register, then
9616          if size > 0 && this could be used again
9617          we have to point it back to where it
9618          belongs */
9619       if ((AOP_SIZE (result) > 1 &&
9620            !OP_SYMBOL (left)->remat &&
9621            (OP_SYMBOL (left)->liveTo > ic->seq ||
9622             ic->depth)) &&
9623           !pi)
9624         {
9625           int size = AOP_SIZE (result) - 1;
9626           while (size--)
9627             emitcode ("dec", "%s", rname);
9628         }
9629     }
9630
9631   if (ifx && !ifx->generated)
9632     {
9633       genIfxJump (ifx, "a", left, NULL, result);
9634     }
9635
9636   /* done */
9637   freeAsmop (left, NULL, ic, TRUE);
9638   freeAsmop (result, NULL, ic, TRUE);
9639   if (pi) pi->generated = 1;
9640
9641 }
9642
9643 /*--------------------------------------------------------------------*/
9644 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
9645 /*--------------------------------------------------------------------*/
9646 static void
9647 loadDptrFromOperand (operand *op, bool loadBToo)
9648 {
9649   if (AOP_TYPE (op) != AOP_STR)
9650     {
9651       /* if this is rematerializable */
9652       if (AOP_TYPE (op) == AOP_IMMD)
9653         {
9654           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
9655           if (loadBToo)
9656             {
9657               if (AOP(op)->aopu.aop_immd.from_cast_remat)
9658                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
9659               else
9660                 {
9661                   wassertl(FALSE, "need pointerCode");
9662                   emitcode ("", "; mov b,???");
9663                   /* genPointerGet and genPointerSet originally did different
9664                   ** things for this case. Both seem wrong.
9665                   ** from genPointerGet:
9666                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
9667                   ** from genPointerSet:
9668                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
9669                   */
9670                 }
9671             }
9672         }
9673       else if (AOP_TYPE (op) == AOP_DPTR)
9674         {
9675           if (loadBToo)
9676             {
9677               MOVA (aopGet (op, 0, FALSE, FALSE));
9678               emitcode ("push", "acc");
9679               MOVA (aopGet (op, 1, FALSE, FALSE));
9680               emitcode ("push", "acc");
9681               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9682               emitcode ("pop", "dph");
9683               emitcode ("pop", "dpl");
9684             }
9685           else
9686             {
9687               MOVA (aopGet (op, 0, FALSE, FALSE));
9688               emitcode ("push", "acc");
9689               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9690               emitcode ("pop", "dpl");
9691             }
9692         }
9693       else
9694         {                       /* we need to get it byte by byte */
9695           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9696           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9697           if (loadBToo)
9698             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9699         }
9700     }
9701 }
9702
9703 /*-----------------------------------------------------------------*/
9704 /* genFarPointerGet - gget value from far space                    */
9705 /*-----------------------------------------------------------------*/
9706 static void
9707 genFarPointerGet (operand * left,
9708                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9709 {
9710   int size, offset;
9711   sym_link *retype = getSpec (operandType (result));
9712
9713   D(emitcode (";     genFarPointerGet",""));
9714
9715   aopOp (left, ic, FALSE);
9716   loadDptrFromOperand (left, FALSE);
9717
9718   /* so dptr now contains the address */
9719   aopOp (result, ic, FALSE);
9720
9721   /* if bit then unpack */
9722   if (IS_BITFIELD (retype))
9723     genUnpackBits (result, "dptr", FPOINTER, ifx);
9724   else
9725     {
9726       size = AOP_SIZE (result);
9727       offset = 0;
9728
9729       while (size--)
9730         {
9731           emitcode ("movx", "a,@dptr");
9732           if (!ifx)
9733             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9734           if (size || pi)
9735             emitcode ("inc", "dptr");
9736         }
9737     }
9738
9739   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9740     {
9741     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9742     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9743     pi->generated = 1;
9744   }
9745
9746   if (ifx && !ifx->generated)
9747     {
9748       genIfxJump (ifx, "a", left, NULL, result);
9749     }
9750
9751   freeAsmop (left, NULL, ic, TRUE);
9752   freeAsmop (result, NULL, ic, TRUE);
9753 }
9754
9755 /*-----------------------------------------------------------------*/
9756 /* genCodePointerGet - gget value from code space                  */
9757 /*-----------------------------------------------------------------*/
9758 static void
9759 genCodePointerGet (operand * left,
9760                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9761 {
9762   int size, offset;
9763   sym_link *retype = getSpec (operandType (result));
9764
9765   D(emitcode (";     genCodePointerGet",""));
9766
9767   aopOp (left, ic, FALSE);
9768   loadDptrFromOperand (left, FALSE);
9769
9770   /* so dptr now contains the address */
9771   aopOp (result, ic, FALSE);
9772
9773   /* if bit then unpack */
9774   if (IS_BITFIELD (retype))
9775     genUnpackBits (result, "dptr", CPOINTER, ifx);
9776   else
9777     {
9778       size = AOP_SIZE (result);
9779       offset = 0;
9780
9781       while (size--)
9782         {
9783           if (pi)
9784             {
9785               emitcode ("clr", "a");
9786               emitcode ("movc", "a,@a+dptr");
9787               if (!ifx)
9788               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9789               emitcode ("inc", "dptr");
9790             }
9791           else
9792             {
9793               emitcode ("mov", "a,#0x%02x", offset);
9794               emitcode ("movc", "a,@a+dptr");
9795               if (!ifx)
9796               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9797             }
9798         }
9799     }
9800
9801   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9802     {
9803     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9804     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9805     pi->generated = 1;
9806   }
9807
9808   if (ifx && !ifx->generated)
9809     {
9810       genIfxJump (ifx, "a", left, NULL, result);
9811     }
9812
9813   freeAsmop (left, NULL, ic, TRUE);
9814   freeAsmop (result, NULL, ic, TRUE);
9815 }
9816
9817 /*-----------------------------------------------------------------*/
9818 /* genGenPointerGet - gget value from generic pointer space        */
9819 /*-----------------------------------------------------------------*/
9820 static void
9821 genGenPointerGet (operand * left,
9822                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9823 {
9824   int size, offset;
9825   sym_link *retype = getSpec (operandType (result));
9826
9827   D(emitcode (";     genGenPointerGet",""));
9828
9829   aopOp (left, ic, FALSE);
9830   loadDptrFromOperand (left, TRUE);
9831
9832   /* so dptr know contains the address */
9833   aopOp (result, ic, FALSE);
9834
9835   /* if bit then unpack */
9836   if (IS_BITFIELD (retype))
9837     genUnpackBits (result, "dptr", GPOINTER, ifx);
9838   else
9839     {
9840       size = AOP_SIZE (result);
9841       offset = 0;
9842
9843       while (size--)
9844         {
9845           emitcode ("lcall", "__gptrget");
9846           if (!ifx)
9847           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9848           if (size || pi)
9849             emitcode ("inc", "dptr");
9850         }
9851     }
9852
9853   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9854     {
9855     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9856     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9857     pi->generated = 1;
9858   }
9859
9860   if (ifx && !ifx->generated)
9861     {
9862       genIfxJump (ifx, "a", left, NULL, result);
9863     }
9864
9865
9866   freeAsmop (left, NULL, ic, TRUE);
9867   freeAsmop (result, NULL, ic, TRUE);
9868 }
9869
9870 /*-----------------------------------------------------------------*/
9871 /* genPointerGet - generate code for pointer get                   */
9872 /*-----------------------------------------------------------------*/
9873 static void
9874 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9875 {
9876   operand *left, *result;
9877   sym_link *type, *etype;
9878   int p_type;
9879
9880   D(emitcode (";     genPointerGet",""));
9881
9882   left = IC_LEFT (ic);
9883   result = IC_RESULT (ic);
9884
9885   if (getSize (operandType (result))>1)
9886     ifx = NULL;
9887
9888   /* depending on the type of pointer we need to
9889      move it to the correct pointer register */
9890   type = operandType (left);
9891   etype = getSpec (type);
9892   /* if left is of type of pointer then it is simple */
9893   if (IS_PTR (type) && !IS_FUNC (type->next))
9894     p_type = DCL_TYPE (type);
9895   else
9896     {
9897       /* we have to go by the storage class */
9898       p_type = PTR_TYPE (SPEC_OCLS (etype));
9899     }
9900
9901   /* special case when cast remat */
9902   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9903       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9904           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9905           type = operandType (left);
9906           p_type = DCL_TYPE (type);
9907   }
9908   /* now that we have the pointer type we assign
9909      the pointer values */
9910   switch (p_type)
9911     {
9912
9913     case POINTER:
9914     case IPOINTER:
9915       genNearPointerGet (left, result, ic, pi, ifx);
9916       break;
9917
9918     case PPOINTER:
9919       genPagedPointerGet (left, result, ic, pi, ifx);
9920       break;
9921
9922     case FPOINTER:
9923       genFarPointerGet (left, result, ic, pi, ifx);
9924       break;
9925
9926     case CPOINTER:
9927       genCodePointerGet (left, result, ic, pi, ifx);
9928       break;
9929
9930     case GPOINTER:
9931       genGenPointerGet (left, result, ic, pi, ifx);
9932       break;
9933     }
9934
9935 }
9936
9937
9938
9939 /*-----------------------------------------------------------------*/
9940 /* genPackBits - generates code for packed bit storage             */
9941 /*-----------------------------------------------------------------*/
9942 static void
9943 genPackBits (sym_link * etype,
9944              operand * right,
9945              char *rname, int p_type)
9946 {
9947   int offset = 0;       /* source byte offset */
9948   int rlen = 0;         /* remaining bitfield length */
9949   int blen;             /* bitfield length */
9950   int bstr;             /* bitfield starting bit within byte */
9951   int litval;           /* source literal value (if AOP_LIT) */
9952   unsigned char mask;   /* bitmask within current byte */
9953
9954   D(emitcode (";     genPackBits",""));
9955
9956   blen = SPEC_BLEN (etype);
9957   bstr = SPEC_BSTR (etype);
9958
9959   /* If the bitfield length is less than a byte */
9960   if (blen < 8)
9961     {
9962       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9963               (unsigned char) (0xFF >> (8 - bstr)));
9964
9965       if (AOP_TYPE (right) == AOP_LIT)
9966         {
9967           /* Case with a bitfield length <8 and literal source
9968           */
9969           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9970           litval <<= bstr;
9971           litval &= (~mask) & 0xff;
9972           emitPtrByteGet (rname, p_type, FALSE);
9973           if ((mask|litval)!=0xff)
9974             emitcode ("anl","a,#0x%02x", mask);
9975           if (litval)
9976             emitcode ("orl","a,#0x%02x", litval);
9977         }
9978       else
9979         {
9980           if ((blen==1) && (p_type!=GPOINTER))
9981             {
9982               /* Case with a bitfield length == 1 and no generic pointer
9983               */
9984               if (AOP_TYPE (right) == AOP_CRY)
9985                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9986               else
9987                 {
9988                   MOVA (aopGet (right, 0, FALSE, FALSE));
9989                   emitcode ("rrc","a");
9990                 }
9991               emitPtrByteGet (rname, p_type, FALSE);
9992               emitcode ("mov","acc.%d,c",bstr);
9993             }
9994           else
9995             {
9996               bool pushedB;
9997               /* Case with a bitfield length < 8 and arbitrary source
9998               */
9999               MOVA (aopGet (right, 0, FALSE, FALSE));
10000               /* shift and mask source value */
10001               AccLsh (bstr);
10002               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10003
10004               pushedB = pushB ();
10005               /* transfer A to B and get next byte */
10006               emitPtrByteGet (rname, p_type, TRUE);
10007
10008               emitcode ("anl", "a,#0x%02x", mask);
10009               emitcode ("orl", "a,b");
10010               if (p_type == GPOINTER)
10011                 emitcode ("pop", "b");
10012
10013               popB (pushedB);
10014            }
10015         }
10016
10017       emitPtrByteSet (rname, p_type, "a");
10018       return;
10019     }
10020
10021   /* Bit length is greater than 7 bits. In this case, copy  */
10022   /* all except the partial byte at the end                 */
10023   for (rlen=blen;rlen>=8;rlen-=8)
10024     {
10025       emitPtrByteSet (rname, p_type,
10026                       aopGet (right, offset++, FALSE, TRUE) );
10027       if (rlen>8)
10028         emitcode ("inc", "%s", rname);
10029     }
10030
10031   /* If there was a partial byte at the end */
10032   if (rlen)
10033     {
10034       mask = (((unsigned char) -1 << rlen) & 0xff);
10035
10036       if (AOP_TYPE (right) == AOP_LIT)
10037         {
10038           /* Case with partial byte and literal source
10039           */
10040           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10041           litval >>= (blen-rlen);
10042           litval &= (~mask) & 0xff;
10043           emitPtrByteGet (rname, p_type, FALSE);
10044           if ((mask|litval)!=0xff)
10045             emitcode ("anl","a,#0x%02x", mask);
10046           if (litval)
10047             emitcode ("orl","a,#0x%02x", litval);
10048         }
10049       else
10050         {
10051           bool pushedB;
10052           /* Case with partial byte and arbitrary source
10053           */
10054           MOVA (aopGet (right, offset++, FALSE, FALSE));
10055           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10056
10057           pushedB = pushB ();
10058           /* transfer A to B and get next byte */
10059           emitPtrByteGet (rname, p_type, TRUE);
10060
10061           emitcode ("anl", "a,#0x%02x", mask);
10062           emitcode ("orl", "a,b");
10063           if (p_type == GPOINTER)
10064             emitcode ("pop", "b");
10065
10066           popB (pushedB);
10067         }
10068       emitPtrByteSet (rname, p_type, "a");
10069     }
10070
10071 }
10072
10073
10074 /*-----------------------------------------------------------------*/
10075 /* genDataPointerSet - remat pointer to data space                 */
10076 /*-----------------------------------------------------------------*/
10077 static void
10078 genDataPointerSet (operand * right,
10079                    operand * result,
10080                    iCode * ic)
10081 {
10082   int size, offset = 0;
10083   char *l, buffer[256];
10084
10085   D(emitcode (";     genDataPointerSet",""));
10086
10087   aopOp (right, ic, FALSE);
10088
10089   l = aopGet (result, 0, FALSE, TRUE);
10090   size = AOP_SIZE (right);
10091   while (size--)
10092     {
10093       if (offset)
10094         sprintf (buffer, "(%s + %d)", l + 1, offset);
10095       else
10096         sprintf (buffer, "%s", l + 1);
10097       emitcode ("mov", "%s,%s", buffer,
10098                 aopGet (right, offset++, FALSE, FALSE));
10099     }
10100
10101   freeAsmop (right, NULL, ic, TRUE);
10102   freeAsmop (result, NULL, ic, TRUE);
10103 }
10104
10105 /*-----------------------------------------------------------------*/
10106 /* genNearPointerSet - emitcode for near pointer put                */
10107 /*-----------------------------------------------------------------*/
10108 static void
10109 genNearPointerSet (operand * right,
10110                    operand * result,
10111                    iCode * ic,
10112                    iCode * pi)
10113 {
10114   asmop *aop = NULL;
10115   regs *preg = NULL;
10116   char *rname, *l;
10117   sym_link *retype, *letype;
10118   sym_link *ptype = operandType (result);
10119
10120   D(emitcode (";     genNearPointerSet",""));
10121
10122   retype = getSpec (operandType (right));
10123   letype = getSpec (ptype);
10124   aopOp (result, ic, FALSE);
10125
10126   /* if the result is rematerializable &
10127      in data space & not a bit variable */
10128   if (AOP_TYPE (result) == AOP_IMMD &&
10129       DCL_TYPE (ptype) == POINTER &&
10130       !IS_BITVAR (retype) &&
10131       !IS_BITVAR (letype))
10132     {
10133       genDataPointerSet (right, result, ic);
10134       return;
10135     }
10136
10137   /* if the value is already in a pointer register
10138      then don't need anything more */
10139   if (!AOP_INPREG (AOP (result)))
10140     {
10141         if (
10142             //AOP_TYPE (result) == AOP_STK
10143             IS_AOP_PREG(result)
10144             )
10145         {
10146             // Aha, it is a pointer, just in disguise.
10147             rname = aopGet (result, 0, FALSE, FALSE);
10148             if (*rname != '@')
10149             {
10150                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10151                         __FILE__, __LINE__);
10152             }
10153             else
10154             {
10155                 // Expected case.
10156                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10157                 rname++;  // skip the '@'.
10158             }
10159         }
10160         else
10161         {
10162             /* otherwise get a free pointer register */
10163             aop = newAsmop (0);
10164             preg = getFreePtr (ic, &aop, FALSE);
10165             emitcode ("mov", "%s,%s",
10166                       preg->name,
10167                       aopGet (result, 0, FALSE, TRUE));
10168             rname = preg->name;
10169         }
10170     }
10171     else
10172     {
10173         rname = aopGet (result, 0, FALSE, FALSE);
10174     }
10175
10176   aopOp (right, ic, FALSE);
10177
10178   /* if bitfield then unpack the bits */
10179   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10180     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10181   else
10182     {
10183       /* we have can just get the values */
10184       int size = AOP_SIZE (right);
10185       int offset = 0;
10186
10187       while (size--)
10188         {
10189           l = aopGet (right, offset, FALSE, TRUE);
10190           if (*l == '@')
10191             {
10192               MOVA (l);
10193               emitcode ("mov", "@%s,a", rname);
10194             }
10195           else
10196             emitcode ("mov", "@%s,%s", rname, l);
10197           if (size || pi)
10198             emitcode ("inc", "%s", rname);
10199           offset++;
10200         }
10201     }
10202
10203   /* now some housekeeping stuff */
10204   if (aop) /* we had to allocate for this iCode */
10205     {
10206       if (pi)
10207         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10208       freeAsmop (NULL, aop, ic, TRUE);
10209     }
10210   else
10211     {
10212       /* we did not allocate which means left
10213          already in a pointer register, then
10214          if size > 0 && this could be used again
10215          we have to point it back to where it
10216          belongs */
10217       if ((AOP_SIZE (right) > 1 &&
10218            !OP_SYMBOL (result)->remat &&
10219            (OP_SYMBOL (result)->liveTo > ic->seq ||
10220             ic->depth)) &&
10221           !pi)
10222         {
10223           int size = AOP_SIZE (right) - 1;
10224           while (size--)
10225             emitcode ("dec", "%s", rname);
10226         }
10227     }
10228
10229   /* done */
10230   if (pi) pi->generated = 1;
10231   freeAsmop (result, NULL, ic, TRUE);
10232   freeAsmop (right, NULL, ic, TRUE);
10233 }
10234
10235 /*-----------------------------------------------------------------*/
10236 /* genPagedPointerSet - emitcode for Paged pointer put             */
10237 /*-----------------------------------------------------------------*/
10238 static void
10239 genPagedPointerSet (operand * right,
10240                     operand * result,
10241                     iCode * ic,
10242                     iCode * pi)
10243 {
10244   asmop *aop = NULL;
10245   regs *preg = NULL;
10246   char *rname, *l;
10247   sym_link *retype, *letype;
10248
10249   D(emitcode (";     genPagedPointerSet",""));
10250
10251   retype = getSpec (operandType (right));
10252   letype = getSpec (operandType (result));
10253
10254   aopOp (result, ic, FALSE);
10255
10256   /* if the value is already in a pointer register
10257      then don't need anything more */
10258   if (!AOP_INPREG (AOP (result)))
10259     {
10260       /* otherwise get a free pointer register */
10261       aop = newAsmop (0);
10262       preg = getFreePtr (ic, &aop, FALSE);
10263       emitcode ("mov", "%s,%s",
10264                 preg->name,
10265                 aopGet (result, 0, FALSE, TRUE));
10266       rname = preg->name;
10267     }
10268   else
10269     rname = aopGet (result, 0, FALSE, FALSE);
10270
10271   aopOp (right, ic, FALSE);
10272
10273   /* if bitfield then unpack the bits */
10274   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10275     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10276   else
10277     {
10278       /* we have can just get the values */
10279       int size = AOP_SIZE (right);
10280       int offset = 0;
10281
10282       while (size--)
10283         {
10284           l = aopGet (right, offset, FALSE, TRUE);
10285
10286           MOVA (l);
10287           emitcode ("movx", "@%s,a", rname);
10288
10289           if (size || pi)
10290             emitcode ("inc", "%s", rname);
10291
10292           offset++;
10293         }
10294     }
10295
10296   /* now some housekeeping stuff */
10297   if (aop) /* we had to allocate for this iCode */
10298     {
10299       if (pi)
10300         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10301       freeAsmop (NULL, aop, ic, TRUE);
10302     }
10303   else
10304     {
10305       /* we did not allocate which means left
10306          already in a pointer register, then
10307          if size > 0 && this could be used again
10308          we have to point it back to where it
10309          belongs */
10310       if (AOP_SIZE (right) > 1 &&
10311           !OP_SYMBOL (result)->remat &&
10312           (OP_SYMBOL (result)->liveTo > ic->seq ||
10313            ic->depth))
10314         {
10315           int size = AOP_SIZE (right) - 1;
10316           while (size--)
10317             emitcode ("dec", "%s", rname);
10318         }
10319     }
10320
10321   /* done */
10322   if (pi) pi->generated = 1;
10323   freeAsmop (result, NULL, ic, TRUE);
10324   freeAsmop (right, NULL, ic, TRUE);
10325
10326
10327 }
10328
10329 /*-----------------------------------------------------------------*/
10330 /* genFarPointerSet - set value from far space                     */
10331 /*-----------------------------------------------------------------*/
10332 static void
10333 genFarPointerSet (operand * right,
10334                   operand * result, iCode * ic, iCode * pi)
10335 {
10336   int size, offset;
10337   sym_link *retype = getSpec (operandType (right));
10338   sym_link *letype = getSpec (operandType (result));
10339
10340   D(emitcode (";     genFarPointerSet",""));
10341
10342   aopOp (result, ic, FALSE);
10343   loadDptrFromOperand (result, FALSE);
10344
10345   /* so dptr know contains the address */
10346   aopOp (right, ic, FALSE);
10347
10348   /* if bit then unpack */
10349   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10350     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10351   else
10352     {
10353       size = AOP_SIZE (right);
10354       offset = 0;
10355
10356       while (size--)
10357         {
10358           char *l = aopGet (right, offset++, FALSE, FALSE);
10359           MOVA (l);
10360           emitcode ("movx", "@dptr,a");
10361           if (size || pi)
10362             emitcode ("inc", "dptr");
10363         }
10364     }
10365   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10366     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10367     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10368     pi->generated=1;
10369   }
10370   freeAsmop (result, NULL, ic, TRUE);
10371   freeAsmop (right, NULL, ic, TRUE);
10372 }
10373
10374 /*-----------------------------------------------------------------*/
10375 /* genGenPointerSet - set value from generic pointer space         */
10376 /*-----------------------------------------------------------------*/
10377 static void
10378 genGenPointerSet (operand * right,
10379                   operand * result, iCode * ic, iCode * pi)
10380 {
10381   int size, offset;
10382   sym_link *retype = getSpec (operandType (right));
10383   sym_link *letype = getSpec (operandType (result));
10384
10385   D(emitcode (";     genGenPointerSet",""));
10386
10387   aopOp (result, ic, FALSE);
10388   loadDptrFromOperand (result, TRUE);
10389
10390   /* so dptr know contains the address */
10391   aopOp (right, ic, FALSE);
10392
10393   /* if bit then unpack */
10394   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10395     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10396   else
10397     {
10398       size = AOP_SIZE (right);
10399       offset = 0;
10400
10401       while (size--)
10402         {
10403           char *l = aopGet (right, offset++, FALSE, FALSE);
10404           MOVA (l);
10405           emitcode ("lcall", "__gptrput");
10406           if (size || pi)
10407             emitcode ("inc", "dptr");
10408         }
10409     }
10410
10411   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10412     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10413     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10414     pi->generated=1;
10415   }
10416   freeAsmop (result, NULL, ic, TRUE);
10417   freeAsmop (right, NULL, ic, TRUE);
10418 }
10419
10420 /*-----------------------------------------------------------------*/
10421 /* genPointerSet - stores the value into a pointer location        */
10422 /*-----------------------------------------------------------------*/
10423 static void
10424 genPointerSet (iCode * ic, iCode *pi)
10425 {
10426   operand *right, *result;
10427   sym_link *type, *etype;
10428   int p_type;
10429
10430   D(emitcode (";     genPointerSet",""));
10431
10432   right = IC_RIGHT (ic);
10433   result = IC_RESULT (ic);
10434
10435   /* depending on the type of pointer we need to
10436      move it to the correct pointer register */
10437   type = operandType (result);
10438   etype = getSpec (type);
10439   /* if left is of type of pointer then it is simple */
10440   if (IS_PTR (type) && !IS_FUNC (type->next))
10441     {
10442       p_type = DCL_TYPE (type);
10443     }
10444   else
10445     {
10446       /* we have to go by the storage class */
10447       p_type = PTR_TYPE (SPEC_OCLS (etype));
10448     }
10449
10450   /* special case when cast remat */
10451   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10452       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10453           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10454           type = operandType (result);
10455           p_type = DCL_TYPE (type);
10456   }
10457   /* now that we have the pointer type we assign
10458      the pointer values */
10459   switch (p_type)
10460     {
10461
10462     case POINTER:
10463     case IPOINTER:
10464       genNearPointerSet (right, result, ic, pi);
10465       break;
10466
10467     case PPOINTER:
10468       genPagedPointerSet (right, result, ic, pi);
10469       break;
10470
10471     case FPOINTER:
10472       genFarPointerSet (right, result, ic, pi);
10473       break;
10474
10475     case GPOINTER:
10476       genGenPointerSet (right, result, ic, pi);
10477       break;
10478
10479     default:
10480       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10481               "genPointerSet: illegal pointer type");
10482     }
10483
10484 }
10485
10486 /*-----------------------------------------------------------------*/
10487 /* genIfx - generate code for Ifx statement                        */
10488 /*-----------------------------------------------------------------*/
10489 static void
10490 genIfx (iCode * ic, iCode * popIc)
10491 {
10492   operand *cond = IC_COND (ic);
10493   int isbit = 0;
10494   char *dup = NULL;
10495
10496   D(emitcode (";     genIfx",""));
10497
10498   aopOp (cond, ic, FALSE);
10499
10500   /* get the value into acc */
10501   if (AOP_TYPE (cond) != AOP_CRY)
10502     toBoolean (cond);
10503   else
10504     {
10505       isbit = 1;
10506       if (AOP(cond)->aopu.aop_dir)
10507         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10508     }
10509   /* the result is now in the accumulator or a directly addressable bit */
10510   freeAsmop (cond, NULL, ic, TRUE);
10511
10512   /* if there was something to be popped then do it */
10513   if (popIc)
10514     genIpop (popIc);
10515
10516   /* if the condition is a bit variable */
10517   if (isbit && dup)
10518     genIfxJump(ic, dup, NULL, NULL, NULL);
10519   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10520     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10521   else if (isbit && !IS_ITEMP (cond))
10522     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10523   else
10524     genIfxJump (ic, "a", NULL, NULL, NULL);
10525
10526   ic->generated = 1;
10527 }
10528
10529 /*-----------------------------------------------------------------*/
10530 /* genAddrOf - generates code for address of                       */
10531 /*-----------------------------------------------------------------*/
10532 static void
10533 genAddrOf (iCode * ic)
10534 {
10535   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10536   int size, offset;
10537
10538   D(emitcode (";     genAddrOf",""));
10539
10540   aopOp (IC_RESULT (ic), ic, FALSE);
10541
10542   /* if the operand is on the stack then we
10543      need to get the stack offset of this
10544      variable */
10545   if (sym->onStack)
10546     {
10547       /* if it has an offset then we need to compute
10548          it */
10549       if (sym->stack)
10550         {
10551           emitcode ("mov", "a,%s", SYM_BP (sym));
10552           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
10553                                          ((char) (sym->stack - _G.nRegsSaved)) :
10554                                          ((char) sym->stack)) & 0xff);
10555           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10556         }
10557       else
10558         {
10559           /* we can just move _bp */
10560           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10561         }
10562       /* fill the result with zero */
10563       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10564
10565       offset = 1;
10566       while (size--)
10567         {
10568           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10569         }
10570
10571       goto release;
10572     }
10573
10574   /* object not on stack then we need the name */
10575   size = AOP_SIZE (IC_RESULT (ic));
10576   offset = 0;
10577
10578   while (size--)
10579     {
10580       char s[SDCC_NAME_MAX];
10581       if (offset)
10582         sprintf (s, "#(%s >> %d)",
10583                  sym->rname,
10584                  offset * 8);
10585       else
10586         sprintf (s, "#%s", sym->rname);
10587       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10588     }
10589
10590 release:
10591   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10592
10593 }
10594
10595 /*-----------------------------------------------------------------*/
10596 /* genFarFarAssign - assignment when both are in far space         */
10597 /*-----------------------------------------------------------------*/
10598 static void
10599 genFarFarAssign (operand * result, operand * right, iCode * ic)
10600 {
10601   int size = AOP_SIZE (right);
10602   int offset = 0;
10603   char *l;
10604
10605   D(emitcode (";     genFarFarAssign",""));
10606
10607   /* first push the right side on to the stack */
10608   while (size--)
10609     {
10610       l = aopGet (right, offset++, FALSE, FALSE);
10611       MOVA (l);
10612       emitcode ("push", "acc");
10613     }
10614
10615   freeAsmop (right, NULL, ic, FALSE);
10616   /* now assign DPTR to result */
10617   aopOp (result, ic, FALSE);
10618   size = AOP_SIZE (result);
10619   while (size--)
10620     {
10621       emitcode ("pop", "acc");
10622       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
10623     }
10624   freeAsmop (result, NULL, ic, FALSE);
10625
10626 }
10627
10628 /*-----------------------------------------------------------------*/
10629 /* genAssign - generate code for assignment                        */
10630 /*-----------------------------------------------------------------*/
10631 static void
10632 genAssign (iCode * ic)
10633 {
10634   operand *result, *right;
10635   int size, offset;
10636   unsigned long lit = 0L;
10637
10638   D(emitcode(";     genAssign",""));
10639
10640   result = IC_RESULT (ic);
10641   right = IC_RIGHT (ic);
10642
10643   /* if they are the same */
10644   if (operandsEqu (result, right) &&
10645       !isOperandVolatile (result, FALSE) &&
10646       !isOperandVolatile (right, FALSE))
10647     return;
10648
10649   aopOp (right, ic, FALSE);
10650
10651   /* special case both in far space */
10652   if (AOP_TYPE (right) == AOP_DPTR &&
10653       IS_TRUE_SYMOP (result) &&
10654       isOperandInFarSpace (result))
10655     {
10656
10657       genFarFarAssign (result, right, ic);
10658       return;
10659     }
10660
10661   aopOp (result, ic, TRUE);
10662
10663   /* if they are the same registers */
10664   if (sameRegs (AOP (right), AOP (result)) &&
10665       !isOperandVolatile (result, FALSE) &&
10666       !isOperandVolatile (right, FALSE))
10667     goto release;
10668
10669   /* if the result is a bit */
10670   if (AOP_TYPE (result) == AOP_CRY)
10671     {
10672
10673       /* if the right size is a literal then
10674          we know what the value is */
10675       if (AOP_TYPE (right) == AOP_LIT)
10676         {
10677           if (((int) operandLitValue (right)))
10678             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10679           else
10680             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10681           goto release;
10682         }
10683
10684       /* the right is also a bit variable */
10685       if (AOP_TYPE (right) == AOP_CRY)
10686         {
10687           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10688           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10689           goto release;
10690         }
10691
10692       /* we need to or */
10693       toBoolean (right);
10694       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10695       goto release;
10696     }
10697
10698   /* bit variables done */
10699   /* general case */
10700   size = AOP_SIZE (result);
10701   offset = 0;
10702   if (AOP_TYPE (right) == AOP_LIT)
10703     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10704   if ((size > 1) &&
10705       (AOP_TYPE (result) != AOP_REG) &&
10706       (AOP_TYPE (right) == AOP_LIT) &&
10707       !IS_FLOAT (operandType (right)) &&
10708       (lit < 256L))
10709     {
10710       while ((size) && (lit))
10711         {
10712           aopPut (result,
10713                   aopGet (right, offset, FALSE, FALSE),
10714                   offset,
10715                   isOperandVolatile (result, FALSE));
10716           lit >>= 8;
10717           offset++;
10718           size--;
10719         }
10720       emitcode ("clr", "a");
10721       while (size--)
10722         {
10723           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10724           offset++;
10725         }
10726     }
10727   else
10728     {
10729       while (size--)
10730         {
10731           aopPut (result,
10732                   aopGet (right, offset, FALSE, FALSE),
10733                   offset,
10734                   isOperandVolatile (result, FALSE));
10735           offset++;
10736         }
10737     }
10738
10739 release:
10740   freeAsmop (right, NULL, ic, TRUE);
10741   freeAsmop (result, NULL, ic, TRUE);
10742 }
10743
10744 /*-----------------------------------------------------------------*/
10745 /* genJumpTab - generates code for jump table                      */
10746 /*-----------------------------------------------------------------*/
10747 static void
10748 genJumpTab (iCode * ic)
10749 {
10750   symbol *jtab,*jtablo,*jtabhi;
10751   char *l;
10752   unsigned int count;
10753
10754   D(emitcode (";     genJumpTab",""));
10755
10756   count = elementsInSet( IC_JTLABELS (ic) );
10757
10758   if( count <= 16 )
10759     {
10760       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10761          if the switch argument is in a register.
10762          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10763       /* (MB) What if peephole converts ljmp to sjmp or ret ???
10764          How will multiply by three be updated ???*/
10765       aopOp (IC_JTCOND (ic), ic, FALSE);
10766       /* get the condition into accumulator */
10767       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10768       MOVA (l);
10769       /* multiply by three */
10770       emitcode ("add", "a,acc");
10771       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10772       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10773
10774       jtab = newiTempLabel (NULL);
10775       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10776       emitcode ("jmp", "@a+dptr");
10777       emitcode ("", "%05d$:", jtab->key + 100);
10778       /* now generate the jump labels */
10779       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10780            jtab = setNextItem (IC_JTLABELS (ic)))
10781         emitcode ("ljmp", "%05d$", jtab->key + 100);
10782     }
10783   else
10784     {
10785       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10786          if the switch argument is in a register.
10787          For n>6 this algorithm may be more compact */
10788       jtablo = newiTempLabel (NULL);
10789       jtabhi = newiTempLabel (NULL);
10790
10791       /* get the condition into accumulator.
10792          Using b as temporary storage, if register push/pop is needed */
10793       aopOp (IC_JTCOND (ic), ic, FALSE);
10794       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10795       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10796           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10797         {
10798           // (MB) what if B is in use???
10799           wassertl(!BINUSE, "B was in use");
10800           emitcode ("mov", "b,%s", l);
10801           l = "b";
10802         }
10803       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10804       MOVA (l);
10805       if( count <= 112 )
10806         {
10807           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10808           emitcode ("movc", "a,@a+pc");
10809           emitcode ("push", "acc");
10810
10811           MOVA (l);
10812           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10813           emitcode ("movc", "a,@a+pc");
10814           emitcode ("push", "acc");
10815         }
10816       else
10817         {
10818           /* this scales up to n<=255, but needs two more bytes
10819              and changes dptr */
10820           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10821           emitcode ("movc", "a,@a+dptr");
10822           emitcode ("push", "acc");
10823
10824           MOVA (l);
10825           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10826           emitcode ("movc", "a,@a+dptr");
10827           emitcode ("push", "acc");
10828         }
10829
10830       emitcode ("ret", "");
10831
10832       /* now generate jump table, LSB */
10833       emitcode ("", "%05d$:", jtablo->key + 100);
10834       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10835            jtab = setNextItem (IC_JTLABELS (ic)))
10836         emitcode (".db", "%05d$", jtab->key + 100);
10837
10838       /* now generate jump table, MSB */
10839       emitcode ("", "%05d$:", jtabhi->key + 100);
10840       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10841            jtab = setNextItem (IC_JTLABELS (ic)))
10842          emitcode (".db", "%05d$>>8", jtab->key + 100);
10843     }
10844 }
10845
10846 /*-----------------------------------------------------------------*/
10847 /* genCast - gen code for casting                                  */
10848 /*-----------------------------------------------------------------*/
10849 static void
10850 genCast (iCode * ic)
10851 {
10852   operand *result = IC_RESULT (ic);
10853   sym_link *ctype = operandType (IC_LEFT (ic));
10854   sym_link *rtype = operandType (IC_RIGHT (ic));
10855   operand *right = IC_RIGHT (ic);
10856   int size, offset;
10857
10858   D(emitcode(";     genCast",""));
10859
10860   /* if they are equivalent then do nothing */
10861   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10862     return;
10863
10864   aopOp (right, ic, FALSE);
10865   aopOp (result, ic, FALSE);
10866
10867   /* if the result is a bit (and not a bitfield) */
10868   // if (AOP_TYPE (result) == AOP_CRY)
10869   if (IS_BIT (OP_SYMBOL (result)->type))
10870     /* not for bitfields */
10871     {
10872       /* if the right size is a literal then
10873          we know what the value is */
10874       if (AOP_TYPE (right) == AOP_LIT)
10875         {
10876           if (((int) operandLitValue (right)))
10877             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10878           else
10879             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10880
10881           goto release;
10882         }
10883
10884       /* the right is also a bit variable */
10885       if (AOP_TYPE (right) == AOP_CRY)
10886         {
10887           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10888           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10889           goto release;
10890         }
10891
10892       /* we need to or */
10893       toBoolean (right);
10894       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10895       goto release;
10896     }
10897
10898
10899   /* if they are the same size : or less */
10900   if (AOP_SIZE (result) <= AOP_SIZE (right))
10901     {
10902
10903       /* if they are in the same place */
10904       if (sameRegs (AOP (right), AOP (result)))
10905         goto release;
10906
10907       /* if they in different places then copy */
10908       size = AOP_SIZE (result);
10909       offset = 0;
10910       while (size--)
10911         {
10912           aopPut (result,
10913                   aopGet (right, offset, FALSE, FALSE),
10914                   offset,
10915                   isOperandVolatile (result, FALSE));
10916           offset++;
10917         }
10918       goto release;
10919     }
10920
10921
10922   /* if the result is of type pointer */
10923   if (IS_PTR (ctype))
10924     {
10925
10926       int p_type;
10927       sym_link *type = operandType (right);
10928       sym_link *etype = getSpec (type);
10929
10930       /* pointer to generic pointer */
10931       if (IS_GENPTR (ctype))
10932         {
10933           if (IS_PTR (type))
10934             p_type = DCL_TYPE (type);
10935           else
10936             {
10937               if (SPEC_SCLS(etype)==S_REGISTER) {
10938                 // let's assume it is a generic pointer
10939                 p_type=GPOINTER;
10940               } else {
10941                 /* we have to go by the storage class */
10942                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10943               }
10944             }
10945
10946           /* the first two bytes are known */
10947           size = GPTRSIZE - 1;
10948           offset = 0;
10949           while (size--)
10950             {
10951               aopPut (result,
10952                       aopGet (right, offset, FALSE, FALSE),
10953                       offset,
10954                       isOperandVolatile (result, FALSE));
10955               offset++;
10956             }
10957           /* the last byte depending on type */
10958             {
10959                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10960                 char gpValStr[10];
10961
10962                 if (gpVal == -1)
10963                 {
10964                     // pointerTypeToGPByte will have bitched.
10965                     exit(1);
10966                 }
10967
10968                 sprintf(gpValStr, "#0x%x", gpVal);
10969                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10970             }
10971           goto release;
10972         }
10973
10974       /* just copy the pointers */
10975       size = AOP_SIZE (result);
10976       offset = 0;
10977       while (size--)
10978         {
10979           aopPut (result,
10980                   aopGet (right, offset, FALSE, FALSE),
10981                   offset,
10982                   isOperandVolatile (result, FALSE));
10983           offset++;
10984         }
10985       goto release;
10986     }
10987
10988   /* so we now know that the size of destination is greater
10989      than the size of the source */
10990   /* we move to result for the size of source */
10991   size = AOP_SIZE (right);
10992   offset = 0;
10993   while (size--)
10994     {
10995       aopPut (result,
10996               aopGet (right, offset, FALSE, FALSE),
10997               offset,
10998               isOperandVolatile (result, FALSE));
10999       offset++;
11000     }
11001
11002   /* now depending on the sign of the source && destination */
11003   size = AOP_SIZE (result) - AOP_SIZE (right);
11004   /* if unsigned or not an integral type */
11005   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11006     {
11007       while (size--)
11008         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
11009     }
11010   else
11011     {
11012       /* we need to extend the sign :{ */
11013       char *l = aopGet (right, AOP_SIZE (right) - 1,
11014                         FALSE, FALSE);
11015       MOVA (l);
11016       emitcode ("rlc", "a");
11017       emitcode ("subb", "a,acc");
11018       while (size--)
11019         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
11020     }
11021
11022   /* we are done hurray !!!! */
11023
11024 release:
11025   freeAsmop (right, NULL, ic, TRUE);
11026   freeAsmop (result, NULL, ic, TRUE);
11027
11028 }
11029
11030 /*-----------------------------------------------------------------*/
11031 /* genDjnz - generate decrement & jump if not zero instrucion      */
11032 /*-----------------------------------------------------------------*/
11033 static int
11034 genDjnz (iCode * ic, iCode * ifx)
11035 {
11036   symbol *lbl, *lbl1;
11037   if (!ifx)
11038     return 0;
11039
11040   D(emitcode (";     genDjnz",""));
11041
11042   /* if the if condition has a false label
11043      then we cannot save */
11044   if (IC_FALSE (ifx))
11045     return 0;
11046
11047   /* if the minus is not of the form
11048      a = a - 1 */
11049   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11050       !IS_OP_LITERAL (IC_RIGHT (ic)))
11051     return 0;
11052
11053   if (operandLitValue (IC_RIGHT (ic)) != 1)
11054     return 0;
11055
11056   /* if the size of this greater than one then no
11057      saving */
11058   if (getSize (operandType (IC_RESULT (ic))) > 1)
11059     return 0;
11060
11061   /* otherwise we can save BIG */
11062   lbl = newiTempLabel (NULL);
11063   lbl1 = newiTempLabel (NULL);
11064
11065   aopOp (IC_RESULT (ic), ic, FALSE);
11066
11067   if (AOP_NEEDSACC(IC_RESULT(ic)))
11068   {
11069       /* If the result is accessed indirectly via
11070        * the accumulator, we must explicitly write
11071        * it back after the decrement.
11072        */
11073       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11074
11075       if (strcmp(rByte, "a"))
11076       {
11077            /* Something is hopelessly wrong */
11078            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11079                    __FILE__, __LINE__);
11080            /* We can just give up; the generated code will be inefficient,
11081             * but what the hey.
11082             */
11083            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11084            return 0;
11085       }
11086       emitcode ("dec", "%s", rByte);
11087       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
11088       emitcode ("jnz", "%05d$", lbl->key + 100);
11089   }
11090   else if (IS_AOP_PREG (IC_RESULT (ic)))
11091     {
11092       emitcode ("dec", "%s",
11093                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11094       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11095       emitcode ("jnz", "%05d$", lbl->key + 100);
11096     }
11097   else
11098     {
11099       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11100                 lbl->key + 100);
11101     }
11102   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11103   emitcode ("", "%05d$:", lbl->key + 100);
11104   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11105   emitcode ("", "%05d$:", lbl1->key + 100);
11106
11107   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11108   ifx->generated = 1;
11109   return 1;
11110 }
11111
11112 /*-----------------------------------------------------------------*/
11113 /* genReceive - generate code for a receive iCode                  */
11114 /*-----------------------------------------------------------------*/
11115 static void
11116 genReceive (iCode * ic)
11117 {
11118   int size = getSize (operandType (IC_RESULT (ic)));
11119   int offset = 0;
11120
11121   D(emitcode (";     genReceive",""));
11122
11123   if (ic->argreg == 1)
11124     { /* first parameter */
11125       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11126            isOperandInPagedSpace (IC_RESULT (ic))) &&
11127           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11128            IS_TRUE_SYMOP (IC_RESULT (ic))))
11129         {
11130           regs *tempRegs[4];
11131           int receivingA = 0;
11132           int roffset = 0;
11133
11134           for (offset = 0; offset<size; offset++)
11135             if (!strcmp (fReturn[offset], "a"))
11136               receivingA = 1;
11137
11138           if (!receivingA)
11139             {
11140               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11141                 {
11142                   for (offset = size-1; offset>0; offset--)
11143                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11144                   emitcode("mov","a,%s", fReturn[0]);
11145                   _G.accInUse++;
11146                   aopOp (IC_RESULT (ic), ic, FALSE);
11147                   _G.accInUse--;
11148                   aopPut (IC_RESULT (ic), "a", offset,
11149                           isOperandVolatile (IC_RESULT (ic), FALSE));
11150                   for (offset = 1; offset<size; offset++)
11151                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
11152                             isOperandVolatile (IC_RESULT (ic), FALSE));
11153                   goto release;
11154                 }
11155             }
11156           else
11157             {
11158               if (getTempRegs(tempRegs, size, ic))
11159                 {
11160                   for (offset = 0; offset<size; offset++)
11161                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11162                   aopOp (IC_RESULT (ic), ic, FALSE);
11163                   for (offset = 0; offset<size; offset++)
11164                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
11165                             isOperandVolatile (IC_RESULT (ic), FALSE));
11166                   goto release;
11167                 }
11168             }
11169
11170           offset = fReturnSizeMCS51 - size;
11171           while (size--)
11172             {
11173               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11174                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11175               offset++;
11176             }
11177           aopOp (IC_RESULT (ic), ic, FALSE);
11178           size = AOP_SIZE (IC_RESULT (ic));
11179           offset = 0;
11180           while (size--)
11181             {
11182               emitcode ("pop", "acc");
11183               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11184             }
11185         }
11186       else
11187         {
11188           _G.accInUse++;
11189           aopOp (IC_RESULT (ic), ic, FALSE);
11190           _G.accInUse--;
11191           assignResultValue (IC_RESULT (ic), NULL);
11192         }
11193     }
11194   else if (ic->argreg > 12)
11195     { /* bit parameters */
11196       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11197         {
11198           aopOp (IC_RESULT (ic), ic, FALSE);
11199           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11200           outBitC(IC_RESULT (ic));
11201         }
11202     }
11203   else
11204     { /* other parameters */
11205       int rb1off ;
11206       aopOp (IC_RESULT (ic), ic, FALSE);
11207       rb1off = ic->argreg;
11208       while (size--)
11209         {
11210           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
11211         }
11212     }
11213
11214 release:
11215   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11216 }
11217
11218 /*-----------------------------------------------------------------*/
11219 /* genDummyRead - generate code for dummy read of volatiles        */
11220 /*-----------------------------------------------------------------*/
11221 static void
11222 genDummyRead (iCode * ic)
11223 {
11224   operand *op;
11225   int size, offset;
11226
11227   D(emitcode(";     genDummyRead",""));
11228
11229   op = IC_RIGHT (ic);
11230   if (op && IS_SYMOP (op))
11231     {
11232       aopOp (op, ic, FALSE);
11233
11234       /* if the result is a bit */
11235       if (AOP_TYPE (op) == AOP_CRY)
11236         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11237       else
11238         {
11239           /* bit variables done */
11240           /* general case */
11241           size = AOP_SIZE (op);
11242           offset = 0;
11243           while (size--)
11244           {
11245             MOVA (aopGet (op, offset, FALSE, FALSE));
11246             offset++;
11247           }
11248         }
11249
11250       freeAsmop (op, NULL, ic, TRUE);
11251     }
11252
11253   op = IC_LEFT (ic);
11254   if (op && IS_SYMOP (op))
11255     {
11256       aopOp (op, ic, FALSE);
11257
11258       /* if the result is a bit */
11259       if (AOP_TYPE (op) == AOP_CRY)
11260         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11261       else
11262         {
11263           /* bit variables done */
11264           /* general case */
11265           size = AOP_SIZE (op);
11266           offset = 0;
11267           while (size--)
11268           {
11269             MOVA (aopGet (op, offset, FALSE, FALSE));
11270             offset++;
11271           }
11272         }
11273
11274       freeAsmop (op, NULL, ic, TRUE);
11275     }
11276 }
11277
11278 /*-----------------------------------------------------------------*/
11279 /* genCritical - generate code for start of a critical sequence    */
11280 /*-----------------------------------------------------------------*/
11281 static void
11282 genCritical (iCode *ic)
11283 {
11284   symbol *tlbl = newiTempLabel (NULL);
11285
11286   D(emitcode(";     genCritical",""));
11287
11288   if (IC_RESULT (ic))
11289     {
11290       aopOp (IC_RESULT (ic), ic, TRUE);
11291       aopPut (IC_RESULT (ic), one, 0, 0);
11292       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11293       aopPut (IC_RESULT (ic), zero, 0, 0);
11294       emitcode ("", "%05d$:", (tlbl->key + 100));
11295       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11296     }
11297   else
11298     {
11299       emitcode ("setb", "c");
11300       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11301       emitcode ("clr", "c");
11302       emitcode ("", "%05d$:", (tlbl->key + 100));
11303       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11304     }
11305 }
11306
11307 /*-----------------------------------------------------------------*/
11308 /* genEndCritical - generate code for end of a critical sequence   */
11309 /*-----------------------------------------------------------------*/
11310 static void
11311 genEndCritical (iCode *ic)
11312 {
11313   D(emitcode(";     genEndCritical",""));
11314
11315   if (IC_RIGHT (ic))
11316     {
11317       aopOp (IC_RIGHT (ic), ic, FALSE);
11318       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11319         {
11320           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11321           emitcode ("mov", "ea,c");
11322         }
11323       else
11324         {
11325           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11326             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11327           emitcode ("rrc", "a");
11328           emitcode ("mov", "ea,c");
11329         }
11330       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11331     }
11332   else
11333     {
11334       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11335       emitcode ("mov", "ea,c");
11336     }
11337 }
11338
11339 /*-----------------------------------------------------------------*/
11340 /* gen51Code - generate code for 8051 based controllers            */
11341 /*-----------------------------------------------------------------*/
11342 void
11343 gen51Code (iCode * lic)
11344 {
11345   iCode *ic;
11346   int cln = 0;
11347   /* int cseq = 0; */
11348
11349   _G.currentFunc = NULL;
11350   lineHead = lineCurr = NULL;
11351
11352   /* print the allocation information */
11353   if (allocInfo && currFunc)
11354     printAllocInfo (currFunc, codeOutFile);
11355   /* if debug information required */
11356   if (options.debug && currFunc)
11357     {
11358       debugFile->writeFunction (currFunc, lic);
11359     }
11360   /* stack pointer name */
11361   if (options.useXstack)
11362     spname = "_spx";
11363   else
11364     spname = "sp";
11365
11366
11367   for (ic = lic; ic; ic = ic->next)
11368     {
11369       _G.current_iCode = ic;
11370
11371       if (ic->lineno && cln != ic->lineno)
11372         {
11373           if (options.debug)
11374             {
11375               debugFile->writeCLine (ic);
11376             }
11377           if (!options.noCcodeInAsm) {
11378             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
11379                       printCLine(ic->filename, ic->lineno));
11380           }
11381           cln = ic->lineno;
11382         }
11383       #if 0
11384       if (ic->seqPoint && ic->seqPoint != cseq)
11385         {
11386           emitcode ("", "; sequence point %d", ic->seqPoint);
11387           cseq = ic->seqPoint;
11388         }
11389       #endif
11390       if (options.iCodeInAsm) {
11391         char regsInUse[80];
11392         int i;
11393
11394         for (i=0; i<8; i++) {
11395           sprintf (&regsInUse[i],
11396                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
11397         }
11398         regsInUse[i]=0;
11399         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11400       }
11401       /* if the result is marked as
11402          spilt and rematerializable or code for
11403          this has already been generated then
11404          do nothing */
11405       if (resultRemat (ic) || ic->generated)
11406         continue;
11407
11408       /* depending on the operation */
11409       switch (ic->op)
11410         {
11411         case '!':
11412           genNot (ic);
11413           break;
11414
11415         case '~':
11416           genCpl (ic);
11417           break;
11418
11419         case UNARYMINUS:
11420           genUminus (ic);
11421           break;
11422
11423         case IPUSH:
11424           genIpush (ic);
11425           break;
11426
11427         case IPOP:
11428           /* IPOP happens only when trying to restore a
11429              spilt live range, if there is an ifx statement
11430              following this pop then the if statement might
11431              be using some of the registers being popped which
11432              would destory the contents of the register so
11433              we need to check for this condition and handle it */
11434           if (ic->next &&
11435               ic->next->op == IFX &&
11436               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11437             genIfx (ic->next, ic);
11438           else
11439             genIpop (ic);
11440           break;
11441
11442         case CALL:
11443           genCall (ic);
11444           break;
11445
11446         case PCALL:
11447           genPcall (ic);
11448           break;
11449
11450         case FUNCTION:
11451           genFunction (ic);
11452           break;
11453
11454         case ENDFUNCTION:
11455           genEndFunction (ic);
11456           break;
11457
11458         case RETURN:
11459           genRet (ic);
11460           break;
11461
11462         case LABEL:
11463           genLabel (ic);
11464           break;
11465
11466         case GOTO:
11467           genGoto (ic);
11468           break;
11469
11470         case '+':
11471           genPlus (ic);
11472           break;
11473
11474         case '-':
11475           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11476             genMinus (ic);
11477           break;
11478
11479         case '*':
11480           genMult (ic);
11481           break;
11482
11483         case '/':
11484           genDiv (ic);
11485           break;
11486
11487         case '%':
11488           genMod (ic);
11489           break;
11490
11491         case '>':
11492           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11493           break;
11494
11495         case '<':
11496           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11497           break;
11498
11499         case LE_OP:
11500         case GE_OP:
11501         case NE_OP:
11502
11503           /* note these two are xlated by algebraic equivalence
11504              during parsing SDCC.y */
11505           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11506                   "got '>=' or '<=' shouldn't have come here");
11507           break;
11508
11509         case EQ_OP:
11510           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11511           break;
11512
11513         case AND_OP:
11514           genAndOp (ic);
11515           break;
11516
11517         case OR_OP:
11518           genOrOp (ic);
11519           break;
11520
11521         case '^':
11522           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11523           break;
11524
11525         case '|':
11526           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11527           break;
11528
11529         case BITWISEAND:
11530           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11531           break;
11532
11533         case INLINEASM:
11534           genInline (ic);
11535           break;
11536
11537         case RRC:
11538           genRRC (ic);
11539           break;
11540
11541         case RLC:
11542           genRLC (ic);
11543           break;
11544
11545         case GETHBIT:
11546           genGetHbit (ic);
11547           break;
11548
11549         case GETABIT:
11550           genGetAbit (ic);
11551           break;
11552
11553         case GETBYTE:
11554           genGetByte (ic);
11555           break;
11556
11557         case GETWORD:
11558           genGetWord (ic);
11559           break;
11560
11561         case LEFT_OP:
11562           genLeftShift (ic);
11563           break;
11564
11565         case RIGHT_OP:
11566           genRightShift (ic);
11567           break;
11568
11569         case GET_VALUE_AT_ADDRESS:
11570           genPointerGet (ic,
11571                          hasInc (IC_LEFT (ic), ic,
11572                                  getSize (operandType (IC_RESULT (ic)))),
11573                          ifxForOp (IC_RESULT (ic), ic) );
11574           break;
11575
11576         case '=':
11577           if (POINTER_SET (ic))
11578             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
11579           else
11580             genAssign (ic);
11581           break;
11582
11583         case IFX:
11584           genIfx (ic, NULL);
11585           break;
11586
11587         case ADDRESS_OF:
11588           genAddrOf (ic);
11589           break;
11590
11591         case JUMPTABLE:
11592           genJumpTab (ic);
11593           break;
11594
11595         case CAST:
11596           genCast (ic);
11597           break;
11598
11599         case RECEIVE:
11600           genReceive (ic);
11601           break;
11602
11603         case SEND:
11604           addSet (&_G.sendSet, ic);
11605           break;
11606
11607         case DUMMY_READ_VOLATILE:
11608           genDummyRead (ic);
11609           break;
11610
11611         case CRITICAL:
11612           genCritical (ic);
11613           break;
11614
11615         case ENDCRITICAL:
11616           genEndCritical (ic);
11617           break;
11618
11619         case SWAP:
11620           genSwap (ic);
11621           break;
11622
11623         default:
11624           ic = ic;
11625         }
11626     }
11627
11628   _G.current_iCode = NULL;
11629
11630   /* now we are ready to call the
11631      peep hole optimizer */
11632   if (!options.nopeep)
11633     peepHole (&lineHead);
11634
11635   /* now do the actual printing */
11636   printLine (lineHead, codeOutFile);
11637   return;
11638 }