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