0757d80dcbd284ecb38568a82fb079b03d7eaf10
[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               /* reverse subtraction with 2's complement */
4585               if (offset == 0)
4586                 emitcode( "setb", "c");
4587                else
4588                 emitcode( "cpl", "c");
4589               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4590               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4591               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4592               emitcode("cpl", "a");
4593               if (size) /* skip if last byte */
4594                 emitcode( "cpl", "c");
4595             }
4596           } else {
4597             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4598             if (offset == 0)
4599               CLRC;
4600             emitcode ("subb", "a,%s",
4601                       aopGet(rightOp, offset, FALSE, TRUE));
4602           }
4603
4604           aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
4605         }
4606     }
4607
4608
4609   adjustArithmeticResult (ic);
4610
4611 release:
4612   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4613   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4614   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4615 }
4616
4617
4618 /*-----------------------------------------------------------------*/
4619 /* genMultbits :- multiplication of bits                           */
4620 /*-----------------------------------------------------------------*/
4621 static void
4622 genMultbits (operand * left,
4623              operand * right,
4624              operand * result)
4625 {
4626   D(emitcode (";     genMultbits",""));
4627
4628   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4629   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4630   outBitC (result);
4631 }
4632
4633 /*-----------------------------------------------------------------*/
4634 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4635 /*-----------------------------------------------------------------*/
4636 static void
4637 genMultOneByte (operand * left,
4638                 operand * right,
4639                 operand * result)
4640 {
4641   symbol *lbl;
4642   int size = AOP_SIZE (result);
4643   bool runtimeSign, compiletimeSign;
4644   bool lUnsigned, rUnsigned, pushedB;
4645
4646   D(emitcode (";     genMultOneByte",""));
4647
4648   if (size < 1 || size > 2)
4649     {
4650       /* this should never happen */
4651       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4652                AOP_SIZE(result), __FILE__, lineno);
4653       exit (1);
4654     }
4655
4656   /* (if two literals: the value is computed before) */
4657   /* if one literal, literal on the right */
4658   if (AOP_TYPE (left) == AOP_LIT)
4659     {
4660       operand *t = right;
4661       right = left;
4662       left = t;
4663       /* emitcode (";", "swapped left and right"); */
4664     }
4665   /* if no literal, unsigned on the right: shorter code */
4666   if (   AOP_TYPE (right) != AOP_LIT
4667       && SPEC_USIGN (getSpec (operandType (left))))
4668     {
4669       operand *t = right;
4670       right = left;
4671       left = t;
4672     }
4673
4674   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4675   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4676
4677   pushedB = pushB ();
4678
4679   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4680                    no need to take care about the signedness! */
4681       || (lUnsigned && rUnsigned))
4682     {
4683       /* just an unsigned 8 * 8 = 8 multiply
4684          or 8u * 8u = 16u */
4685       /* emitcode (";","unsigned"); */
4686       /* TODO: check for accumulator clash between left & right aops? */
4687
4688       if (AOP_TYPE (right) == AOP_LIT)
4689         {
4690           /* moving to accumulator first helps peepholes */
4691           MOVA (aopGet (left, 0, FALSE, FALSE));
4692           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4693         }
4694       else
4695         {
4696           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4697           MOVA (aopGet (left, 0, FALSE, FALSE));
4698         }
4699
4700       emitcode ("mul", "ab");
4701       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4702       if (size == 2)
4703         aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4704
4705       popB (pushedB);
4706       return;
4707     }
4708
4709   /* we have to do a signed multiply */
4710   /* emitcode (";", "signed"); */
4711
4712   /* now sign adjust for both left & right */
4713
4714   /* let's see what's needed: */
4715   /* apply negative sign during runtime */
4716   runtimeSign = FALSE;
4717   /* negative sign from literals */
4718   compiletimeSign = FALSE;
4719
4720   if (!lUnsigned)
4721     {
4722       if (AOP_TYPE(left) == AOP_LIT)
4723         {
4724           /* signed literal */
4725           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4726           if (val < 0)
4727             compiletimeSign = TRUE;
4728         }
4729       else
4730         /* signed but not literal */
4731         runtimeSign = TRUE;
4732     }
4733
4734   if (!rUnsigned)
4735     {
4736       if (AOP_TYPE(right) == AOP_LIT)
4737         {
4738           /* signed literal */
4739           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4740           if (val < 0)
4741             compiletimeSign ^= TRUE;
4742         }
4743       else
4744         /* signed but not literal */
4745         runtimeSign = TRUE;
4746     }
4747
4748   /* initialize F0, which stores the runtime sign */
4749   if (runtimeSign)
4750     {
4751       if (compiletimeSign)
4752         emitcode ("setb", "F0"); /* set sign flag */
4753       else
4754         emitcode ("clr", "F0"); /* reset sign flag */
4755     }
4756
4757   /* save the signs of the operands */
4758   if (AOP_TYPE(right) == AOP_LIT)
4759     {
4760       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4761
4762       if (!rUnsigned && val < 0)
4763         emitcode ("mov", "b,#0x%02x", -val);
4764       else
4765         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
4766     }
4767   else /* ! literal */
4768     {
4769       if (rUnsigned)  /* emitcode (";", "signed"); */
4770
4771         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4772       else
4773         {
4774           MOVA (aopGet (right, 0, FALSE, FALSE));
4775           lbl = newiTempLabel (NULL);
4776           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4777           emitcode ("cpl", "F0"); /* complement sign flag */
4778           emitcode ("cpl", "a");  /* 2's complement */
4779           emitcode ("inc", "a");
4780           emitcode ("", "%05d$:", (lbl->key + 100));
4781           emitcode ("mov", "b,a");
4782         }
4783     }
4784
4785   if (AOP_TYPE(left) == AOP_LIT)
4786     {
4787       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4788
4789       if (!lUnsigned && val < 0)
4790         emitcode ("mov", "a,#0x%02x", -val);
4791       else
4792         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
4793     }
4794   else /* ! literal */
4795     {
4796       MOVA (aopGet (left, 0, FALSE, FALSE));
4797
4798       if (!lUnsigned)
4799         {
4800           lbl = newiTempLabel (NULL);
4801           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
4802           emitcode ("cpl", "F0"); /* complement sign flag */
4803           emitcode ("cpl", "a"); /* 2's complement */
4804           emitcode ("inc", "a");
4805           emitcode ("", "%05d$:", (lbl->key + 100));
4806         }
4807     }
4808
4809   /* now the multiplication */
4810   emitcode ("mul", "ab");
4811   if (runtimeSign || compiletimeSign)
4812     {
4813       lbl = newiTempLabel (NULL);
4814       if (runtimeSign)
4815         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
4816       emitcode ("cpl", "a"); /* lsb 2's complement */
4817       if (size != 2)
4818         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4819       else
4820         {
4821           emitcode ("add", "a,#1"); /* this sets carry flag */
4822           emitcode ("xch", "a,b");
4823           emitcode ("cpl", "a"); /* msb 2's complement */
4824           emitcode ("addc", "a,#0");
4825           emitcode ("xch", "a,b");
4826         }
4827       emitcode ("", "%05d$:", (lbl->key + 100));
4828     }
4829   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4830   if (size == 2)
4831     aopPut (result, "b", 1, isOperandVolatile (result, FALSE));
4832
4833   popB (pushedB);
4834 }
4835
4836 /*-----------------------------------------------------------------*/
4837 /* genMult - generates code for multiplication                     */
4838 /*-----------------------------------------------------------------*/
4839 static void
4840 genMult (iCode * ic)
4841 {
4842   operand *left = IC_LEFT (ic);
4843   operand *right = IC_RIGHT (ic);
4844   operand *result = IC_RESULT (ic);
4845
4846   D(emitcode (";     genMult",""));
4847
4848   /* assign the amsops */
4849   aopOp (left, ic, FALSE);
4850   aopOp (right, ic, FALSE);
4851   aopOp (result, ic, TRUE);
4852
4853   /* special cases first */
4854   /* both are bits */
4855   if (AOP_TYPE (left) == AOP_CRY &&
4856       AOP_TYPE (right) == AOP_CRY)
4857     {
4858       genMultbits (left, right, result);
4859       goto release;
4860     }
4861
4862   /* if both are of size == 1 */
4863 #if 0 // one of them can be a sloc shared with the result
4864     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
4865 #else
4866   if (getSize(operandType(left)) == 1 &&
4867       getSize(operandType(right)) == 1)
4868 #endif
4869     {
4870       genMultOneByte (left, right, result);
4871       goto release;
4872     }
4873
4874   /* should have been converted to function call */
4875     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
4876              getSize(OP_SYMBOL(right)->type));
4877   assert (0);
4878
4879 release:
4880   freeAsmop (result, NULL, ic, TRUE);
4881   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4882   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4883 }
4884
4885 /*-----------------------------------------------------------------*/
4886 /* genDivbits :- division of bits                                  */
4887 /*-----------------------------------------------------------------*/
4888 static void
4889 genDivbits (operand * left,
4890             operand * right,
4891             operand * result)
4892 {
4893   char *l;
4894   bool pushedB;
4895
4896   D(emitcode (";     genDivbits",""));
4897
4898   pushedB = pushB ();
4899
4900   /* the result must be bit */
4901   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4902   l = aopGet (left, 0, FALSE, FALSE);
4903
4904   MOVA (l);
4905
4906   emitcode ("div", "ab");
4907   emitcode ("rrc", "a");
4908
4909   popB (pushedB);
4910
4911   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
4912 }
4913
4914 /*-----------------------------------------------------------------*/
4915 /* genDivOneByte : 8 bit division                                  */
4916 /*-----------------------------------------------------------------*/
4917 static void
4918 genDivOneByte (operand * left,
4919                operand * right,
4920                operand * result)
4921 {
4922   bool lUnsigned, rUnsigned, pushedB;
4923   bool runtimeSign, compiletimeSign;
4924   symbol *lbl;
4925   int size, offset;
4926
4927   D(emitcode (";     genDivOneByte",""));
4928
4929   /* Why is it necessary that genDivOneByte() can return an int result?
4930      Have a look at:
4931
4932         volatile unsigned char uc;
4933         volatile signed char sc1, sc2;
4934         volatile int i;
4935
4936         uc  = 255;
4937         sc1 = -1;
4938         i = uc / sc1;
4939
4940      Or:
4941
4942         sc1 = -128;
4943         sc2 = -1;
4944         i = sc1 / sc2;
4945
4946      In all cases a one byte result would overflow, the following cast to int
4947      would return the wrong result.
4948
4949      Two possible solution:
4950         a) cast operands to int, if ((unsigned) / (signed)) or
4951            ((signed) / (signed))
4952         b) return an 16 bit signed int; this is what we're doing here!
4953   */
4954
4955   size = AOP_SIZE (result) - 1;
4956   offset = 1;
4957   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4958   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4959
4960   pushedB = pushB ();
4961
4962   /* signed or unsigned */
4963   if (lUnsigned && rUnsigned)
4964     {
4965       /* unsigned is easy */
4966       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4967       MOVA (aopGet (left, 0, FALSE, FALSE));
4968       emitcode ("div", "ab");
4969       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
4970       while (size--)
4971         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
4972
4973       popB (pushedB);
4974       return;
4975     }
4976
4977   /* signed is a little bit more difficult */
4978
4979   /* now sign adjust for both left & right */
4980
4981   /* let's see what's needed: */
4982   /* apply negative sign during runtime */
4983   runtimeSign = FALSE;
4984   /* negative sign from literals */
4985   compiletimeSign = FALSE;
4986
4987   if (!lUnsigned)
4988     {
4989       if (AOP_TYPE(left) == AOP_LIT)
4990         {
4991           /* signed literal */
4992           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4993           if (val < 0)
4994             compiletimeSign = TRUE;
4995         }
4996       else
4997         /* signed but not literal */
4998         runtimeSign = TRUE;
4999     }
5000
5001   if (!rUnsigned)
5002     {
5003       if (AOP_TYPE(right) == AOP_LIT)
5004         {
5005           /* signed literal */
5006           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5007           if (val < 0)
5008             compiletimeSign ^= TRUE;
5009         }
5010       else
5011         /* signed but not literal */
5012         runtimeSign = TRUE;
5013     }
5014
5015   /* initialize F0, which stores the runtime sign */
5016   if (runtimeSign)
5017     {
5018       if (compiletimeSign)
5019         emitcode ("setb", "F0"); /* set sign flag */
5020       else
5021         emitcode ("clr", "F0"); /* reset sign flag */
5022     }
5023
5024   /* save the signs of the operands */
5025   if (AOP_TYPE(right) == AOP_LIT)
5026     {
5027       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5028
5029       if (!rUnsigned && val < 0)
5030         emitcode ("mov", "b,#0x%02x", -val);
5031       else
5032         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5033     }
5034   else /* ! literal */
5035     {
5036       if (rUnsigned)
5037         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5038       else
5039         {
5040           MOVA (aopGet (right, 0, FALSE, FALSE));
5041           lbl = newiTempLabel (NULL);
5042           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5043           emitcode ("cpl", "F0"); /* complement sign flag */
5044           emitcode ("cpl", "a");  /* 2's complement */
5045           emitcode ("inc", "a");
5046           emitcode ("", "%05d$:", (lbl->key + 100));
5047           emitcode ("mov", "b,a");
5048         }
5049     }
5050
5051   if (AOP_TYPE(left) == AOP_LIT)
5052     {
5053       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5054
5055       if (!lUnsigned && val < 0)
5056         emitcode ("mov", "a,#0x%02x", -val);
5057       else
5058         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5059     }
5060   else /* ! literal */
5061     {
5062       MOVA (aopGet (left, 0, FALSE, FALSE));
5063
5064       if (!lUnsigned)
5065         {
5066           lbl = newiTempLabel (NULL);
5067           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5068           emitcode ("cpl", "F0"); /* complement sign flag */
5069           emitcode ("cpl", "a");  /* 2's complement */
5070           emitcode ("inc", "a");
5071           emitcode ("", "%05d$:", (lbl->key + 100));
5072         }
5073     }
5074
5075   /* now the division */
5076   emitcode ("div", "ab");
5077
5078   if (runtimeSign || compiletimeSign)
5079     {
5080       lbl = newiTempLabel (NULL);
5081       if (runtimeSign)
5082         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5083       emitcode ("cpl", "a"); /* lsb 2's complement */
5084       emitcode ("inc", "a");
5085       emitcode ("", "%05d$:", (lbl->key + 100));
5086
5087       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5088       if (size > 0)
5089         {
5090           /* msb is 0x00 or 0xff depending on the sign */
5091           if (runtimeSign)
5092             {
5093               emitcode ("mov", "c,F0");
5094               emitcode ("subb", "a,acc");
5095               while (size--)
5096                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5097             }
5098           else /* compiletimeSign */
5099             while (size--)
5100               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5101         }
5102     }
5103   else
5104     {
5105       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5106       while (size--)
5107         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5108     }
5109
5110   popB (pushedB);
5111 }
5112
5113 /*-----------------------------------------------------------------*/
5114 /* genDiv - generates code for division                            */
5115 /*-----------------------------------------------------------------*/
5116 static void
5117 genDiv (iCode * ic)
5118 {
5119   operand *left = IC_LEFT (ic);
5120   operand *right = IC_RIGHT (ic);
5121   operand *result = IC_RESULT (ic);
5122
5123   D(emitcode (";     genDiv",""));
5124
5125   /* assign the amsops */
5126   aopOp (left, ic, FALSE);
5127   aopOp (right, ic, FALSE);
5128   aopOp (result, ic, TRUE);
5129
5130   /* special cases first */
5131   /* both are bits */
5132   if (AOP_TYPE (left) == AOP_CRY &&
5133       AOP_TYPE (right) == AOP_CRY)
5134     {
5135       genDivbits (left, right, result);
5136       goto release;
5137     }
5138
5139   /* if both are of size == 1 */
5140   if (AOP_SIZE (left) == 1 &&
5141       AOP_SIZE (right) == 1)
5142     {
5143       genDivOneByte (left, right, result);
5144       goto release;
5145     }
5146
5147   /* should have been converted to function call */
5148   assert (0);
5149 release:
5150   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5151   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5152   freeAsmop (result, NULL, ic, TRUE);
5153 }
5154
5155 /*-----------------------------------------------------------------*/
5156 /* genModbits :- modulus of bits                                   */
5157 /*-----------------------------------------------------------------*/
5158 static void
5159 genModbits (operand * left,
5160             operand * right,
5161             operand * result)
5162 {
5163   char *l;
5164   bool pushedB;
5165
5166   D(emitcode (";     genModbits",""));
5167
5168   pushedB = pushB ();
5169
5170   /* the result must be bit */
5171   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5172   l = aopGet (left, 0, FALSE, FALSE);
5173
5174   MOVA (l);
5175
5176   emitcode ("div", "ab");
5177   emitcode ("mov", "a,b");
5178   emitcode ("rrc", "a");
5179
5180   popB (pushedB);
5181
5182   aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
5183 }
5184
5185 /*-----------------------------------------------------------------*/
5186 /* genModOneByte : 8 bit modulus                                   */
5187 /*-----------------------------------------------------------------*/
5188 static void
5189 genModOneByte (operand * left,
5190                operand * right,
5191                operand * result)
5192 {
5193   bool lUnsigned, rUnsigned, pushedB;
5194   bool runtimeSign, compiletimeSign;
5195   symbol *lbl;
5196   int size, offset;
5197
5198   D(emitcode (";     genModOneByte",""));
5199
5200   size = AOP_SIZE (result) - 1;
5201   offset = 1;
5202   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5203   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5204
5205   /* if right is a literal, check it for 2^n */
5206   if (AOP_TYPE(right) == AOP_LIT)
5207     {
5208       unsigned char val = abs((int) operandLitValue(right));
5209       symbol *lbl2 = NULL;
5210
5211       switch (val)
5212         {
5213           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5214           case 2:
5215           case 4:
5216           case 8:
5217           case 16:
5218           case 32:
5219           case 64:
5220           case 128:
5221             if (lUnsigned)
5222               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5223                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5224               /* because iCode should have been changed to genAnd  */
5225               /* see file "SDCCopt.c", function "convertToFcall()" */
5226
5227             MOVA (aopGet (left, 0, FALSE, FALSE));
5228             emitcode ("mov", "c,acc.7");
5229             emitcode ("anl", "a,#0x%02x", val - 1);
5230             lbl = newiTempLabel (NULL);
5231             emitcode ("jz", "%05d$", (lbl->key + 100));
5232             emitcode ("jnc", "%05d$", (lbl->key + 100));
5233             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5234             if (size)
5235               {
5236                 int size2 = size;
5237                 int offs2 = offset;
5238
5239                 aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5240                 while (size2--)
5241                   aopPut (result, "#0xff", offs2++, isOperandVolatile (result, FALSE));
5242                 lbl2 = newiTempLabel (NULL);
5243                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5244               }
5245             emitcode ("", "%05d$:", (lbl->key + 100));
5246             aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5247             while (size--)
5248               aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5249             if (lbl2)
5250               {
5251                 emitcode ("", "%05d$:", (lbl2->key + 100));
5252               }
5253             return;
5254
5255           default:
5256             break;
5257         }
5258     }
5259
5260   pushedB = pushB ();
5261
5262   /* signed or unsigned */
5263   if (lUnsigned && rUnsigned)
5264     {
5265       /* unsigned is easy */
5266       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5267       MOVA (aopGet (left, 0, FALSE, FALSE));
5268       emitcode ("div", "ab");
5269       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5270       while (size--)
5271         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5272
5273       popB (pushedB);
5274       return;
5275     }
5276
5277   /* signed is a little bit more difficult */
5278
5279   /* now sign adjust for both left & right */
5280
5281   /* modulus: sign of the right operand has no influence on the result! */
5282   if (AOP_TYPE(right) == AOP_LIT)
5283     {
5284       signed char val = (char) operandLitValue(right);
5285
5286       if (!rUnsigned && val < 0)
5287         emitcode ("mov", "b,#0x%02x", -val);
5288       else
5289         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5290     }
5291   else /* not literal */
5292     {
5293       if (rUnsigned)
5294         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5295       else
5296         {
5297           MOVA (aopGet (right, 0, FALSE, FALSE));
5298           lbl = newiTempLabel (NULL);
5299           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5300           emitcode ("cpl", "a"); /* 2's complement */
5301           emitcode ("inc", "a");
5302           emitcode ("", "%05d$:", (lbl->key + 100));
5303           emitcode ("mov", "b,a");
5304         }
5305     }
5306
5307   /* let's see what's needed: */
5308   /* apply negative sign during runtime */
5309   runtimeSign = FALSE;
5310   /* negative sign from literals */
5311   compiletimeSign = FALSE;
5312
5313   /* sign adjust left side */
5314   if (AOP_TYPE(left) == AOP_LIT)
5315     {
5316       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5317
5318       if (!lUnsigned && val < 0)
5319         {
5320           compiletimeSign = TRUE; /* set sign flag */
5321           emitcode ("mov", "a,#0x%02x", -val);
5322         }
5323       else
5324         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5325     }
5326   else /* ! literal */
5327     {
5328       MOVA (aopGet (left, 0, FALSE, FALSE));
5329
5330       if (!lUnsigned)
5331         {
5332           runtimeSign = TRUE;
5333           emitcode ("clr", "F0"); /* clear sign flag */
5334
5335           lbl = newiTempLabel (NULL);
5336           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5337           emitcode ("setb", "F0"); /* set sign flag */
5338           emitcode ("cpl", "a");   /* 2's complement */
5339           emitcode ("inc", "a");
5340           emitcode ("", "%05d$:", (lbl->key + 100));
5341         }
5342     }
5343
5344   /* now the modulus */
5345   emitcode ("div", "ab");
5346
5347   if (runtimeSign || compiletimeSign)
5348     {
5349       emitcode ("mov", "a,b");
5350       lbl = newiTempLabel (NULL);
5351       if (runtimeSign)
5352         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5353       emitcode ("cpl", "a"); /* 2's complement */
5354       emitcode ("inc", "a");
5355       emitcode ("", "%05d$:", (lbl->key + 100));
5356
5357       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5358       if (size > 0)
5359         {
5360           /* msb is 0x00 or 0xff depending on the sign */
5361           if (runtimeSign)
5362             {
5363               emitcode ("mov", "c,F0");
5364               emitcode ("subb", "a,acc");
5365               while (size--)
5366                 aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
5367             }
5368           else /* compiletimeSign */
5369             while (size--)
5370               aopPut (result, "#0xff", offset++, isOperandVolatile (result, FALSE));
5371         }
5372     }
5373   else
5374     {
5375       aopPut (result, "b", 0, isOperandVolatile (result, FALSE));
5376       while (size--)
5377         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
5378     }
5379
5380   popB (pushedB);
5381 }
5382
5383 /*-----------------------------------------------------------------*/
5384 /* genMod - generates code for division                            */
5385 /*-----------------------------------------------------------------*/
5386 static void
5387 genMod (iCode * ic)
5388 {
5389   operand *left = IC_LEFT (ic);
5390   operand *right = IC_RIGHT (ic);
5391   operand *result = IC_RESULT (ic);
5392
5393   D(emitcode (";     genMod",""));
5394
5395   /* assign the asmops */
5396   aopOp (left, ic, FALSE);
5397   aopOp (right, ic, FALSE);
5398   aopOp (result, ic, TRUE);
5399
5400   /* special cases first */
5401   /* both are bits */
5402   if (AOP_TYPE (left) == AOP_CRY &&
5403       AOP_TYPE (right) == AOP_CRY)
5404     {
5405       genModbits (left, right, result);
5406       goto release;
5407     }
5408
5409   /* if both are of size == 1 */
5410   if (AOP_SIZE (left) == 1 &&
5411       AOP_SIZE (right) == 1)
5412     {
5413       genModOneByte (left, right, result);
5414       goto release;
5415     }
5416
5417   /* should have been converted to function call */
5418   assert (0);
5419
5420 release:
5421   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5422   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5423   freeAsmop (result, NULL, ic, TRUE);
5424 }
5425
5426 /*-----------------------------------------------------------------*/
5427 /* genIfxJump :- will create a jump depending on the ifx           */
5428 /*-----------------------------------------------------------------*/
5429 static void
5430 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5431 {
5432   symbol *jlbl;
5433   symbol *tlbl = newiTempLabel (NULL);
5434   char *inst;
5435
5436   D(emitcode (";     genIfxJump",""));
5437
5438   /* if true label then we jump if condition
5439      supplied is true */
5440   if (IC_TRUE (ic))
5441     {
5442       jlbl = IC_TRUE (ic);
5443       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5444                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5445     }
5446   else
5447     {
5448       /* false label is present */
5449       jlbl = IC_FALSE (ic);
5450       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5451                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5452     }
5453   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5454     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5455   else
5456     emitcode (inst, "%05d$", tlbl->key + 100);
5457   freeForBranchAsmop (result);
5458   freeForBranchAsmop (right);
5459   freeForBranchAsmop (left);
5460   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5461   emitcode ("", "%05d$:", tlbl->key + 100);
5462
5463   /* mark the icode as generated */
5464   ic->generated = 1;
5465 }
5466
5467 /*-----------------------------------------------------------------*/
5468 /* genCmp :- greater or less than comparison                       */
5469 /*-----------------------------------------------------------------*/
5470 static void
5471 genCmp (operand * left, operand * right,
5472         operand * result, iCode * ifx, int sign, iCode *ic)
5473 {
5474   int size, offset = 0;
5475   unsigned long lit = 0L;
5476   bool rightInB;
5477
5478   D(emitcode (";     genCmp",""));
5479
5480   /* if left & right are bit variables */
5481   if (AOP_TYPE (left) == AOP_CRY &&
5482       AOP_TYPE (right) == AOP_CRY)
5483     {
5484       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5485       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5486     }
5487   else
5488     {
5489       /* subtract right from left if at the
5490          end the carry flag is set then we know that
5491          left is greater than right */
5492       size = max (AOP_SIZE (left), AOP_SIZE (right));
5493
5494       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5495       if ((size == 1) && !sign &&
5496           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5497         {
5498           symbol *lbl = newiTempLabel (NULL);
5499           emitcode ("cjne", "%s,%s,%05d$",
5500                     aopGet (left, offset, FALSE, FALSE),
5501                     aopGet (right, offset, FALSE, FALSE),
5502                     lbl->key + 100);
5503           emitcode ("", "%05d$:", lbl->key + 100);
5504         }
5505       else
5506         {
5507           if (AOP_TYPE (right) == AOP_LIT)
5508             {
5509               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5510               /* optimize if(x < 0) or if(x >= 0) */
5511               if (lit == 0L)
5512                 {
5513                   if (!sign)
5514                     {
5515                       CLRC;
5516                     }
5517                   else
5518                     {
5519                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5520                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5521                         {
5522                           genIfxJump (ifx, "acc.7", left, right, result);
5523                           freeAsmop (right, NULL, ic, TRUE);
5524                           freeAsmop (left, NULL, ic, TRUE);
5525
5526                           return;
5527                         }
5528                       else
5529                         emitcode ("rlc", "a");
5530                     }
5531                   goto release;
5532                 }
5533             }
5534           CLRC;
5535           while (size--)
5536             {
5537               bool pushedB = FALSE;
5538               rightInB = aopGetUsesAcc(right, offset);
5539               if (rightInB)
5540                 {
5541                   pushedB = pushB ();
5542                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5543                 }
5544               MOVA (aopGet (left, offset, FALSE, FALSE));
5545               if (sign && size == 0)
5546                 {
5547                   emitcode ("xrl", "a,#0x80");
5548                   if (AOP_TYPE (right) == AOP_LIT)
5549                     {
5550                       unsigned long lit = (unsigned long)
5551                       floatFromVal (AOP (right)->aopu.aop_lit);
5552                       emitcode ("subb", "a,#0x%02x",
5553                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5554                     }
5555                   else
5556                     {
5557                       if (!rightInB)
5558                         {
5559                           pushedB = pushB ();
5560                           rightInB++;
5561                           emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5562                         }
5563                       emitcode ("xrl", "b,#0x80");
5564                       emitcode ("subb", "a,b");
5565                     }
5566                 }
5567               else
5568                 {
5569                   if (rightInB)
5570                     emitcode ("subb", "a,b");
5571                   else
5572                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5573                 }
5574               if (rightInB)
5575                 popB (pushedB);
5576               offset++;
5577             }
5578         }
5579     }
5580
5581 release:
5582   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5583   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5584   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5585     {
5586       outBitC (result);
5587     }
5588   else
5589     {
5590       /* if the result is used in the next
5591          ifx conditional branch then generate
5592          code a little differently */
5593       if (ifx)
5594         genIfxJump (ifx, "c", NULL, NULL, result);
5595       else
5596         outBitC (result);
5597       /* leave the result in acc */
5598     }
5599 }
5600
5601 /*-----------------------------------------------------------------*/
5602 /* genCmpGt :- greater than comparison                             */
5603 /*-----------------------------------------------------------------*/
5604 static void
5605 genCmpGt (iCode * ic, iCode * ifx)
5606 {
5607   operand *left, *right, *result;
5608   sym_link *letype, *retype;
5609   int sign;
5610
5611   D(emitcode (";     genCmpGt",""));
5612
5613   left = IC_LEFT (ic);
5614   right = IC_RIGHT (ic);
5615   result = IC_RESULT (ic);
5616
5617   letype = getSpec (operandType (left));
5618   retype = getSpec (operandType (right));
5619   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5620            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5621   /* assign the amsops */
5622   aopOp (left, ic, FALSE);
5623   aopOp (right, ic, FALSE);
5624   aopOp (result, ic, TRUE);
5625
5626   genCmp (right, left, result, ifx, sign, ic);
5627
5628   freeAsmop (result, NULL, ic, TRUE);
5629 }
5630
5631 /*-----------------------------------------------------------------*/
5632 /* genCmpLt - less than comparisons                                */
5633 /*-----------------------------------------------------------------*/
5634 static void
5635 genCmpLt (iCode * ic, iCode * ifx)
5636 {
5637   operand *left, *right, *result;
5638   sym_link *letype, *retype;
5639   int sign;
5640
5641   D(emitcode (";     genCmpLt",""));
5642
5643   left = IC_LEFT (ic);
5644   right = IC_RIGHT (ic);
5645   result = IC_RESULT (ic);
5646
5647   letype = getSpec (operandType (left));
5648   retype = getSpec (operandType (right));
5649   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5650            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5651   /* assign the amsops */
5652   aopOp (left, ic, FALSE);
5653   aopOp (right, ic, FALSE);
5654   aopOp (result, ic, TRUE);
5655
5656   genCmp (left, right, result, ifx, sign, ic);
5657
5658   freeAsmop (result, NULL, ic, TRUE);
5659 }
5660
5661 /*-----------------------------------------------------------------*/
5662 /* gencjneshort - compare and jump if not equal                    */
5663 /*-----------------------------------------------------------------*/
5664 static void
5665 gencjneshort (operand * left, operand * right, symbol * lbl)
5666 {
5667   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5668   int offset = 0;
5669   unsigned long lit = 0L;
5670
5671   /* if the left side is a literal or
5672      if the right is in a pointer register and left
5673      is not */
5674   if ((AOP_TYPE (left) == AOP_LIT) ||
5675       (AOP_TYPE (left) == AOP_IMMD) ||
5676       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5677     {
5678       operand *t = right;
5679       right = left;
5680       left = t;
5681     }
5682
5683   if (AOP_TYPE (right) == AOP_LIT)
5684     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5685
5686   /* if the right side is a literal then anything goes */
5687   if (AOP_TYPE (right) == AOP_LIT &&
5688       AOP_TYPE (left) != AOP_DIR  &&
5689       AOP_TYPE (left) != AOP_IMMD)
5690     {
5691       while (size--)
5692         {
5693           emitcode ("cjne", "%s,%s,%05d$",
5694                     aopGet (left, offset, FALSE, FALSE),
5695                     aopGet (right, offset, FALSE, FALSE),
5696                     lbl->key + 100);
5697           offset++;
5698         }
5699     }
5700
5701   /* if the right side is in a register or in direct space or
5702      if the left is a pointer register & right is not */
5703   else if (AOP_TYPE (right) == AOP_REG ||
5704            AOP_TYPE (right) == AOP_DIR ||
5705            AOP_TYPE (right) == AOP_LIT ||
5706            AOP_TYPE (right) == AOP_IMMD ||
5707            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
5708            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
5709     {
5710       while (size--)
5711         {
5712           MOVA (aopGet (left, offset, FALSE, FALSE));
5713           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
5714               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
5715             emitcode ("jnz", "%05d$", lbl->key + 100);
5716           else
5717             emitcode ("cjne", "a,%s,%05d$",
5718                       aopGet (right, offset, FALSE, TRUE),
5719                       lbl->key + 100);
5720           offset++;
5721         }
5722     }
5723   else
5724     {
5725       /* right is a pointer reg need both a & b */
5726       while (size--)
5727         {
5728           char *l;
5729           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
5730           wassertl(!BINUSE, "B was in use");
5731           l = aopGet (left, offset, FALSE, FALSE);
5732           if (strcmp (l, "b"))
5733             emitcode ("mov", "b,%s", l);
5734           MOVA (aopGet (right, offset, FALSE, FALSE));
5735           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
5736           offset++;
5737         }
5738     }
5739 }
5740
5741 /*-----------------------------------------------------------------*/
5742 /* gencjne - compare and jump if not equal                         */
5743 /*-----------------------------------------------------------------*/
5744 static void
5745 gencjne (operand * left, operand * right, symbol * lbl)
5746 {
5747   symbol *tlbl = newiTempLabel (NULL);
5748
5749   gencjneshort (left, right, lbl);
5750
5751   emitcode ("mov", "a,%s", one);
5752   emitcode ("sjmp", "%05d$", tlbl->key + 100);
5753   emitcode ("", "%05d$:", lbl->key + 100);
5754   emitcode ("clr", "a");
5755   emitcode ("", "%05d$:", tlbl->key + 100);
5756 }
5757
5758 /*-----------------------------------------------------------------*/
5759 /* genCmpEq - generates code for equal to                          */
5760 /*-----------------------------------------------------------------*/
5761 static void
5762 genCmpEq (iCode * ic, iCode * ifx)
5763 {
5764   operand *left, *right, *result;
5765
5766   D(emitcode (";     genCmpEq",""));
5767
5768   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
5769   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
5770   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
5771
5772   /* if literal, literal on the right or
5773      if the right is in a pointer register and left
5774      is not */
5775   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
5776       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
5777     {
5778       operand *t = IC_RIGHT (ic);
5779       IC_RIGHT (ic) = IC_LEFT (ic);
5780       IC_LEFT (ic) = t;
5781     }
5782
5783   if (ifx && !AOP_SIZE (result))
5784     {
5785       symbol *tlbl;
5786       /* if they are both bit variables */
5787       if (AOP_TYPE (left) == AOP_CRY &&
5788           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5789         {
5790           if (AOP_TYPE (right) == AOP_LIT)
5791             {
5792               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5793               if (lit == 0L)
5794                 {
5795                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5796                   emitcode ("cpl", "c");
5797                 }
5798               else if (lit == 1L)
5799                 {
5800                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5801                 }
5802               else
5803                 {
5804                   emitcode ("clr", "c");
5805                 }
5806               /* AOP_TYPE(right) == AOP_CRY */
5807             }
5808           else
5809             {
5810               symbol *lbl = newiTempLabel (NULL);
5811               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5812               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5813               emitcode ("cpl", "c");
5814               emitcode ("", "%05d$:", (lbl->key + 100));
5815             }
5816           /* if true label then we jump if condition
5817              supplied is true */
5818           tlbl = newiTempLabel (NULL);
5819           if (IC_TRUE (ifx))
5820             {
5821               emitcode ("jnc", "%05d$", tlbl->key + 100);
5822               freeForBranchAsmop (result);
5823               freeForBranchAsmop (right);
5824               freeForBranchAsmop (left);
5825               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5826             }
5827           else
5828             {
5829               emitcode ("jc", "%05d$", tlbl->key + 100);
5830               freeForBranchAsmop (result);
5831               freeForBranchAsmop (right);
5832               freeForBranchAsmop (left);
5833               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5834             }
5835           emitcode ("", "%05d$:", tlbl->key + 100);
5836         }
5837       else
5838         {
5839           tlbl = newiTempLabel (NULL);
5840           gencjneshort (left, right, tlbl);
5841           if (IC_TRUE (ifx))
5842             {
5843               freeForBranchAsmop (result);
5844               freeForBranchAsmop (right);
5845               freeForBranchAsmop (left);
5846               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
5847               emitcode ("", "%05d$:", tlbl->key + 100);
5848             }
5849           else
5850             {
5851               symbol *lbl = newiTempLabel (NULL);
5852               emitcode ("sjmp", "%05d$", lbl->key + 100);
5853               emitcode ("", "%05d$:", tlbl->key + 100);
5854               freeForBranchAsmop (result);
5855               freeForBranchAsmop (right);
5856               freeForBranchAsmop (left);
5857               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
5858               emitcode ("", "%05d$:", lbl->key + 100);
5859             }
5860         }
5861       /* mark the icode as generated */
5862       ifx->generated = 1;
5863       goto release;
5864     }
5865
5866   /* if they are both bit variables */
5867   if (AOP_TYPE (left) == AOP_CRY &&
5868       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
5869     {
5870       if (AOP_TYPE (right) == AOP_LIT)
5871         {
5872           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5873           if (lit == 0L)
5874             {
5875               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5876               emitcode ("cpl", "c");
5877             }
5878           else if (lit == 1L)
5879             {
5880               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5881             }
5882           else
5883             {
5884               emitcode ("clr", "c");
5885             }
5886           /* AOP_TYPE(right) == AOP_CRY */
5887         }
5888       else
5889         {
5890           symbol *lbl = newiTempLabel (NULL);
5891           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5892           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
5893           emitcode ("cpl", "c");
5894           emitcode ("", "%05d$:", (lbl->key + 100));
5895         }
5896       /* c = 1 if egal */
5897       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5898         {
5899           outBitC (result);
5900           goto release;
5901         }
5902       if (ifx)
5903         {
5904           genIfxJump (ifx, "c", left, right, result);
5905           goto release;
5906         }
5907       /* if the result is used in an arithmetic operation
5908          then put the result in place */
5909       outBitC (result);
5910     }
5911   else
5912     {
5913       gencjne (left, right, newiTempLabel (NULL));
5914       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5915         {
5916           aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
5917           goto release;
5918         }
5919       if (ifx)
5920         {
5921           genIfxJump (ifx, "a", left, right, result);
5922           goto release;
5923         }
5924       /* if the result is used in an arithmetic operation
5925          then put the result in place */
5926       if (AOP_TYPE (result) != AOP_CRY)
5927         outAcc (result);
5928       /* leave the result in acc */
5929     }
5930
5931 release:
5932   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5933   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5934   freeAsmop (result, NULL, ic, TRUE);
5935 }
5936
5937 /*-----------------------------------------------------------------*/
5938 /* ifxForOp - returns the icode containing the ifx for operand     */
5939 /*-----------------------------------------------------------------*/
5940 static iCode *
5941 ifxForOp (operand * op, iCode * ic)
5942 {
5943   /* if true symbol then needs to be assigned */
5944   if (IS_TRUE_SYMOP (op))
5945     return NULL;
5946
5947   /* if this has register type condition and
5948      the next instruction is ifx with the same operand
5949      and live to of the operand is upto the ifx only then */
5950   if (ic->next &&
5951       ic->next->op == IFX &&
5952       IC_COND (ic->next)->key == op->key &&
5953       OP_SYMBOL (op)->liveTo <= ic->next->seq)
5954     return ic->next;
5955
5956   return NULL;
5957 }
5958
5959 /*-----------------------------------------------------------------*/
5960 /* hasInc - operand is incremented before any other use            */
5961 /*-----------------------------------------------------------------*/
5962 static iCode *
5963 hasInc (operand *op, iCode *ic,int osize)
5964 {
5965   sym_link *type = operandType(op);
5966   sym_link *retype = getSpec (type);
5967   iCode *lic = ic->next;
5968   int isize ;
5969
5970   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
5971   if (!IS_SYMOP(op)) return NULL;
5972
5973   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
5974   if (IS_AGGREGATE(type->next)) return NULL;
5975   if (osize != (isize = getSize(type->next))) return NULL;
5976
5977   while (lic) {
5978     /* if operand of the form op = op + <sizeof *op> */
5979     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
5980         isOperandEqual(IC_RESULT(lic),op) &&
5981         isOperandLiteral(IC_RIGHT(lic)) &&
5982         operandLitValue(IC_RIGHT(lic)) == isize) {
5983       return lic;
5984     }
5985     /* if the operand used or deffed */
5986     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
5987       return NULL;
5988     }
5989     /* if GOTO or IFX */
5990     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
5991     lic = lic->next;
5992   }
5993   return NULL;
5994 }
5995
5996 /*-----------------------------------------------------------------*/
5997 /* genAndOp - for && operation                                     */
5998 /*-----------------------------------------------------------------*/
5999 static void
6000 genAndOp (iCode * ic)
6001 {
6002   operand *left, *right, *result;
6003   symbol *tlbl;
6004
6005   D(emitcode (";     genAndOp",""));
6006
6007   /* note here that && operations that are in an
6008      if statement are taken away by backPatchLabels
6009      only those used in arthmetic operations remain */
6010   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6011   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6012   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6013
6014   /* if both are bit variables */
6015   if (AOP_TYPE (left) == AOP_CRY &&
6016       AOP_TYPE (right) == AOP_CRY)
6017     {
6018       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6019       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6020       outBitC (result);
6021     }
6022   else
6023     {
6024       tlbl = newiTempLabel (NULL);
6025       toBoolean (left);
6026       emitcode ("jz", "%05d$", tlbl->key + 100);
6027       toBoolean (right);
6028       emitcode ("", "%05d$:", tlbl->key + 100);
6029       outBitAcc (result);
6030     }
6031
6032   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6033   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6034   freeAsmop (result, NULL, ic, TRUE);
6035 }
6036
6037
6038 /*-----------------------------------------------------------------*/
6039 /* genOrOp - for || operation                                      */
6040 /*-----------------------------------------------------------------*/
6041 static void
6042 genOrOp (iCode * ic)
6043 {
6044   operand *left, *right, *result;
6045   symbol *tlbl;
6046
6047   D(emitcode (";     genOrOp",""));
6048
6049   /* note here that || operations that are in an
6050      if statement are taken away by backPatchLabels
6051      only those used in arthmetic operations remain */
6052   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6053   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6054   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6055
6056   /* if both are bit variables */
6057   if (AOP_TYPE (left) == AOP_CRY &&
6058       AOP_TYPE (right) == AOP_CRY)
6059     {
6060       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6061       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6062       outBitC (result);
6063     }
6064   else
6065     {
6066       tlbl = newiTempLabel (NULL);
6067       toBoolean (left);
6068       emitcode ("jnz", "%05d$", tlbl->key + 100);
6069       toBoolean (right);
6070       emitcode ("", "%05d$:", tlbl->key + 100);
6071       outBitAcc (result);
6072     }
6073
6074   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6075   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6076   freeAsmop (result, NULL, ic, TRUE);
6077 }
6078
6079 /*-----------------------------------------------------------------*/
6080 /* isLiteralBit - test if lit == 2^n                               */
6081 /*-----------------------------------------------------------------*/
6082 static int
6083 isLiteralBit (unsigned long lit)
6084 {
6085   unsigned long pw[32] =
6086   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6087    0x100L, 0x200L, 0x400L, 0x800L,
6088    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6089    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6090    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6091    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6092    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6093   int idx;
6094
6095   for (idx = 0; idx < 32; idx++)
6096     if (lit == pw[idx])
6097       return idx + 1;
6098   return 0;
6099 }
6100
6101 /*-----------------------------------------------------------------*/
6102 /* continueIfTrue -                                                */
6103 /*-----------------------------------------------------------------*/
6104 static void
6105 continueIfTrue (iCode * ic)
6106 {
6107   if (IC_TRUE (ic))
6108     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6109   ic->generated = 1;
6110 }
6111
6112 /*-----------------------------------------------------------------*/
6113 /* jmpIfTrue -                                                     */
6114 /*-----------------------------------------------------------------*/
6115 static void
6116 jumpIfTrue (iCode * ic)
6117 {
6118   if (!IC_TRUE (ic))
6119     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6120   ic->generated = 1;
6121 }
6122
6123 /*-----------------------------------------------------------------*/
6124 /* jmpTrueOrFalse -                                                */
6125 /*-----------------------------------------------------------------*/
6126 static void
6127 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6128 {
6129   // ugly but optimized by peephole
6130   if (IC_TRUE (ic))
6131     {
6132       symbol *nlbl = newiTempLabel (NULL);
6133       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6134       emitcode ("", "%05d$:", tlbl->key + 100);
6135       freeForBranchAsmop (result);
6136       freeForBranchAsmop (right);
6137       freeForBranchAsmop (left);
6138       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6139       emitcode ("", "%05d$:", nlbl->key + 100);
6140     }
6141   else
6142     {
6143       freeForBranchAsmop (result);
6144       freeForBranchAsmop (right);
6145       freeForBranchAsmop (left);
6146       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6147       emitcode ("", "%05d$:", tlbl->key + 100);
6148     }
6149   ic->generated = 1;
6150 }
6151
6152 /*-----------------------------------------------------------------*/
6153 /* genAnd  - code for and                                          */
6154 /*-----------------------------------------------------------------*/
6155 static void
6156 genAnd (iCode * ic, iCode * ifx)
6157 {
6158   operand *left, *right, *result;
6159   int size, offset = 0;
6160   unsigned long lit = 0L;
6161   int bytelit = 0;
6162   char buffer[10];
6163
6164   D(emitcode (";     genAnd",""));
6165
6166   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6167   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6168   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6169
6170 #ifdef DEBUG_TYPE
6171   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6172             AOP_TYPE (result),
6173             AOP_TYPE (left), AOP_TYPE (right));
6174   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6175             AOP_SIZE (result),
6176             AOP_SIZE (left), AOP_SIZE (right));
6177 #endif
6178
6179   /* if left is a literal & right is not then exchange them */
6180   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6181       AOP_NEEDSACC (left))
6182     {
6183       operand *tmp = right;
6184       right = left;
6185       left = tmp;
6186     }
6187
6188   /* if result = right then exchange left and right */
6189   if (sameRegs (AOP (result), AOP (right)))
6190     {
6191       operand *tmp = right;
6192       right = left;
6193       left = tmp;
6194     }
6195
6196   /* if right is bit then exchange them */
6197   if (AOP_TYPE (right) == AOP_CRY &&
6198       AOP_TYPE (left) != AOP_CRY)
6199     {
6200       operand *tmp = right;
6201       right = left;
6202       left = tmp;
6203     }
6204   if (AOP_TYPE (right) == AOP_LIT)
6205     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6206
6207   size = AOP_SIZE (result);
6208
6209   // if(bit & yy)
6210   // result = bit & yy;
6211   if (AOP_TYPE (left) == AOP_CRY)
6212     {
6213       // c = bit & literal;
6214       if (AOP_TYPE (right) == AOP_LIT)
6215         {
6216           if (lit & 1)
6217             {
6218               if (size && sameRegs (AOP (result), AOP (left)))
6219                 // no change
6220                 goto release;
6221               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6222             }
6223           else
6224             {
6225               // bit(result) = 0;
6226               if (size && (AOP_TYPE (result) == AOP_CRY))
6227                 {
6228                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6229                   goto release;
6230                 }
6231               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6232                 {
6233                   jumpIfTrue (ifx);
6234                   goto release;
6235                 }
6236               emitcode ("clr", "c");
6237             }
6238         }
6239       else
6240         {
6241           if (AOP_TYPE (right) == AOP_CRY)
6242             {
6243               // c = bit & bit;
6244               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6245               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6246             }
6247           else
6248             {
6249               // c = bit & val;
6250               MOVA (aopGet (right, 0, FALSE, FALSE));
6251               // c = lsb
6252               emitcode ("rrc", "a");
6253               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6254             }
6255         }
6256       // bit = c
6257       // val = c
6258       if (size)
6259         outBitC (result);
6260       // if(bit & ...)
6261       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6262         genIfxJump (ifx, "c", left, right, result);
6263       goto release;
6264     }
6265
6266   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6267   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6268   if ((AOP_TYPE (right) == AOP_LIT) &&
6269       (AOP_TYPE (result) == AOP_CRY) &&
6270       (AOP_TYPE (left) != AOP_CRY))
6271     {
6272       int posbit = isLiteralBit (lit);
6273       /* left &  2^n */
6274       if (posbit)
6275         {
6276           posbit--;
6277           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6278           // bit = left & 2^n
6279           if (size)
6280             {
6281               switch (posbit & 0x07)
6282                 {
6283                   case 0: emitcode ("rrc", "a");
6284                           break;
6285                   case 7: emitcode ("rlc", "a");
6286                           break;
6287                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6288                           break;
6289                 }
6290             }
6291           // if(left &  2^n)
6292           else
6293             {
6294               if (ifx)
6295                 {
6296                   SNPRINTF (buffer, sizeof(buffer),
6297                             "acc.%d", posbit & 0x07);
6298                   genIfxJump (ifx, buffer, left, right, result);
6299                 }
6300               else
6301                 {// what is this case? just found it in ds390/gen.c
6302                    emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6303                 }
6304               goto release;
6305             }
6306         }
6307       else
6308         {
6309           symbol *tlbl = newiTempLabel (NULL);
6310           int sizel = AOP_SIZE (left);
6311           if (size)
6312             emitcode ("setb", "c");
6313           while (sizel--)
6314             {
6315               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6316                 {
6317                   MOVA (aopGet (left, offset, FALSE, FALSE));
6318                   // byte ==  2^n ?
6319                   if ((posbit = isLiteralBit (bytelit)) != 0)
6320                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6321                   else
6322                     {
6323                       if (bytelit != 0x0FFL)
6324                         emitcode ("anl", "a,%s",
6325                                   aopGet (right, offset, FALSE, TRUE));
6326                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6327                     }
6328                 }
6329               offset++;
6330             }
6331           // bit = left & literal
6332           if (size)
6333             {
6334               emitcode ("clr", "c");
6335               emitcode ("", "%05d$:", tlbl->key + 100);
6336             }
6337           // if(left & literal)
6338           else
6339             {
6340               if (ifx)
6341                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6342               else
6343                 emitcode ("", "%05d$:", tlbl->key + 100);
6344               goto release;
6345             }
6346         }
6347       outBitC (result);
6348       goto release;
6349     }
6350
6351   /* if left is same as result */
6352   if (sameRegs (AOP (result), AOP (left)))
6353     {
6354       for (; size--; offset++)
6355         {
6356           if (AOP_TYPE (right) == AOP_LIT)
6357             {
6358               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6359               if (bytelit == 0x0FF)
6360                 {
6361                   /* dummy read of volatile operand */
6362                   if (isOperandVolatile (left, FALSE))
6363                     MOVA (aopGet (left, offset, FALSE, FALSE));
6364                   else
6365                     continue;
6366                 }
6367               else if (bytelit == 0)
6368                 {
6369                   aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6370                 }
6371               else if (IS_AOP_PREG (result))
6372                 {
6373                   MOVA (aopGet (left, offset, FALSE, TRUE));
6374                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6375                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6376                 }
6377               else
6378                 emitcode ("anl", "%s,%s",
6379                           aopGet (left, offset, FALSE, TRUE),
6380                           aopGet (right, offset, FALSE, FALSE));
6381             }
6382           else
6383             {
6384               if (AOP_TYPE (left) == AOP_ACC && offset == 0)
6385                 {
6386                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6387                 }
6388               else
6389                 {
6390                   MOVA (aopGet (right, offset, FALSE, FALSE));
6391                   if (IS_AOP_PREG (result))
6392                     {
6393                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6394                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6395                     }
6396                   else
6397                     emitcode ("anl", "%s,a",
6398                               aopGet (left, offset, FALSE, TRUE));
6399                 }
6400             }
6401         }
6402     }
6403   else
6404     {
6405       // left & result in different registers
6406       if (AOP_TYPE (result) == AOP_CRY)
6407         {
6408           // result = bit
6409           // if(size), result in bit
6410           // if(!size && ifx), conditional oper: if(left & right)
6411           symbol *tlbl = newiTempLabel (NULL);
6412           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6413           if (size)
6414             emitcode ("setb", "c");
6415           while (sizer--)
6416             {
6417               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6418                   && AOP_TYPE(left)==AOP_ACC)
6419                 {
6420                   if (offset)
6421                     emitcode("mov", "a,b");
6422                   emitcode ("anl", "a,%s",
6423                             aopGet (right, offset, FALSE, FALSE));
6424                 } else {
6425                   if (AOP_TYPE(left)==AOP_ACC)
6426                     {
6427                       if (!offset)
6428                         {
6429                           bool pushedB = pushB ();
6430                           emitcode("mov", "b,a");
6431                           MOVA (aopGet (right, offset, FALSE, FALSE));
6432                           emitcode("anl", "a,b");
6433                           popB (pushedB);
6434                         }
6435                       else
6436                         {
6437                           MOVA (aopGet (right, offset, FALSE, FALSE));
6438                           emitcode("anl", "a,b");
6439                         }
6440                     } else {
6441                       MOVA (aopGet (right, offset, FALSE, FALSE));
6442                       emitcode ("anl", "a,%s",
6443                                 aopGet (left, offset, FALSE, FALSE));
6444                     }
6445                 }
6446               emitcode ("jnz", "%05d$", tlbl->key + 100);
6447               offset++;
6448             }
6449           if (size)
6450             {
6451               CLRC;
6452               emitcode ("", "%05d$:", tlbl->key + 100);
6453               outBitC (result);
6454             }
6455           else if (ifx)
6456             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6457           else
6458             emitcode ("", "%05d$:", tlbl->key + 100);
6459         }
6460       else
6461         {
6462           for (; (size--); offset++)
6463             {
6464               // normal case
6465               // result = left & right
6466               if (AOP_TYPE (right) == AOP_LIT)
6467                 {
6468                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6469                   if (bytelit == 0x0FF)
6470                     {
6471                       aopPut (result,
6472                               aopGet (left, offset, FALSE, FALSE),
6473                               offset,
6474                               isOperandVolatile (result, FALSE));
6475                       continue;
6476                     }
6477                   else if (bytelit == 0)
6478                     {
6479                       /* dummy read of volatile operand */
6480                       if (isOperandVolatile (left, FALSE))
6481                         MOVA (aopGet (left, offset, FALSE, FALSE));
6482                       aopPut (result, zero, offset, isOperandVolatile (result, FALSE));
6483                       continue;
6484                     }
6485                   else if (AOP_TYPE (left) == AOP_ACC)
6486                     {
6487                       if (!offset)
6488                         {
6489                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6490                           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6491                           continue;
6492                         }
6493                       else
6494                         {
6495                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6496                           aopPut (result, "b", offset, isOperandVolatile (result, FALSE));
6497                           continue;
6498                         }
6499                     }
6500                 }
6501               // faster than result <- left, anl result,right
6502               // and better if result is SFR
6503               if (AOP_TYPE (left) == AOP_ACC)
6504                 {
6505                   if (offset)
6506                     emitcode("mov", "a,b");
6507                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6508                 }
6509               else
6510                 {
6511                   MOVA (aopGet (right, offset, FALSE, FALSE));
6512                   emitcode ("anl", "a,%s",
6513                             aopGet (left, offset, FALSE, FALSE));
6514                 }
6515               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6516             }
6517         }
6518     }
6519
6520 release:
6521   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6522   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6523   freeAsmop (result, NULL, ic, TRUE);
6524 }
6525
6526 /*-----------------------------------------------------------------*/
6527 /* genOr  - code for or                                            */
6528 /*-----------------------------------------------------------------*/
6529 static void
6530 genOr (iCode * ic, iCode * ifx)
6531 {
6532   operand *left, *right, *result;
6533   int size, offset = 0;
6534   unsigned long lit = 0L;
6535   int bytelit = 0;
6536
6537   D(emitcode (";     genOr",""));
6538
6539   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6540   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6541   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6542
6543 #ifdef DEBUG_TYPE
6544   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6545             AOP_TYPE (result),
6546             AOP_TYPE (left), AOP_TYPE (right));
6547   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6548             AOP_SIZE (result),
6549             AOP_SIZE (left), AOP_SIZE (right));
6550 #endif
6551
6552   /* if left is a literal & right is not then exchange them */
6553   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6554       AOP_NEEDSACC (left))
6555     {
6556       operand *tmp = right;
6557       right = left;
6558       left = tmp;
6559     }
6560
6561   /* if result = right then exchange them */
6562   if (sameRegs (AOP (result), AOP (right)))
6563     {
6564       operand *tmp = right;
6565       right = left;
6566       left = tmp;
6567     }
6568
6569   /* if right is bit then exchange them */
6570   if (AOP_TYPE (right) == AOP_CRY &&
6571       AOP_TYPE (left) != AOP_CRY)
6572     {
6573       operand *tmp = right;
6574       right = left;
6575       left = tmp;
6576     }
6577   if (AOP_TYPE (right) == AOP_LIT)
6578     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6579
6580   size = AOP_SIZE (result);
6581
6582   // if(bit | yy)
6583   // xx = bit | yy;
6584   if (AOP_TYPE (left) == AOP_CRY)
6585     {
6586       if (AOP_TYPE (right) == AOP_LIT)
6587         {
6588           // c = bit | literal;
6589           if (lit)
6590             {
6591               // lit != 0 => result = 1
6592               if (AOP_TYPE (result) == AOP_CRY)
6593                 {
6594                   if (size)
6595                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6596                   else if (ifx)
6597                     continueIfTrue (ifx);
6598                   goto release;
6599                 }
6600               emitcode ("setb", "c");
6601             }
6602           else
6603             {
6604               // lit == 0 => result = left
6605               if (size && sameRegs (AOP (result), AOP (left)))
6606                 goto release;
6607               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6608             }
6609         }
6610       else
6611         {
6612           if (AOP_TYPE (right) == AOP_CRY)
6613             {
6614               // c = bit | bit;
6615               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6616               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
6617             }
6618           else
6619             {
6620               // c = bit | val;
6621               symbol *tlbl = newiTempLabel (NULL);
6622               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
6623                 emitcode ("setb", "c");
6624               emitcode ("jb", "%s,%05d$",
6625                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
6626               toBoolean (right);
6627               emitcode ("jnz", "%05d$", tlbl->key + 100);
6628               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6629                 {
6630                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
6631                   goto release;
6632                 }
6633               else
6634                 {
6635                   CLRC;
6636                   emitcode ("", "%05d$:", tlbl->key + 100);
6637                 }
6638             }
6639         }
6640       // bit = c
6641       // val = c
6642       if (size)
6643         outBitC (result);
6644       // if(bit | ...)
6645       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6646         genIfxJump (ifx, "c", left, right, result);
6647       goto release;
6648     }
6649
6650   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
6651   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
6652   if ((AOP_TYPE (right) == AOP_LIT) &&
6653       (AOP_TYPE (result) == AOP_CRY) &&
6654       (AOP_TYPE (left) != AOP_CRY))
6655     {
6656       if (lit)
6657         {
6658           // result = 1
6659           if (size)
6660             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6661           else
6662             continueIfTrue (ifx);
6663           goto release;
6664         }
6665       else
6666         {
6667           // lit = 0, result = boolean(left)
6668           if (size)
6669             emitcode ("setb", "c");
6670           toBoolean (right);
6671           if (size)
6672             {
6673               symbol *tlbl = newiTempLabel (NULL);
6674               emitcode ("jnz", "%05d$", tlbl->key + 100);
6675               CLRC;
6676               emitcode ("", "%05d$:", tlbl->key + 100);
6677             }
6678           else
6679             {
6680               genIfxJump (ifx, "a", left, right, result);
6681               goto release;
6682             }
6683         }
6684       outBitC (result);
6685       goto release;
6686     }
6687
6688   /* if left is same as result */
6689   if (sameRegs (AOP (result), AOP (left)))
6690     {
6691       for (; size--; offset++)
6692         {
6693           if (AOP_TYPE (right) == AOP_LIT)
6694             {
6695               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6696               if (bytelit == 0)
6697                 {
6698                   /* dummy read of volatile operand */
6699                   if (isOperandVolatile (left, FALSE))
6700                     MOVA (aopGet (left, offset, FALSE, FALSE));
6701                   else
6702                     continue;
6703                 }
6704               else if (bytelit == 0x0FF)
6705                 {
6706                   aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6707                 }
6708               else if (IS_AOP_PREG (left))
6709                 {
6710                   MOVA (aopGet (left, offset, FALSE, TRUE));
6711                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6712                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6713                 }
6714               else
6715                 {
6716                   emitcode ("orl", "%s,%s",
6717                             aopGet (left, offset, FALSE, TRUE),
6718                             aopGet (right, offset, FALSE, FALSE));
6719                 }
6720             }
6721           else
6722             {
6723               if (AOP_TYPE (left) == AOP_ACC)
6724                 {
6725                   if (offset)
6726                     emitcode("mov", "a,b");
6727                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6728                 }
6729               else
6730                 {
6731                   MOVA (aopGet (right, offset, FALSE, FALSE));
6732                   if (IS_AOP_PREG (left))
6733                     {
6734                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6735                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6736                     }
6737                   else
6738                     {
6739                       emitcode ("orl", "%s,a",
6740                                 aopGet (left, offset, FALSE, TRUE));
6741                     }
6742                 }
6743             }
6744         }
6745     }
6746   else
6747     {
6748       // left & result in different registers
6749       if (AOP_TYPE (result) == AOP_CRY)
6750         {
6751           // result = bit
6752           // if(size), result in bit
6753           // if(!size && ifx), conditional oper: if(left | right)
6754           symbol *tlbl = newiTempLabel (NULL);
6755           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
6756           if (size)
6757             emitcode ("setb", "c");
6758           while (sizer--)
6759             {
6760               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6761                 if (offset)
6762                   emitcode("mov", "a,b");
6763                 emitcode ("orl", "a,%s",
6764                           aopGet (right, offset, FALSE, FALSE));
6765               } else {
6766                 MOVA (aopGet (right, offset, FALSE, FALSE));
6767                 emitcode ("orl", "a,%s",
6768                           aopGet (left, offset, FALSE, FALSE));
6769               }
6770               emitcode ("jnz", "%05d$", tlbl->key + 100);
6771               offset++;
6772             }
6773           if (size)
6774             {
6775               CLRC;
6776               emitcode ("", "%05d$:", tlbl->key + 100);
6777               outBitC (result);
6778             }
6779           else if (ifx)
6780             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6781           else
6782             emitcode ("", "%05d$:", tlbl->key + 100);
6783         }
6784       else
6785         {
6786           for (; (size--); offset++)
6787             {
6788               // normal case
6789               // result = left | right
6790               if (AOP_TYPE (right) == AOP_LIT)
6791                 {
6792                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6793                   if (bytelit == 0)
6794                     {
6795                       aopPut (result,
6796                               aopGet (left, offset, FALSE, FALSE),
6797                               offset,
6798                               isOperandVolatile (result, FALSE));
6799                       continue;
6800                     }
6801                   else if (bytelit == 0x0FF)
6802                     {
6803                       /* dummy read of volatile operand */
6804                       if (isOperandVolatile (left, FALSE))
6805                         MOVA (aopGet (left, offset, FALSE, FALSE));
6806                       aopPut (result, "#0xFF", offset, isOperandVolatile (result, FALSE));
6807                       continue;
6808                     }
6809                 }
6810               // faster than result <- left, anl result,right
6811               // and better if result is SFR
6812               if (AOP_TYPE (left) == AOP_ACC)
6813                 {
6814                   if (offset)
6815                     emitcode("mov", "a,b");
6816                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6817                 }
6818               else
6819                 {
6820                   MOVA (aopGet (right, offset, FALSE, FALSE));
6821                   emitcode ("orl", "a,%s",
6822                             aopGet (left, offset, FALSE, FALSE));
6823                 }
6824               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
6825             }
6826         }
6827     }
6828
6829 release:
6830   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6831   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6832   freeAsmop (result, NULL, ic, TRUE);
6833 }
6834
6835 /*-----------------------------------------------------------------*/
6836 /* genXor - code for xclusive or                                   */
6837 /*-----------------------------------------------------------------*/
6838 static void
6839 genXor (iCode * ic, iCode * ifx)
6840 {
6841   operand *left, *right, *result;
6842   int size, offset = 0;
6843   unsigned long lit = 0L;
6844   int bytelit = 0;
6845
6846   D(emitcode (";     genXor",""));
6847
6848   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6849   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6850   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6851
6852 #ifdef DEBUG_TYPE
6853   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6854             AOP_TYPE (result),
6855             AOP_TYPE (left), AOP_TYPE (right));
6856   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6857             AOP_SIZE (result),
6858             AOP_SIZE (left), AOP_SIZE (right));
6859 #endif
6860
6861   /* if left is a literal & right is not ||
6862      if left needs acc & right does not */
6863   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6864       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
6865     {
6866       operand *tmp = right;
6867       right = left;
6868       left = tmp;
6869     }
6870
6871   /* if result = right then exchange them */
6872   if (sameRegs (AOP (result), AOP (right)))
6873     {
6874       operand *tmp = right;
6875       right = left;
6876       left = tmp;
6877     }
6878
6879   /* if right is bit then exchange them */
6880   if (AOP_TYPE (right) == AOP_CRY &&
6881       AOP_TYPE (left) != AOP_CRY)
6882     {
6883       operand *tmp = right;
6884       right = left;
6885       left = tmp;
6886     }
6887   if (AOP_TYPE (right) == AOP_LIT)
6888     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6889
6890   size = AOP_SIZE (result);
6891
6892   // if(bit ^ yy)
6893   // xx = bit ^ yy;
6894   if (AOP_TYPE (left) == AOP_CRY)
6895     {
6896       if (AOP_TYPE (right) == AOP_LIT)
6897         {
6898           // c = bit & literal;
6899           if (lit >> 1)
6900             {
6901               // lit>>1  != 0 => result = 1
6902               if (AOP_TYPE (result) == AOP_CRY)
6903                 {
6904                   if (size)
6905                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6906                   else if (ifx)
6907                     continueIfTrue (ifx);
6908                   goto release;
6909                 }
6910               emitcode ("setb", "c");
6911             }
6912           else
6913             {
6914               // lit == (0 or 1)
6915               if (lit == 0)
6916                 {
6917                   // lit == 0, result = left
6918                   if (size && sameRegs (AOP (result), AOP (left)))
6919                     goto release;
6920                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6921                 }
6922               else
6923                 {
6924                   // lit == 1, result = not(left)
6925                   if (size && sameRegs (AOP (result), AOP (left)))
6926                     {
6927                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
6928                       goto release;
6929                     }
6930                   else
6931                     {
6932                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6933                       emitcode ("cpl", "c");
6934                     }
6935                 }
6936             }
6937
6938         }
6939       else
6940         {
6941           // right != literal
6942           symbol *tlbl = newiTempLabel (NULL);
6943           if (AOP_TYPE (right) == AOP_CRY)
6944             {
6945               // c = bit ^ bit;
6946               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6947             }
6948           else
6949             {
6950               int sizer = AOP_SIZE (right);
6951               // c = bit ^ val
6952               // if val>>1 != 0, result = 1
6953               emitcode ("setb", "c");
6954               while (sizer)
6955                 {
6956                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
6957                   if (sizer == 1)
6958                     // test the msb of the lsb
6959                     emitcode ("anl", "a,#0xfe");
6960                   emitcode ("jnz", "%05d$", tlbl->key + 100);
6961                   sizer--;
6962                 }
6963               // val = (0,1)
6964               emitcode ("rrc", "a");
6965             }
6966           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
6967           emitcode ("cpl", "c");
6968           emitcode ("", "%05d$:", (tlbl->key + 100));
6969         }
6970       // bit = c
6971       // val = c
6972       if (size)
6973         outBitC (result);
6974       // if(bit | ...)
6975       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6976         genIfxJump (ifx, "c", left, right, result);
6977       goto release;
6978     }
6979
6980   /* if left is same as result */
6981   if (sameRegs (AOP (result), AOP (left)))
6982     {
6983       for (; size--; offset++)
6984         {
6985           if (AOP_TYPE (right) == AOP_LIT)
6986             {
6987               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6988               if (bytelit == 0)
6989                 {
6990                   /* dummy read of volatile operand */
6991                   if (isOperandVolatile (left, FALSE))
6992                     MOVA (aopGet (left, offset, FALSE, FALSE));
6993                   else
6994                     continue;
6995                 }
6996               else if (IS_AOP_PREG (left))
6997                 {
6998                   MOVA (aopGet (left, offset, FALSE, TRUE));
6999                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7000                   aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7001                 }
7002               else
7003                 {
7004                   emitcode ("xrl", "%s,%s",
7005                             aopGet (left, offset, FALSE, TRUE),
7006                             aopGet (right, offset, FALSE, FALSE));
7007                 }
7008             }
7009           else
7010             {
7011               if (AOP_TYPE (left) == AOP_ACC)
7012                 {
7013                   if (offset)
7014                     emitcode("mov", "a,b");
7015                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7016                 }
7017               else
7018                 {
7019                   MOVA (aopGet (right, offset, FALSE, FALSE));
7020                   if (IS_AOP_PREG (left))
7021                     {
7022                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7023                       aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7024                     }
7025                   else
7026                     emitcode ("xrl", "%s,a",
7027                               aopGet (left, offset, FALSE, TRUE));
7028                 }
7029             }
7030         }
7031     }
7032   else
7033     {
7034       // left & result in different registers
7035       if (AOP_TYPE (result) == AOP_CRY)
7036         {
7037           // result = bit
7038           // if(size), result in bit
7039           // if(!size && ifx), conditional oper: if(left ^ right)
7040           symbol *tlbl = newiTempLabel (NULL);
7041           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7042           if (size)
7043             emitcode ("setb", "c");
7044           while (sizer--)
7045             {
7046               if ((AOP_TYPE (right) == AOP_LIT) &&
7047                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7048                 {
7049                   MOVA (aopGet (left, offset, FALSE, FALSE));
7050                 }
7051               else
7052                 {
7053                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7054                     if (offset)
7055                       emitcode("mov", "a,b");
7056                     emitcode ("xrl", "a,%s",
7057                               aopGet (right, offset, FALSE, FALSE));
7058                   } else {
7059                     MOVA (aopGet (right, offset, FALSE, FALSE));
7060                     emitcode ("xrl", "a,%s",
7061                               aopGet (left, offset, FALSE, FALSE));
7062                   }
7063                 }
7064               emitcode ("jnz", "%05d$", tlbl->key + 100);
7065               offset++;
7066             }
7067           if (size)
7068             {
7069               CLRC;
7070               emitcode ("", "%05d$:", tlbl->key + 100);
7071               outBitC (result);
7072             }
7073           else if (ifx)
7074             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7075         }
7076       else
7077         {
7078           for (; (size--); offset++)
7079             {
7080               // normal case
7081               // result = left & right
7082               if (AOP_TYPE (right) == AOP_LIT)
7083                 {
7084                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7085                   if (bytelit == 0)
7086                     {
7087                       aopPut (result,
7088                               aopGet (left, offset, FALSE, FALSE),
7089                               offset,
7090                               isOperandVolatile (result, FALSE));
7091                       continue;
7092                     }
7093                 }
7094               // faster than result <- left, anl result,right
7095               // and better if result is SFR
7096               if (AOP_TYPE (left) == AOP_ACC)
7097                 {
7098                   if (offset)
7099                     emitcode("mov", "a,b");
7100                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7101                 }
7102               else
7103                 {
7104                   MOVA (aopGet (right, offset, FALSE, FALSE));
7105                   emitcode ("xrl", "a,%s",
7106                             aopGet (left, offset, FALSE, TRUE));
7107                 }
7108               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
7109             }
7110         }
7111     }
7112
7113 release:
7114   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7115   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7116   freeAsmop (result, NULL, ic, TRUE);
7117 }
7118
7119 /*-----------------------------------------------------------------*/
7120 /* genInline - write the inline code out                           */
7121 /*-----------------------------------------------------------------*/
7122 static void
7123 genInline (iCode * ic)
7124 {
7125   char *buffer, *bp, *bp1;
7126
7127   D(emitcode (";     genInline",""));
7128
7129   _G.inLine += (!options.asmpeep);
7130
7131   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
7132   strcpy (buffer, IC_INLINE (ic));
7133
7134   /* emit each line as a code */
7135   while (*bp)
7136     {
7137       if (*bp == '\n')
7138         {
7139           *bp++ = '\0';
7140           emitcode (bp1, "");
7141           bp1 = bp;
7142         }
7143       else
7144         {
7145           /* Add \n for labels, not dirs such as c:\mydir */
7146           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7147             {
7148               bp++;
7149               *bp = '\0';
7150               bp++;
7151               emitcode (bp1, "");
7152               bp1 = bp;
7153             }
7154           else
7155             bp++;
7156         }
7157     }
7158   if (bp1 != bp)
7159     emitcode (bp1, "");
7160   /*     emitcode("",buffer); */
7161   _G.inLine -= (!options.asmpeep);
7162 }
7163
7164 /*-----------------------------------------------------------------*/
7165 /* genRRC - rotate right with carry                                */
7166 /*-----------------------------------------------------------------*/
7167 static void
7168 genRRC (iCode * ic)
7169 {
7170   operand *left, *result;
7171   int size, offset = 0;
7172   char *l;
7173
7174   D(emitcode (";     genRRC",""));
7175
7176   /* rotate right with carry */
7177   left = IC_LEFT (ic);
7178   result = IC_RESULT (ic);
7179   aopOp (left, ic, FALSE);
7180   aopOp (result, ic, FALSE);
7181
7182   /* move it to the result */
7183   size = AOP_SIZE (result);
7184   offset = size - 1;
7185   if (size == 1) { /* special case for 1 byte */
7186       l = aopGet (left, offset, FALSE, FALSE);
7187       MOVA (l);
7188       emitcode ("rr", "a");
7189       goto release;
7190   }
7191   /* no need to clear carry, bit7 will be written later */
7192   while (size--)
7193     {
7194       l = aopGet (left, offset, FALSE, FALSE);
7195       MOVA (l);
7196       emitcode ("rrc", "a");
7197       if (AOP_SIZE (result) > 1)
7198         aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
7199     }
7200   /* now we need to put the carry into the
7201      highest order byte of the result */
7202   if (AOP_SIZE (result) > 1)
7203     {
7204       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7205       MOVA (l);
7206     }
7207   emitcode ("mov", "acc.7,c");
7208  release:
7209   aopPut (result, "a", AOP_SIZE (result) - 1, isOperandVolatile (result, FALSE));
7210   freeAsmop (left, NULL, ic, TRUE);
7211   freeAsmop (result, NULL, ic, TRUE);
7212 }
7213
7214 /*-----------------------------------------------------------------*/
7215 /* genRLC - generate code for rotate left with carry               */
7216 /*-----------------------------------------------------------------*/
7217 static void
7218 genRLC (iCode * ic)
7219 {
7220   operand *left, *result;
7221   int size, offset = 0;
7222   char *l;
7223
7224   D(emitcode (";     genRLC",""));
7225
7226   /* rotate right with carry */
7227   left = IC_LEFT (ic);
7228   result = IC_RESULT (ic);
7229   aopOp (left, ic, FALSE);
7230   aopOp (result, ic, FALSE);
7231
7232   /* move it to the result */
7233   size = AOP_SIZE (result);
7234   offset = 0;
7235   if (size--)
7236     {
7237       l = aopGet (left, offset, FALSE, FALSE);
7238       MOVA (l);
7239       if (size == 0) { /* special case for 1 byte */
7240               emitcode("rl","a");
7241               goto release;
7242       }
7243       emitcode("rlc","a"); /* bit0 will be written later */
7244       if (AOP_SIZE (result) > 1)
7245         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7246       while (size--)
7247         {
7248           l = aopGet (left, offset, FALSE, FALSE);
7249           MOVA (l);
7250           emitcode ("rlc", "a");
7251           if (AOP_SIZE (result) > 1)
7252             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
7253         }
7254     }
7255   /* now we need to put the carry into the
7256      highest order byte of the result */
7257   if (AOP_SIZE (result) > 1)
7258     {
7259       l = aopGet (result, 0, FALSE, FALSE);
7260       MOVA (l);
7261     }
7262   emitcode ("mov", "acc.0,c");
7263  release:
7264   aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7265   freeAsmop (left, NULL, ic, TRUE);
7266   freeAsmop (result, NULL, ic, TRUE);
7267 }
7268
7269 /*-----------------------------------------------------------------*/
7270 /* genGetHbit - generates code get highest order bit               */
7271 /*-----------------------------------------------------------------*/
7272 static void
7273 genGetHbit (iCode * ic)
7274 {
7275   operand *left, *result;
7276
7277   D(emitcode (";     genGetHbit",""));
7278
7279   left = IC_LEFT (ic);
7280   result = IC_RESULT (ic);
7281   aopOp (left, ic, FALSE);
7282   aopOp (result, ic, FALSE);
7283
7284   /* get the highest order byte into a */
7285   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7286   if (AOP_TYPE (result) == AOP_CRY)
7287     {
7288       emitcode ("rlc", "a");
7289       outBitC (result);
7290     }
7291   else
7292     {
7293       emitcode ("rl", "a");
7294       emitcode ("anl", "a,#0x01");
7295       outAcc (result);
7296     }
7297
7298
7299   freeAsmop (left, NULL, ic, TRUE);
7300   freeAsmop (result, NULL, ic, TRUE);
7301 }
7302
7303 /*-----------------------------------------------------------------*/
7304 /* genGetAbit - generates code get a single bit                    */
7305 /*-----------------------------------------------------------------*/
7306 static void
7307 genGetAbit (iCode * ic)
7308 {
7309   operand *left, *right, *result;
7310   int shCount;
7311
7312   D(emitcode (";     genGetAbit",""));
7313
7314   left = IC_LEFT (ic);
7315   right = IC_RIGHT (ic);
7316   result = IC_RESULT (ic);
7317   aopOp (left, ic, FALSE);
7318   aopOp (right, ic, FALSE);
7319   aopOp (result, ic, FALSE);
7320
7321   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7322
7323   /* get the needed byte into a */
7324   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7325   shCount %= 8;
7326   if (AOP_TYPE (result) == AOP_CRY)
7327     {
7328       if ((shCount) == 7)
7329           emitcode ("rlc", "a");
7330       else if ((shCount) == 0)
7331           emitcode ("rrc", "a");
7332       else
7333           emitcode ("mov", "c,acc[%d]", shCount);
7334       outBitC (result);
7335     }
7336   else
7337     {
7338       switch (shCount)
7339         {
7340         case 2:
7341           emitcode ("rr", "a");
7342           //fallthrough
7343         case 1:
7344           emitcode ("rr", "a");
7345           //fallthrough
7346         case 0:
7347           emitcode ("anl", "a,#0x01");
7348           break;
7349         case 3:
7350         case 5:
7351           emitcode ("mov", "c,acc[%d]", shCount);
7352           emitcode ("clr", "a");
7353           emitcode ("rlc", "a");
7354           break;
7355         case 4:
7356           emitcode ("swap", "a");
7357           emitcode ("anl", "a,#0x01");
7358           break;
7359         case 6:
7360           emitcode ("rl", "a");
7361           //fallthrough
7362         case 7:
7363           emitcode ("rl", "a");
7364           emitcode ("anl", "a,#0x01");
7365           break;
7366         }
7367       outAcc (result);
7368     }
7369
7370   freeAsmop (left, NULL, ic, TRUE);
7371   freeAsmop (right, NULL, ic, TRUE);
7372   freeAsmop (result, NULL, ic, TRUE);
7373 }
7374
7375 /*-----------------------------------------------------------------*/
7376 /* genGetByte - generates code get a single byte                   */
7377 /*-----------------------------------------------------------------*/
7378 static void
7379 genGetByte (iCode * ic)
7380 {
7381   operand *left, *right, *result;
7382   int offset;
7383
7384   D(emitcode (";     genGetByte",""));
7385
7386   left = IC_LEFT (ic);
7387   right = IC_RIGHT (ic);
7388   result = IC_RESULT (ic);
7389   aopOp (left, ic, FALSE);
7390   aopOp (right, ic, FALSE);
7391   aopOp (result, ic, FALSE);
7392
7393   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7394   aopPut (result,
7395           aopGet (left, offset, FALSE, FALSE),
7396           0,
7397           isOperandVolatile (result, FALSE));
7398
7399   freeAsmop (left, NULL, ic, TRUE);
7400   freeAsmop (right, NULL, ic, TRUE);
7401   freeAsmop (result, NULL, ic, TRUE);
7402 }
7403
7404 /*-----------------------------------------------------------------*/
7405 /* genGetWord - generates code get two bytes                       */
7406 /*-----------------------------------------------------------------*/
7407 static void
7408 genGetWord (iCode * ic)
7409 {
7410   operand *left, *right, *result;
7411   int offset;
7412
7413   D(emitcode (";     genGetWord",""));
7414
7415   left = IC_LEFT (ic);
7416   right = IC_RIGHT (ic);
7417   result = IC_RESULT (ic);
7418   aopOp (left, ic, FALSE);
7419   aopOp (right, ic, FALSE);
7420   aopOp (result, ic, FALSE);
7421
7422   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7423   aopPut (result,
7424           aopGet (left, offset, FALSE, FALSE),
7425           0,
7426           isOperandVolatile (result, FALSE));
7427   aopPut (result,
7428           aopGet (left, offset+1, FALSE, FALSE),
7429           1,
7430           isOperandVolatile (result, FALSE));
7431
7432   freeAsmop (left, NULL, ic, TRUE);
7433   freeAsmop (right, NULL, ic, TRUE);
7434   freeAsmop (result, NULL, ic, TRUE);
7435 }
7436
7437 /*-----------------------------------------------------------------*/
7438 /* genSwap - generates code to swap nibbles or bytes               */
7439 /*-----------------------------------------------------------------*/
7440 static void
7441 genSwap (iCode * ic)
7442 {
7443   operand *left, *result;
7444
7445   D(emitcode (";     genSwap",""));
7446
7447   left = IC_LEFT (ic);
7448   result = IC_RESULT (ic);
7449   aopOp (left, ic, FALSE);
7450   aopOp (result, ic, FALSE);
7451
7452   switch (AOP_SIZE (left))
7453     {
7454     case 1: /* swap nibbles in byte */
7455       MOVA (aopGet (left, 0, FALSE, FALSE));
7456       emitcode ("swap", "a");
7457       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
7458       break;
7459     case 2: /* swap bytes in word */
7460       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7461         {
7462           MOVA (aopGet (left, 0, FALSE, FALSE));
7463           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7464                   0, isOperandVolatile (result, FALSE));
7465           aopPut (result, "a", 1, isOperandVolatile (result, FALSE));
7466         }
7467       else if (operandsEqu (left, result))
7468         {
7469           char * reg = "a";
7470           bool pushedB = FALSE, leftInB = FALSE;
7471
7472           MOVA (aopGet (left, 0, FALSE, FALSE));
7473           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7474             {
7475               pushedB = pushB ();
7476               emitcode ("mov", "b,a");
7477               reg = "b";
7478               leftInB = TRUE;
7479             }
7480           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7481                   0, isOperandVolatile (result, FALSE));
7482           aopPut (result, reg, 1, isOperandVolatile (result, FALSE));
7483
7484           if (leftInB)
7485             popB (pushedB);
7486         }
7487       else
7488         {
7489           aopPut (result, aopGet (left, 1, FALSE, FALSE),
7490                   0, isOperandVolatile (result, FALSE));
7491           aopPut (result, aopGet (left, 0, FALSE, FALSE),
7492                   1, isOperandVolatile (result, FALSE));
7493         }
7494       break;
7495     default:
7496       wassertl(FALSE, "unsupported SWAP operand size");
7497     }
7498
7499   freeAsmop (left, NULL, ic, TRUE);
7500   freeAsmop (result, NULL, ic, TRUE);
7501 }
7502
7503
7504 /*-----------------------------------------------------------------*/
7505 /* AccRol - rotate left accumulator by known count                 */
7506 /*-----------------------------------------------------------------*/
7507 static void
7508 AccRol (int shCount)
7509 {
7510   shCount &= 0x0007;            // shCount : 0..7
7511
7512   switch (shCount)
7513     {
7514     case 0:
7515       break;
7516     case 1:
7517       emitcode ("rl", "a");
7518       break;
7519     case 2:
7520       emitcode ("rl", "a");
7521       emitcode ("rl", "a");
7522       break;
7523     case 3:
7524       emitcode ("swap", "a");
7525       emitcode ("rr", "a");
7526       break;
7527     case 4:
7528       emitcode ("swap", "a");
7529       break;
7530     case 5:
7531       emitcode ("swap", "a");
7532       emitcode ("rl", "a");
7533       break;
7534     case 6:
7535       emitcode ("rr", "a");
7536       emitcode ("rr", "a");
7537       break;
7538     case 7:
7539       emitcode ("rr", "a");
7540       break;
7541     }
7542 }
7543
7544 /*-----------------------------------------------------------------*/
7545 /* AccLsh - left shift accumulator by known count                  */
7546 /*-----------------------------------------------------------------*/
7547 static void
7548 AccLsh (int shCount)
7549 {
7550   if (shCount != 0)
7551     {
7552       if (shCount == 1)
7553         emitcode ("add", "a,acc");
7554       else if (shCount == 2)
7555         {
7556           emitcode ("add", "a,acc");
7557           emitcode ("add", "a,acc");
7558         }
7559       else
7560         {
7561           /* rotate left accumulator */
7562           AccRol (shCount);
7563           /* and kill the lower order bits */
7564           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
7565         }
7566     }
7567 }
7568
7569 /*-----------------------------------------------------------------*/
7570 /* AccRsh - right shift accumulator by known count                 */
7571 /*-----------------------------------------------------------------*/
7572 static void
7573 AccRsh (int shCount)
7574 {
7575   if (shCount != 0)
7576     {
7577       if (shCount == 1)
7578         {
7579           CLRC;
7580           emitcode ("rrc", "a");
7581         }
7582       else
7583         {
7584           /* rotate right accumulator */
7585           AccRol (8 - shCount);
7586           /* and kill the higher order bits */
7587           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7588         }
7589     }
7590 }
7591
7592 /*-----------------------------------------------------------------*/
7593 /* AccSRsh - signed right shift accumulator by known count                 */
7594 /*-----------------------------------------------------------------*/
7595 static void
7596 AccSRsh (int shCount)
7597 {
7598   symbol *tlbl;
7599   if (shCount != 0)
7600     {
7601       if (shCount == 1)
7602         {
7603           emitcode ("mov", "c,acc.7");
7604           emitcode ("rrc", "a");
7605         }
7606       else if (shCount == 2)
7607         {
7608           emitcode ("mov", "c,acc.7");
7609           emitcode ("rrc", "a");
7610           emitcode ("mov", "c,acc.7");
7611           emitcode ("rrc", "a");
7612         }
7613       else
7614         {
7615           tlbl = newiTempLabel (NULL);
7616           /* rotate right accumulator */
7617           AccRol (8 - shCount);
7618           /* and kill the higher order bits */
7619           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
7620           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7621           emitcode ("orl", "a,#0x%02x",
7622                     (unsigned char) ~SRMask[shCount]);
7623           emitcode ("", "%05d$:", tlbl->key + 100);
7624         }
7625     }
7626 }
7627
7628 /*-----------------------------------------------------------------*/
7629 /* shiftR1Left2Result - shift right one byte from left to result   */
7630 /*-----------------------------------------------------------------*/
7631 static void
7632 shiftR1Left2Result (operand * left, int offl,
7633                     operand * result, int offr,
7634                     int shCount, int sign)
7635 {
7636   MOVA (aopGet (left, offl, FALSE, FALSE));
7637   /* shift right accumulator */
7638   if (sign)
7639     AccSRsh (shCount);
7640   else
7641     AccRsh (shCount);
7642   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7643 }
7644
7645 /*-----------------------------------------------------------------*/
7646 /* shiftL1Left2Result - shift left one byte from left to result    */
7647 /*-----------------------------------------------------------------*/
7648 static void
7649 shiftL1Left2Result (operand * left, int offl,
7650                     operand * result, int offr, int shCount)
7651 {
7652   char *l;
7653   l = aopGet (left, offl, FALSE, FALSE);
7654   MOVA (l);
7655   /* shift left accumulator */
7656   AccLsh (shCount);
7657   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7658 }
7659
7660 /*-----------------------------------------------------------------*/
7661 /* movLeft2Result - move byte from left to result                  */
7662 /*-----------------------------------------------------------------*/
7663 static void
7664 movLeft2Result (operand * left, int offl,
7665                 operand * result, int offr, int sign)
7666 {
7667   char *l;
7668   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
7669     {
7670       l = aopGet (left, offl, FALSE, FALSE);
7671
7672       if (*l == '@' && (IS_AOP_PREG (result)))
7673         {
7674           emitcode ("mov", "a,%s", l);
7675           aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7676         }
7677       else
7678         {
7679           if (!sign)
7680             aopPut (result, l, offr, isOperandVolatile (result, FALSE));
7681           else
7682             {
7683               /* MSB sign in acc.7 ! */
7684               if (getDataSize (left) == offl + 1)
7685                 {
7686                   emitcode ("mov", "a,%s", l);
7687                   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
7688                 }
7689             }
7690         }
7691     }
7692 }
7693
7694 /*-----------------------------------------------------------------*/
7695 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
7696 /*-----------------------------------------------------------------*/
7697 static void
7698 AccAXRrl1 (char *x)
7699 {
7700   emitcode ("rrc", "a");
7701   emitcode ("xch", "a,%s", x);
7702   emitcode ("rrc", "a");
7703   emitcode ("xch", "a,%s", x);
7704 }
7705
7706 /*-----------------------------------------------------------------*/
7707 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
7708 /*-----------------------------------------------------------------*/
7709 static void
7710 AccAXLrl1 (char *x)
7711 {
7712   emitcode ("xch", "a,%s", x);
7713   emitcode ("rlc", "a");
7714   emitcode ("xch", "a,%s", x);
7715   emitcode ("rlc", "a");
7716 }
7717
7718 /*-----------------------------------------------------------------*/
7719 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
7720 /*-----------------------------------------------------------------*/
7721 static void
7722 AccAXLsh1 (char *x)
7723 {
7724   emitcode ("xch", "a,%s", x);
7725   emitcode ("add", "a,acc");
7726   emitcode ("xch", "a,%s", x);
7727   emitcode ("rlc", "a");
7728 }
7729
7730 /*-----------------------------------------------------------------*/
7731 /* AccAXLsh - left shift a:x by known count (0..7)                 */
7732 /*-----------------------------------------------------------------*/
7733 static void
7734 AccAXLsh (char *x, int shCount)
7735 {
7736   switch (shCount)
7737     {
7738     case 0:
7739       break;
7740     case 1:
7741       AccAXLsh1 (x);
7742       break;
7743     case 2:
7744       AccAXLsh1 (x);
7745       AccAXLsh1 (x);
7746       break;
7747     case 3:
7748     case 4:
7749     case 5:                     // AAAAABBB:CCCCCDDD
7750
7751       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
7752
7753       emitcode ("anl", "a,#0x%02x",
7754                 SLMask[shCount]);       // BBB00000:CCCCCDDD
7755
7756       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
7757
7758       AccRol (shCount);         // DDDCCCCC:BBB00000
7759
7760       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
7761
7762       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
7763
7764       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
7765
7766       emitcode ("anl", "a,#0x%02x",
7767                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
7768
7769       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
7770
7771       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
7772
7773       break;
7774     case 6:                     // AAAAAABB:CCCCCCDD
7775       emitcode ("anl", "a,#0x%02x",
7776                 SRMask[shCount]);       // 000000BB:CCCCCCDD
7777       emitcode ("mov", "c,acc.0");      // c = B
7778       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
7779 #if 0 // REMOVE ME
7780       AccAXRrl1 (x);            // BCCCCCCD:D000000B
7781       AccAXRrl1 (x);            // BBCCCCCC:DD000000
7782 #else
7783       emitcode("rrc","a");
7784       emitcode("xch","a,%s", x);
7785       emitcode("rrc","a");
7786       emitcode("mov","c,acc.0"); //<< get correct bit
7787       emitcode("xch","a,%s", x);
7788
7789       emitcode("rrc","a");
7790       emitcode("xch","a,%s", x);
7791       emitcode("rrc","a");
7792       emitcode("xch","a,%s", x);
7793 #endif
7794       break;
7795     case 7:                     // a:x <<= 7
7796
7797       emitcode ("anl", "a,#0x%02x",
7798                 SRMask[shCount]);       // 0000000B:CCCCCCCD
7799
7800       emitcode ("mov", "c,acc.0");      // c = B
7801
7802       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
7803
7804       AccAXRrl1 (x);            // BCCCCCCC:D0000000
7805
7806       break;
7807     default:
7808       break;
7809     }
7810 }
7811
7812 /*-----------------------------------------------------------------*/
7813 /* AccAXRsh - right shift a:x known count (0..7)                   */
7814 /*-----------------------------------------------------------------*/
7815 static void
7816 AccAXRsh (char *x, int shCount)
7817 {
7818   switch (shCount)
7819     {
7820     case 0:
7821       break;
7822     case 1:
7823       CLRC;
7824       AccAXRrl1 (x);            // 0->a:x
7825
7826       break;
7827     case 2:
7828       CLRC;
7829       AccAXRrl1 (x);            // 0->a:x
7830
7831       CLRC;
7832       AccAXRrl1 (x);            // 0->a:x
7833
7834       break;
7835     case 3:
7836     case 4:
7837     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7838
7839       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
7840
7841       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7842
7843       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7844
7845       emitcode ("anl", "a,#0x%02x",
7846                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7847
7848       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7849
7850       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7851
7852       emitcode ("anl", "a,#0x%02x",
7853                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7854
7855       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7856
7857       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7858
7859       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
7860
7861       break;
7862     case 6:                     // AABBBBBB:CCDDDDDD
7863
7864       emitcode ("mov", "c,acc.7");
7865       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7866
7867       emitcode ("mov", "c,acc.7");
7868       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7869
7870       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7871
7872       emitcode ("anl", "a,#0x%02x",
7873                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7874
7875       break;
7876     case 7:                     // ABBBBBBB:CDDDDDDD
7877
7878       emitcode ("mov", "c,acc.7");      // c = A
7879
7880       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7881
7882       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7883
7884       emitcode ("anl", "a,#0x%02x",
7885                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7886
7887       break;
7888     default:
7889       break;
7890     }
7891 }
7892
7893 /*-----------------------------------------------------------------*/
7894 /* AccAXRshS - right shift signed a:x known count (0..7)           */
7895 /*-----------------------------------------------------------------*/
7896 static void
7897 AccAXRshS (char *x, int shCount)
7898 {
7899   symbol *tlbl;
7900   switch (shCount)
7901     {
7902     case 0:
7903       break;
7904     case 1:
7905       emitcode ("mov", "c,acc.7");
7906       AccAXRrl1 (x);            // s->a:x
7907
7908       break;
7909     case 2:
7910       emitcode ("mov", "c,acc.7");
7911       AccAXRrl1 (x);            // s->a:x
7912
7913       emitcode ("mov", "c,acc.7");
7914       AccAXRrl1 (x);            // s->a:x
7915
7916       break;
7917     case 3:
7918     case 4:
7919     case 5:                     // AAAAABBB:CCCCCDDD = a:x
7920
7921       tlbl = newiTempLabel (NULL);
7922       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
7923
7924       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
7925
7926       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
7927
7928       emitcode ("anl", "a,#0x%02x",
7929                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
7930
7931       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
7932
7933       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
7934
7935       emitcode ("anl", "a,#0x%02x",
7936                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
7937
7938       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
7939
7940       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
7941
7942       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
7943
7944       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7945       emitcode ("orl", "a,#0x%02x",
7946                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
7947
7948       emitcode ("", "%05d$:", tlbl->key + 100);
7949       break;                    // SSSSAAAA:BBBCCCCC
7950
7951     case 6:                     // AABBBBBB:CCDDDDDD
7952
7953       tlbl = newiTempLabel (NULL);
7954       emitcode ("mov", "c,acc.7");
7955       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
7956
7957       emitcode ("mov", "c,acc.7");
7958       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
7959
7960       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
7961
7962       emitcode ("anl", "a,#0x%02x",
7963                 SRMask[shCount]);       // 000000AA:BBBBBBCC
7964
7965       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7966       emitcode ("orl", "a,#0x%02x",
7967                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
7968
7969       emitcode ("", "%05d$:", tlbl->key + 100);
7970       break;
7971     case 7:                     // ABBBBBBB:CDDDDDDD
7972
7973       tlbl = newiTempLabel (NULL);
7974       emitcode ("mov", "c,acc.7");      // c = A
7975
7976       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
7977
7978       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
7979
7980       emitcode ("anl", "a,#0x%02x",
7981                 SRMask[shCount]);       // 0000000A:BBBBBBBC
7982
7983       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
7984       emitcode ("orl", "a,#0x%02x",
7985                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
7986
7987       emitcode ("", "%05d$:", tlbl->key + 100);
7988       break;
7989     default:
7990       break;
7991     }
7992 }
7993
7994 /*-----------------------------------------------------------------*/
7995 /* shiftL2Left2Result - shift left two bytes from left to result   */
7996 /*-----------------------------------------------------------------*/
7997 static void
7998 shiftL2Left2Result (operand * left, int offl,
7999                     operand * result, int offr, int shCount)
8000 {
8001   if (sameRegs (AOP (result), AOP (left)) &&
8002       ((offl + MSB16) == offr))
8003     {
8004       /* don't crash result[offr] */
8005       MOVA (aopGet (left, offl, FALSE, FALSE));
8006       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8007     }
8008   else
8009     {
8010       movLeft2Result (left, offl, result, offr, 0);
8011       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8012     }
8013   /* ax << shCount (x = lsb(result)) */
8014   AccAXLsh (aopGet (result, offr, FALSE, FALSE), shCount);
8015   aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8016 }
8017
8018
8019 /*-----------------------------------------------------------------*/
8020 /* shiftR2Left2Result - shift right two bytes from left to result  */
8021 /*-----------------------------------------------------------------*/
8022 static void
8023 shiftR2Left2Result (operand * left, int offl,
8024                     operand * result, int offr,
8025                     int shCount, int sign)
8026 {
8027   if (sameRegs (AOP (result), AOP (left)) &&
8028       ((offl + MSB16) == offr))
8029     {
8030       /* don't crash result[offr] */
8031       MOVA (aopGet (left, offl, FALSE, FALSE));
8032       emitcode ("xch", "a,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8033     }
8034   else
8035     {
8036       movLeft2Result (left, offl, result, offr, 0);
8037       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8038     }
8039   /* a:x >> shCount (x = lsb(result)) */
8040   if (sign)
8041     AccAXRshS (aopGet (result, offr, FALSE, FALSE), shCount);
8042   else
8043     AccAXRsh (aopGet (result, offr, FALSE, FALSE), shCount);
8044   if (getDataSize (result) > 1)
8045     aopPut (result, "a", offr + MSB16, isOperandVolatile (result, FALSE));
8046 }
8047
8048 /*-----------------------------------------------------------------*/
8049 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8050 /*-----------------------------------------------------------------*/
8051 static void
8052 shiftLLeftOrResult (operand * left, int offl,
8053                     operand * result, int offr, int shCount)
8054 {
8055   MOVA (aopGet (left, offl, FALSE, FALSE));
8056   /* shift left accumulator */
8057   AccLsh (shCount);
8058   /* or with result */
8059   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8060   /* back to result */
8061   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8062 }
8063
8064 /*-----------------------------------------------------------------*/
8065 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8066 /*-----------------------------------------------------------------*/
8067 static void
8068 shiftRLeftOrResult (operand * left, int offl,
8069                     operand * result, int offr, int shCount)
8070 {
8071   MOVA (aopGet (left, offl, FALSE, FALSE));
8072   /* shift right accumulator */
8073   AccRsh (shCount);
8074   /* or with result */
8075   emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8076   /* back to result */
8077   aopPut (result, "a", offr, isOperandVolatile (result, FALSE));
8078 }
8079
8080 /*-----------------------------------------------------------------*/
8081 /* genlshOne - left shift a one byte quantity by known count       */
8082 /*-----------------------------------------------------------------*/
8083 static void
8084 genlshOne (operand * result, operand * left, int shCount)
8085 {
8086   D(emitcode (";     genlshOne",""));
8087
8088   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8089 }
8090
8091 /*-----------------------------------------------------------------*/
8092 /* genlshTwo - left shift two bytes by known amount != 0           */
8093 /*-----------------------------------------------------------------*/
8094 static void
8095 genlshTwo (operand * result, operand * left, int shCount)
8096 {
8097   int size;
8098
8099   D(emitcode (";     genlshTwo",""));
8100
8101   size = getDataSize (result);
8102
8103   /* if shCount >= 8 */
8104   if (shCount >= 8)
8105     {
8106       shCount -= 8;
8107
8108       if (size > 1)
8109         {
8110           if (shCount)
8111             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8112           else
8113             movLeft2Result (left, LSB, result, MSB16, 0);
8114         }
8115       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8116     }
8117
8118   /*  1 <= shCount <= 7 */
8119   else
8120     {
8121       if (size == 1)
8122         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8123       else
8124         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8125     }
8126 }
8127
8128 /*-----------------------------------------------------------------*/
8129 /* shiftLLong - shift left one long from left to result            */
8130 /* offl = LSB or MSB16                                             */
8131 /*-----------------------------------------------------------------*/
8132 static void
8133 shiftLLong (operand * left, operand * result, int offr)
8134 {
8135   char *l;
8136   int size = AOP_SIZE (result);
8137
8138   if (size >= LSB + offr)
8139     {
8140       l = aopGet (left, LSB, FALSE, FALSE);
8141       MOVA (l);
8142       emitcode ("add", "a,acc");
8143       if (sameRegs (AOP (left), AOP (result)) &&
8144           size >= MSB16 + offr && offr != LSB)
8145         emitcode ("xch", "a,%s",
8146                   aopGet (left, LSB + offr, FALSE, FALSE));
8147       else
8148         aopPut (result, "a", LSB + offr, isOperandVolatile (result, FALSE));
8149     }
8150
8151   if (size >= MSB16 + offr)
8152     {
8153       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8154         {
8155           l = aopGet (left, MSB16, FALSE, FALSE);
8156           MOVA (l);
8157         }
8158       emitcode ("rlc", "a");
8159       if (sameRegs (AOP (left), AOP (result)) &&
8160           size >= MSB24 + offr && offr != LSB)
8161         emitcode ("xch", "a,%s",
8162                   aopGet (left, MSB16 + offr, FALSE, FALSE));
8163       else
8164         aopPut (result, "a", MSB16 + offr, isOperandVolatile (result, FALSE));
8165     }
8166
8167   if (size >= MSB24 + offr)
8168     {
8169       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8170         {
8171           l = aopGet (left, MSB24, FALSE, FALSE);
8172           MOVA (l);
8173         }
8174       emitcode ("rlc", "a");
8175       if (sameRegs (AOP (left), AOP (result)) &&
8176           size >= MSB32 + offr && offr != LSB)
8177         emitcode ("xch", "a,%s",
8178                   aopGet (left, MSB24 + offr, FALSE, FALSE));
8179       else
8180         aopPut (result, "a", MSB24 + offr, isOperandVolatile (result, FALSE));
8181     }
8182
8183   if (size > MSB32 + offr)
8184     {
8185       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8186         {
8187           l = aopGet (left, MSB32, FALSE, FALSE);
8188           MOVA (l);
8189         }
8190       emitcode ("rlc", "a");
8191       aopPut (result, "a", MSB32 + offr, isOperandVolatile (result, FALSE));
8192     }
8193   if (offr != LSB)
8194     aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8195 }
8196
8197 /*-----------------------------------------------------------------*/
8198 /* genlshFour - shift four byte by a known amount != 0             */
8199 /*-----------------------------------------------------------------*/
8200 static void
8201 genlshFour (operand * result, operand * left, int shCount)
8202 {
8203   int size;
8204
8205   D(emitcode (";     genlshFour",""));
8206
8207   size = AOP_SIZE (result);
8208
8209   /* if shifting more that 3 bytes */
8210   if (shCount >= 24)
8211     {
8212       shCount -= 24;
8213       if (shCount)
8214         /* lowest order of left goes to the highest
8215            order of the destination */
8216         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8217       else
8218         movLeft2Result (left, LSB, result, MSB32, 0);
8219       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8220       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8221       aopPut (result, zero, MSB24, isOperandVolatile (result, FALSE));
8222       return;
8223     }
8224
8225   /* more than two bytes */
8226   else if (shCount >= 16)
8227     {
8228       /* lower order two bytes goes to higher order two bytes */
8229       shCount -= 16;
8230       /* if some more remaining */
8231       if (shCount)
8232         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8233       else
8234         {
8235           movLeft2Result (left, MSB16, result, MSB32, 0);
8236           movLeft2Result (left, LSB, result, MSB24, 0);
8237         }
8238       aopPut (result, zero, MSB16, isOperandVolatile (result, FALSE));
8239       aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8240       return;
8241     }
8242
8243   /* if more than 1 byte */
8244   else if (shCount >= 8)
8245     {
8246       /* lower order three bytes goes to higher order  three bytes */
8247       shCount -= 8;
8248       if (size == 2)
8249         {
8250           if (shCount)
8251             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8252           else
8253             movLeft2Result (left, LSB, result, MSB16, 0);
8254         }
8255       else
8256         {                       /* size = 4 */
8257           if (shCount == 0)
8258             {
8259               movLeft2Result (left, MSB24, result, MSB32, 0);
8260               movLeft2Result (left, MSB16, result, MSB24, 0);
8261               movLeft2Result (left, LSB, result, MSB16, 0);
8262               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8263             }
8264           else if (shCount == 1)
8265             shiftLLong (left, result, MSB16);
8266           else
8267             {
8268               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8269               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8270               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8271               aopPut (result, zero, LSB, isOperandVolatile (result, FALSE));
8272             }
8273         }
8274     }
8275
8276   /* 1 <= shCount <= 7 */
8277   else if (shCount <= 2)
8278     {
8279       shiftLLong (left, result, LSB);
8280       if (shCount == 2)
8281         shiftLLong (result, result, LSB);
8282     }
8283   /* 3 <= shCount <= 7, optimize */
8284   else
8285     {
8286       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8287       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8288       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8289     }
8290 }
8291
8292 /*-----------------------------------------------------------------*/
8293 /* genLeftShiftLiteral - left shifting by known count              */
8294 /*-----------------------------------------------------------------*/
8295 static void
8296 genLeftShiftLiteral (operand * left,
8297                      operand * right,
8298                      operand * result,
8299                      iCode * ic)
8300 {
8301   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8302   int size;
8303
8304   D(emitcode (";     genLeftShiftLiteral",""));
8305
8306   freeAsmop (right, NULL, ic, TRUE);
8307
8308   aopOp (left, ic, FALSE);
8309   aopOp (result, ic, FALSE);
8310
8311   size = getSize (operandType (result));
8312
8313 #if VIEW_SIZE
8314   emitcode ("; shift left ", "result %d, left %d", size,
8315             AOP_SIZE (left));
8316 #endif
8317
8318   /* I suppose that the left size >= result size */
8319   if (shCount == 0)
8320     {
8321       while (size--)
8322         {
8323           movLeft2Result (left, size, result, size, 0);
8324         }
8325     }
8326
8327   else if (shCount >= (size * 8))
8328     while (size--)
8329       aopPut (result, zero, size, isOperandVolatile (result, FALSE));
8330   else
8331     {
8332       switch (size)
8333         {
8334         case 1:
8335           genlshOne (result, left, shCount);
8336           break;
8337
8338         case 2:
8339           genlshTwo (result, left, shCount);
8340           break;
8341
8342         case 4:
8343           genlshFour (result, left, shCount);
8344           break;
8345         default:
8346           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8347                   "*** ack! mystery literal shift!\n");
8348           break;
8349         }
8350     }
8351   freeAsmop (left, NULL, ic, TRUE);
8352   freeAsmop (result, NULL, ic, TRUE);
8353 }
8354
8355 /*-----------------------------------------------------------------*/
8356 /* genLeftShift - generates code for left shifting                 */
8357 /*-----------------------------------------------------------------*/
8358 static void
8359 genLeftShift (iCode * ic)
8360 {
8361   operand *left, *right, *result;
8362   int size, offset;
8363   char *l;
8364   symbol *tlbl, *tlbl1;
8365   bool pushedB;
8366
8367   D(emitcode (";     genLeftShift",""));
8368
8369   right = IC_RIGHT (ic);
8370   left = IC_LEFT (ic);
8371   result = IC_RESULT (ic);
8372
8373   aopOp (right, ic, FALSE);
8374
8375   /* if the shift count is known then do it
8376      as efficiently as possible */
8377   if (AOP_TYPE (right) == AOP_LIT)
8378     {
8379       genLeftShiftLiteral (left, right, result, ic);
8380       return;
8381     }
8382
8383   /* shift count is unknown then we have to form
8384      a loop get the loop count in B : Note: we take
8385      only the lower order byte since shifting
8386      more that 32 bits make no sense anyway, ( the
8387      largest size of an object can be only 32 bits ) */
8388
8389   pushedB = pushB ();
8390   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8391   emitcode ("inc", "b");
8392   freeAsmop (right, NULL, ic, TRUE);
8393   aopOp (left, ic, FALSE);
8394   aopOp (result, ic, FALSE);
8395
8396   /* now move the left to the result if they are not the same */
8397   if (!sameRegs (AOP (left), AOP (result)) &&
8398       AOP_SIZE (result) > 1)
8399     {
8400
8401       size = AOP_SIZE (result);
8402       offset = 0;
8403       while (size--)
8404         {
8405           l = aopGet (left, offset, FALSE, TRUE);
8406           if (*l == '@' && (IS_AOP_PREG (result)))
8407             {
8408
8409               emitcode ("mov", "a,%s", l);
8410               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8411             }
8412           else
8413             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8414           offset++;
8415         }
8416     }
8417
8418   tlbl = newiTempLabel (NULL);
8419   size = AOP_SIZE (result);
8420   offset = 0;
8421   tlbl1 = newiTempLabel (NULL);
8422
8423   /* if it is only one byte then */
8424   if (size == 1)
8425     {
8426       symbol *tlbl1 = newiTempLabel (NULL);
8427
8428       l = aopGet (left, 0, FALSE, FALSE);
8429       MOVA (l);
8430       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8431       emitcode ("", "%05d$:", tlbl->key + 100);
8432       emitcode ("add", "a,acc");
8433       emitcode ("", "%05d$:", tlbl1->key + 100);
8434       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8435       popB (pushedB);
8436       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8437       goto release;
8438     }
8439
8440   reAdjustPreg (AOP (result));
8441
8442   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8443   emitcode ("", "%05d$:", tlbl->key + 100);
8444   l = aopGet (result, offset, FALSE, FALSE);
8445   MOVA (l);
8446   emitcode ("add", "a,acc");
8447   aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8448   while (--size)
8449     {
8450       l = aopGet (result, offset, FALSE, FALSE);
8451       MOVA (l);
8452       emitcode ("rlc", "a");
8453       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
8454     }
8455   reAdjustPreg (AOP (result));
8456
8457   emitcode ("", "%05d$:", tlbl1->key + 100);
8458   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8459   popB (pushedB);
8460 release:
8461   freeAsmop (left, NULL, ic, TRUE);
8462   freeAsmop (result, NULL, ic, TRUE);
8463 }
8464
8465 /*-----------------------------------------------------------------*/
8466 /* genrshOne - right shift a one byte quantity by known count      */
8467 /*-----------------------------------------------------------------*/
8468 static void
8469 genrshOne (operand * result, operand * left,
8470            int shCount, int sign)
8471 {
8472   D(emitcode (";     genrshOne",""));
8473
8474   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
8475 }
8476
8477 /*-----------------------------------------------------------------*/
8478 /* genrshTwo - right shift two bytes by known amount != 0          */
8479 /*-----------------------------------------------------------------*/
8480 static void
8481 genrshTwo (operand * result, operand * left,
8482            int shCount, int sign)
8483 {
8484   D(emitcode (";     genrshTwo",""));
8485
8486   /* if shCount >= 8 */
8487   if (shCount >= 8)
8488     {
8489       shCount -= 8;
8490       if (shCount)
8491         shiftR1Left2Result (left, MSB16, result, LSB,
8492                             shCount, sign);
8493       else
8494         movLeft2Result (left, MSB16, result, LSB, sign);
8495       addSign (result, MSB16, sign);
8496     }
8497
8498   /*  1 <= shCount <= 7 */
8499   else
8500     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
8501 }
8502
8503 /*-----------------------------------------------------------------*/
8504 /* shiftRLong - shift right one long from left to result           */
8505 /* offl = LSB or MSB16                                             */
8506 /*-----------------------------------------------------------------*/
8507 static void
8508 shiftRLong (operand * left, int offl,
8509             operand * result, int sign)
8510 {
8511   int isSameRegs=sameRegs(AOP(left),AOP(result));
8512
8513   if (isSameRegs && offl>1) {
8514     // we are in big trouble, but this shouldn't happen
8515     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
8516   }
8517
8518   MOVA (aopGet (left, MSB32, FALSE, FALSE));
8519
8520   if (offl==MSB16) {
8521     // shift is > 8
8522     if (sign) {
8523       emitcode ("rlc", "a");
8524       emitcode ("subb", "a,acc");
8525       if (isSameRegs)
8526         emitcode ("xch", "a,%s", aopGet (left, MSB32, FALSE, FALSE));
8527       else {
8528         aopPut (result, "a", MSB32, isOperandVolatile (result, FALSE));
8529         MOVA (aopGet (left, MSB32, FALSE, FALSE));
8530       }
8531     } else {
8532       aopPut (result, zero, MSB32, isOperandVolatile (result, FALSE));
8533     }
8534   }
8535
8536   if (!sign) {
8537     emitcode ("clr", "c");
8538   } else {
8539     emitcode ("mov", "c,acc.7");
8540   }
8541
8542   emitcode ("rrc", "a");
8543
8544   if (isSameRegs && offl==MSB16) {
8545     emitcode ("xch", "a,%s",aopGet (left, MSB24, FALSE, FALSE));
8546   } else {
8547     aopPut (result, "a", MSB32-offl, isOperandVolatile (result, FALSE));
8548     MOVA (aopGet (left, MSB24, FALSE, FALSE));
8549   }
8550
8551   emitcode ("rrc", "a");
8552   if (isSameRegs && offl==1) {
8553     emitcode ("xch", "a,%s",aopGet (left, MSB16, FALSE, FALSE));
8554   } else {
8555     aopPut (result, "a", MSB24-offl, isOperandVolatile (result, FALSE));
8556     MOVA (aopGet (left, MSB16, FALSE, FALSE));
8557   }
8558   emitcode ("rrc", "a");
8559   aopPut (result, "a", MSB16 - offl, isOperandVolatile (result, FALSE));
8560
8561   if (offl == LSB)
8562     {
8563       MOVA (aopGet (left, LSB, FALSE, FALSE));
8564       emitcode ("rrc", "a");
8565       aopPut (result, "a", LSB, isOperandVolatile (result, FALSE));
8566     }
8567 }
8568
8569 /*-----------------------------------------------------------------*/
8570 /* genrshFour - shift four byte by a known amount != 0             */
8571 /*-----------------------------------------------------------------*/
8572 static void
8573 genrshFour (operand * result, operand * left,
8574             int shCount, int sign)
8575 {
8576   D(emitcode (";     genrshFour",""));
8577
8578   /* if shifting more that 3 bytes */
8579   if (shCount >= 24)
8580     {
8581       shCount -= 24;
8582       if (shCount)
8583         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
8584       else
8585         movLeft2Result (left, MSB32, result, LSB, sign);
8586       addSign (result, MSB16, sign);
8587     }
8588   else if (shCount >= 16)
8589     {
8590       shCount -= 16;
8591       if (shCount)
8592         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
8593       else
8594         {
8595           movLeft2Result (left, MSB24, result, LSB, 0);
8596           movLeft2Result (left, MSB32, result, MSB16, sign);
8597         }
8598       addSign (result, MSB24, sign);
8599     }
8600   else if (shCount >= 8)
8601     {
8602       shCount -= 8;
8603       if (shCount == 1)
8604         shiftRLong (left, MSB16, result, sign);
8605       else if (shCount == 0)
8606         {
8607           movLeft2Result (left, MSB16, result, LSB, 0);
8608           movLeft2Result (left, MSB24, result, MSB16, 0);
8609           movLeft2Result (left, MSB32, result, MSB24, sign);
8610           addSign (result, MSB32, sign);
8611         }
8612       else
8613         {
8614           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
8615           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
8616           /* the last shift is signed */
8617           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
8618           addSign (result, MSB32, sign);
8619         }
8620     }
8621   else
8622     {                           /* 1 <= shCount <= 7 */
8623       if (shCount <= 2)
8624         {
8625           shiftRLong (left, LSB, result, sign);
8626           if (shCount == 2)
8627             shiftRLong (result, LSB, result, sign);
8628         }
8629       else
8630         {
8631           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
8632           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
8633           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
8634         }
8635     }
8636 }
8637
8638 /*-----------------------------------------------------------------*/
8639 /* genRightShiftLiteral - right shifting by known count            */
8640 /*-----------------------------------------------------------------*/
8641 static void
8642 genRightShiftLiteral (operand * left,
8643                       operand * right,
8644                       operand * result,
8645                       iCode * ic,
8646                       int sign)
8647 {
8648   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8649   int size;
8650
8651   D(emitcode (";     genRightShiftLiteral",""));
8652
8653   freeAsmop (right, NULL, ic, TRUE);
8654
8655   aopOp (left, ic, FALSE);
8656   aopOp (result, ic, FALSE);
8657
8658 #if VIEW_SIZE
8659   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
8660             AOP_SIZE (left));
8661 #endif
8662
8663   size = getDataSize (left);
8664   /* test the LEFT size !!! */
8665
8666   /* I suppose that the left size >= result size */
8667   if (shCount == 0)
8668     {
8669       size = getDataSize (result);
8670       while (size--)
8671         movLeft2Result (left, size, result, size, 0);
8672     }
8673
8674   else if (shCount >= (size * 8))
8675     {
8676       if (sign) {
8677         /* get sign in acc.7 */
8678         MOVA (aopGet (left, size - 1, FALSE, FALSE));
8679       }
8680       addSign (result, LSB, sign);
8681     }
8682   else
8683     {
8684       switch (size)
8685         {
8686         case 1:
8687           genrshOne (result, left, shCount, sign);
8688           break;
8689
8690         case 2:
8691           genrshTwo (result, left, shCount, sign);
8692           break;
8693
8694         case 4:
8695           genrshFour (result, left, shCount, sign);
8696           break;
8697         default:
8698           break;
8699         }
8700     }
8701   freeAsmop (left, NULL, ic, TRUE);
8702   freeAsmop (result, NULL, ic, TRUE);
8703 }
8704
8705 /*-----------------------------------------------------------------*/
8706 /* genSignedRightShift - right shift of signed number              */
8707 /*-----------------------------------------------------------------*/
8708 static void
8709 genSignedRightShift (iCode * ic)
8710 {
8711   operand *right, *left, *result;
8712   int size, offset;
8713   char *l;
8714   symbol *tlbl, *tlbl1;
8715   bool pushedB;
8716
8717   D(emitcode (";     genSignedRightShift",""));
8718
8719   /* we do it the hard way put the shift count in b
8720      and loop thru preserving the sign */
8721
8722   right = IC_RIGHT (ic);
8723   left = IC_LEFT (ic);
8724   result = IC_RESULT (ic);
8725
8726   aopOp (right, ic, FALSE);
8727
8728
8729   if (AOP_TYPE (right) == AOP_LIT)
8730     {
8731       genRightShiftLiteral (left, right, result, ic, 1);
8732       return;
8733     }
8734   /* shift count is unknown then we have to form
8735      a loop get the loop count in B : Note: we take
8736      only the lower order byte since shifting
8737      more that 32 bits make no sense anyway, ( the
8738      largest size of an object can be only 32 bits ) */
8739
8740   pushedB = pushB ();
8741   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8742   emitcode ("inc", "b");
8743   freeAsmop (right, NULL, ic, TRUE);
8744   aopOp (left, ic, FALSE);
8745   aopOp (result, ic, FALSE);
8746
8747   /* now move the left to the result if they are not the
8748      same */
8749   if (!sameRegs (AOP (left), AOP (result)) &&
8750       AOP_SIZE (result) > 1)
8751     {
8752
8753       size = AOP_SIZE (result);
8754       offset = 0;
8755       while (size--)
8756         {
8757           l = aopGet (left, offset, FALSE, TRUE);
8758           if (*l == '@' && IS_AOP_PREG (result))
8759             {
8760
8761               emitcode ("mov", "a,%s", l);
8762               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8763             }
8764           else
8765             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8766           offset++;
8767         }
8768     }
8769
8770   /* mov the highest order bit to OVR */
8771   tlbl = newiTempLabel (NULL);
8772   tlbl1 = newiTempLabel (NULL);
8773
8774   size = AOP_SIZE (result);
8775   offset = size - 1;
8776   MOVA (aopGet (left, offset, FALSE, FALSE));
8777   emitcode ("rlc", "a");
8778   emitcode ("mov", "ov,c");
8779   /* if it is only one byte then */
8780   if (size == 1)
8781     {
8782       l = aopGet (left, 0, FALSE, FALSE);
8783       MOVA (l);
8784       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8785       emitcode ("", "%05d$:", tlbl->key + 100);
8786       emitcode ("mov", "c,ov");
8787       emitcode ("rrc", "a");
8788       emitcode ("", "%05d$:", tlbl1->key + 100);
8789       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8790       popB (pushedB);
8791       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8792       goto release;
8793     }
8794
8795   reAdjustPreg (AOP (result));
8796   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8797   emitcode ("", "%05d$:", tlbl->key + 100);
8798   emitcode ("mov", "c,ov");
8799   while (size--)
8800     {
8801       l = aopGet (result, offset, FALSE, FALSE);
8802       MOVA (l);
8803       emitcode ("rrc", "a");
8804       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8805     }
8806   reAdjustPreg (AOP (result));
8807   emitcode ("", "%05d$:", tlbl1->key + 100);
8808   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8809   popB (pushedB);
8810
8811 release:
8812   freeAsmop (left, NULL, ic, TRUE);
8813   freeAsmop (result, NULL, ic, TRUE);
8814 }
8815
8816 /*-----------------------------------------------------------------*/
8817 /* genRightShift - generate code for right shifting                */
8818 /*-----------------------------------------------------------------*/
8819 static void
8820 genRightShift (iCode * ic)
8821 {
8822   operand *right, *left, *result;
8823   sym_link *letype;
8824   int size, offset;
8825   char *l;
8826   symbol *tlbl, *tlbl1;
8827   bool pushedB;
8828
8829   D(emitcode (";     genRightShift",""));
8830
8831   /* if signed then we do it the hard way preserve the
8832      sign bit moving it inwards */
8833   letype = getSpec (operandType (IC_LEFT (ic)));
8834
8835   if (!SPEC_USIGN (letype))
8836     {
8837       genSignedRightShift (ic);
8838       return;
8839     }
8840
8841   /* signed & unsigned types are treated the same : i.e. the
8842      signed is NOT propagated inwards : quoting from the
8843      ANSI - standard : "for E1 >> E2, is equivalent to division
8844      by 2**E2 if unsigned or if it has a non-negative value,
8845      otherwise the result is implementation defined ", MY definition
8846      is that the sign does not get propagated */
8847
8848   right = IC_RIGHT (ic);
8849   left = IC_LEFT (ic);
8850   result = IC_RESULT (ic);
8851
8852   aopOp (right, ic, FALSE);
8853
8854   /* if the shift count is known then do it
8855      as efficiently as possible */
8856   if (AOP_TYPE (right) == AOP_LIT)
8857     {
8858       genRightShiftLiteral (left, right, result, ic, 0);
8859       return;
8860     }
8861
8862   /* shift count is unknown then we have to form
8863      a loop get the loop count in B : Note: we take
8864      only the lower order byte since shifting
8865      more that 32 bits make no sense anyway, ( the
8866      largest size of an object can be only 32 bits ) */
8867
8868   pushedB = pushB ();
8869   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
8870   emitcode ("inc", "b");
8871   freeAsmop (right, NULL, ic, TRUE);
8872   aopOp (left, ic, FALSE);
8873   aopOp (result, ic, FALSE);
8874
8875   /* now move the left to the result if they are not the
8876      same */
8877   if (!sameRegs (AOP (left), AOP (result)) &&
8878       AOP_SIZE (result) > 1)
8879     {
8880
8881       size = AOP_SIZE (result);
8882       offset = 0;
8883       while (size--)
8884         {
8885           l = aopGet (left, offset, FALSE, TRUE);
8886           if (*l == '@' && IS_AOP_PREG (result))
8887             {
8888
8889               emitcode ("mov", "a,%s", l);
8890               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
8891             }
8892           else
8893             aopPut (result, l, offset, isOperandVolatile (result, FALSE));
8894           offset++;
8895         }
8896     }
8897
8898   tlbl = newiTempLabel (NULL);
8899   tlbl1 = newiTempLabel (NULL);
8900   size = AOP_SIZE (result);
8901   offset = size - 1;
8902
8903   /* if it is only one byte then */
8904   if (size == 1)
8905     {
8906       l = aopGet (left, 0, FALSE, FALSE);
8907       MOVA (l);
8908       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8909       emitcode ("", "%05d$:", tlbl->key + 100);
8910       CLRC;
8911       emitcode ("rrc", "a");
8912       emitcode ("", "%05d$:", tlbl1->key + 100);
8913       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8914       popB (pushedB);
8915       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
8916       goto release;
8917     }
8918
8919   reAdjustPreg (AOP (result));
8920   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
8921   emitcode ("", "%05d$:", tlbl->key + 100);
8922   CLRC;
8923   while (size--)
8924     {
8925       l = aopGet (result, offset, FALSE, FALSE);
8926       MOVA (l);
8927       emitcode ("rrc", "a");
8928       aopPut (result, "a", offset--, isOperandVolatile (result, FALSE));
8929     }
8930   reAdjustPreg (AOP (result));
8931
8932   emitcode ("", "%05d$:", tlbl1->key + 100);
8933   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
8934   popB (pushedB);
8935
8936 release:
8937   freeAsmop (left, NULL, ic, TRUE);
8938   freeAsmop (result, NULL, ic, TRUE);
8939 }
8940
8941 /*-----------------------------------------------------------------*/
8942 /* emitPtrByteGet - emits code to get a byte into A through a      */
8943 /*                  pointer register (R0, R1, or DPTR). The        */
8944 /*                  original value of A can be preserved in B.     */
8945 /*-----------------------------------------------------------------*/
8946 static void
8947 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
8948 {
8949   switch (p_type)
8950     {
8951     case IPOINTER:
8952     case POINTER:
8953       if (preserveAinB)
8954         emitcode ("mov", "b,a");
8955       emitcode ("mov", "a,@%s", rname);
8956       break;
8957
8958     case PPOINTER:
8959       if (preserveAinB)
8960         emitcode ("mov", "b,a");
8961       emitcode ("movx", "a,@%s", rname);
8962       break;
8963
8964     case FPOINTER:
8965       if (preserveAinB)
8966         emitcode ("mov", "b,a");
8967       emitcode ("movx", "a,@dptr");
8968       break;
8969
8970     case CPOINTER:
8971       if (preserveAinB)
8972         emitcode ("mov", "b,a");
8973       emitcode ("clr", "a");
8974       emitcode ("movc", "a,@a+dptr");
8975       break;
8976
8977     case GPOINTER:
8978       if (preserveAinB)
8979         {
8980           emitcode ("push", "b");
8981           emitcode ("push", "acc");
8982         }
8983       emitcode ("lcall", "__gptrget");
8984       if (preserveAinB)
8985         emitcode ("pop", "b");
8986       break;
8987     }
8988 }
8989
8990 /*-----------------------------------------------------------------*/
8991 /* emitPtrByteSet - emits code to set a byte from src through a    */
8992 /*                  pointer register (R0, R1, or DPTR).            */
8993 /*-----------------------------------------------------------------*/
8994 static void
8995 emitPtrByteSet (char *rname, int p_type, char *src)
8996 {
8997   switch (p_type)
8998     {
8999     case IPOINTER:
9000     case POINTER:
9001       if (*src=='@')
9002         {
9003           MOVA (src);
9004           emitcode ("mov", "@%s,a", rname);
9005         }
9006       else
9007         emitcode ("mov", "@%s,%s", rname, src);
9008       break;
9009
9010     case PPOINTER:
9011       MOVA (src);
9012       emitcode ("movx", "@%s,a", rname);
9013       break;
9014
9015     case FPOINTER:
9016       MOVA (src);
9017       emitcode ("movx", "@dptr,a");
9018       break;
9019
9020     case GPOINTER:
9021       MOVA (src);
9022       emitcode ("lcall", "__gptrput");
9023       break;
9024     }
9025 }
9026
9027 /*-----------------------------------------------------------------*/
9028 /* genUnpackBits - generates code for unpacking bits               */
9029 /*-----------------------------------------------------------------*/
9030 static void
9031 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9032 {
9033   int offset = 0;       /* result byte offset */
9034   int rsize;            /* result size */
9035   int rlen = 0;         /* remaining bitfield length */
9036   sym_link *etype;      /* bitfield type information */
9037   int blen;             /* bitfield length */
9038   int bstr;             /* bitfield starting bit within byte */
9039   char buffer[10];
9040
9041   D(emitcode (";     genUnpackBits",""));
9042
9043   etype = getSpec (operandType (result));
9044   rsize = getSize (operandType (result));
9045   blen = SPEC_BLEN (etype);
9046   bstr = SPEC_BSTR (etype);
9047
9048   if (ifx && blen <= 8)
9049     {
9050       emitPtrByteGet (rname, ptype, FALSE);
9051       if (blen == 1)
9052         {
9053           SNPRINTF (buffer, sizeof(buffer),
9054                     "acc.%d", bstr);
9055           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9056         }
9057       else
9058         {
9059           if (blen < 8)
9060             emitcode ("anl", "a,#0x%02x",
9061                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9062           genIfxJump (ifx, "a", NULL, NULL, NULL);
9063         }
9064       return;
9065     }
9066   wassert (!ifx);
9067
9068   /* If the bitfield length is less than a byte */
9069   if (blen < 8)
9070     {
9071       emitPtrByteGet (rname, ptype, FALSE);
9072       AccRsh (bstr);
9073       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9074       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9075       goto finish;
9076     }
9077
9078   /* Bit field did not fit in a byte. Copy all
9079      but the partial byte at the end.  */
9080   for (rlen=blen;rlen>=8;rlen-=8)
9081     {
9082       emitPtrByteGet (rname, ptype, FALSE);
9083       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9084       if (rlen>8)
9085         emitcode ("inc", "%s", rname);
9086     }
9087
9088   /* Handle the partial byte at the end */
9089   if (rlen)
9090     {
9091       emitPtrByteGet (rname, ptype, FALSE);
9092       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9093       aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9094     }
9095
9096 finish:
9097   if (offset < rsize)
9098     {
9099       rsize -= offset;
9100       while (rsize--)
9101         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
9102     }
9103 }
9104
9105
9106 /*-----------------------------------------------------------------*/
9107 /* genDataPointerGet - generates code when ptr offset is known     */
9108 /*-----------------------------------------------------------------*/
9109 static void
9110 genDataPointerGet (operand * left,
9111                    operand * result,
9112                    iCode * ic)
9113 {
9114   char *l;
9115   char buffer[256];
9116   int size, offset = 0;
9117
9118   D(emitcode (";     genDataPointerGet",""));
9119
9120   aopOp (result, ic, TRUE);
9121
9122   /* get the string representation of the name */
9123   l = aopGet (left, 0, FALSE, TRUE);
9124   size = AOP_SIZE (result);
9125   while (size--)
9126     {
9127       if (offset)
9128         sprintf (buffer, "(%s + %d)", l + 1, offset);
9129       else
9130         sprintf (buffer, "%s", l + 1);
9131       aopPut (result, buffer, offset++, isOperandVolatile (result, FALSE));
9132     }
9133
9134   freeAsmop (left, NULL, ic, TRUE);
9135   freeAsmop (result, NULL, ic, TRUE);
9136 }
9137
9138 /*-----------------------------------------------------------------*/
9139 /* genNearPointerGet - emitcode for near pointer fetch             */
9140 /*-----------------------------------------------------------------*/
9141 static void
9142 genNearPointerGet (operand * left,
9143                    operand * result,
9144                    iCode * ic,
9145                    iCode * pi,
9146                    iCode * ifx)
9147 {
9148   asmop *aop = NULL;
9149   regs *preg = NULL;
9150   char *rname;
9151   sym_link *rtype, *retype;
9152   sym_link *ltype = operandType (left);
9153   char buffer[80];
9154
9155   D(emitcode (";     genNearPointerGet",""));
9156
9157   rtype = operandType (result);
9158   retype = getSpec (rtype);
9159
9160   aopOp (left, ic, FALSE);
9161
9162   /* if left is rematerialisable and
9163      result is not bitfield variable type and
9164      the left is pointer to data space i.e
9165      lower 128 bytes of space */
9166   if (AOP_TYPE (left) == AOP_IMMD &&
9167       !IS_BITFIELD (retype) &&
9168       DCL_TYPE (ltype) == POINTER)
9169     {
9170       genDataPointerGet (left, result, ic);
9171       return;
9172     }
9173
9174  /* if the value is already in a pointer register
9175      then don't need anything more */
9176   if (!AOP_INPREG (AOP (left)))
9177     {
9178       if (IS_AOP_PREG (left))
9179         {
9180           // Aha, it is a pointer, just in disguise.
9181           rname = aopGet (left, 0, FALSE, FALSE);
9182           if (*rname != '@')
9183             {
9184               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9185                       __FILE__, __LINE__);
9186             }
9187           else
9188             {
9189               // Expected case.
9190               emitcode ("mov", "a%s,%s", rname + 1, rname);
9191               rname++;  // skip the '@'.
9192             }
9193         }
9194       else
9195         {
9196           /* otherwise get a free pointer register */
9197           aop = newAsmop (0);
9198           preg = getFreePtr (ic, &aop, FALSE);
9199           emitcode ("mov", "%s,%s",
9200                     preg->name,
9201                     aopGet (left, 0, FALSE, TRUE));
9202           rname = preg->name;
9203         }
9204     }
9205   else
9206     rname = aopGet (left, 0, FALSE, FALSE);
9207
9208   //aopOp (result, ic, FALSE);
9209   aopOp (result, ic, result?TRUE:FALSE);
9210
9211   /* if bitfield then unpack the bits */
9212   if (IS_BITFIELD (retype))
9213     genUnpackBits (result, rname, POINTER, ifx);
9214   else
9215     {
9216       /* we have can just get the values */
9217       int size = AOP_SIZE (result);
9218       int offset = 0;
9219
9220       while (size--)
9221         {
9222           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9223             {
9224
9225               emitcode ("mov", "a,@%s", rname);
9226               if (!ifx)
9227               aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9228             }
9229           else
9230             {
9231               sprintf (buffer, "@%s", rname);
9232               aopPut (result, buffer, offset, isOperandVolatile (result, FALSE));
9233             }
9234           offset++;
9235           if (size || pi)
9236             emitcode ("inc", "%s", rname);
9237         }
9238     }
9239
9240   /* now some housekeeping stuff */
9241   if (aop)       /* we had to allocate for this iCode */
9242     {
9243       if (pi) { /* post increment present */
9244         aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9245       }
9246       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9247     }
9248   else
9249     {
9250       /* we did not allocate which means left
9251          already in a pointer register, then
9252          if size > 0 && this could be used again
9253          we have to point it back to where it
9254          belongs */
9255       if ((AOP_SIZE (result) > 1 &&
9256            !OP_SYMBOL (left)->remat &&
9257            (OP_SYMBOL (left)->liveTo > ic->seq ||
9258             ic->depth)) &&
9259           !pi)
9260         {
9261           int size = AOP_SIZE (result) - 1;
9262           while (size--)
9263             emitcode ("dec", "%s", rname);
9264         }
9265     }
9266
9267   if (ifx && !ifx->generated)
9268     {
9269       genIfxJump (ifx, "a", left, NULL, result);
9270     }
9271
9272   /* done */
9273   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9274   freeAsmop (left, NULL, ic, TRUE);
9275   if (pi) pi->generated = 1;
9276 }
9277
9278 /*-----------------------------------------------------------------*/
9279 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9280 /*-----------------------------------------------------------------*/
9281 static void
9282 genPagedPointerGet (operand * left,
9283                     operand * result,
9284                     iCode * ic,
9285                     iCode *pi,
9286                     iCode *ifx)
9287 {
9288   asmop *aop = NULL;
9289   regs *preg = NULL;
9290   char *rname;
9291   sym_link *rtype, *retype;
9292
9293   D(emitcode (";     genPagedPointerGet",""));
9294
9295   rtype = operandType (result);
9296   retype = getSpec (rtype);
9297
9298   aopOp (left, ic, FALSE);
9299
9300   /* if the value is already in a pointer register
9301      then don't need anything more */
9302   if (!AOP_INPREG (AOP (left)))
9303     {
9304       /* otherwise get a free pointer register */
9305       aop = newAsmop (0);
9306       preg = getFreePtr (ic, &aop, FALSE);
9307       emitcode ("mov", "%s,%s",
9308                 preg->name,
9309                 aopGet (left, 0, FALSE, TRUE));
9310       rname = preg->name;
9311     }
9312   else
9313     rname = aopGet (left, 0, FALSE, FALSE);
9314
9315   aopOp (result, ic, FALSE);
9316
9317   /* if bitfield then unpack the bits */
9318   if (IS_BITFIELD (retype))
9319     genUnpackBits (result, rname, PPOINTER, ifx);
9320   else
9321     {
9322       /* we have can just get the values */
9323       int size = AOP_SIZE (result);
9324       int offset = 0;
9325
9326       while (size--)
9327         {
9328
9329           emitcode ("movx", "a,@%s", rname);
9330           if (!ifx)
9331           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
9332
9333           offset++;
9334
9335           if (size || pi)
9336             emitcode ("inc", "%s", rname);
9337         }
9338     }
9339
9340   /* now some housekeeping stuff */
9341   if (aop) /* we had to allocate for this iCode */
9342     {
9343       if (pi) aopPut (left, rname, 0, isOperandVolatile (left, FALSE));
9344       freeAsmop (NULL, aop, ic, TRUE);
9345     }
9346   else
9347     {
9348       /* we did not allocate which means left
9349          already in a pointer register, then
9350          if size > 0 && this could be used again
9351          we have to point it back to where it
9352          belongs */
9353       if ((AOP_SIZE (result) > 1 &&
9354            !OP_SYMBOL (left)->remat &&
9355            (OP_SYMBOL (left)->liveTo > ic->seq ||
9356             ic->depth)) &&
9357           !pi)
9358         {
9359           int size = AOP_SIZE (result) - 1;
9360           while (size--)
9361             emitcode ("dec", "%s", rname);
9362         }
9363     }
9364
9365   if (ifx && !ifx->generated)
9366     {
9367       genIfxJump (ifx, "a", left, NULL, result);
9368     }
9369
9370   /* done */
9371   freeAsmop (left, NULL, ic, TRUE);
9372   freeAsmop (result, NULL, ic, TRUE);
9373   if (pi) pi->generated = 1;
9374
9375 }
9376
9377 /*--------------------------------------------------------------------*/
9378 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
9379 /*--------------------------------------------------------------------*/
9380 static void
9381 loadDptrFromOperand (operand *op, bool loadBToo)
9382 {
9383   if (AOP_TYPE (op) != AOP_STR)
9384     {
9385       /* if this is rematerializable */
9386       if (AOP_TYPE (op) == AOP_IMMD)
9387         {
9388           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
9389           if (loadBToo)
9390             {
9391               if (AOP(op)->aopu.aop_immd.from_cast_remat)
9392                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
9393               else
9394                 {
9395                   wassertl(FALSE, "need pointerCode");
9396                   emitcode ("", "; mov b,???");
9397                   /* genPointerGet and genPointerSet originally did different
9398                   ** things for this case. Both seem wrong.
9399                   ** from genPointerGet:
9400                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
9401                   ** from genPointerSet:
9402                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
9403                   */
9404                 }
9405             }
9406         }
9407       else if (AOP_TYPE (op) == AOP_DPTR)
9408         {
9409           if (loadBToo)
9410             {
9411               MOVA (aopGet (op, 0, FALSE, FALSE));
9412               emitcode ("push", "acc");
9413               MOVA (aopGet (op, 1, FALSE, FALSE));
9414               emitcode ("push", "acc");
9415               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9416               emitcode ("pop", "dph");
9417               emitcode ("pop", "dpl");
9418             }
9419           else
9420             {
9421               MOVA (aopGet (op, 0, FALSE, FALSE));
9422               emitcode ("push", "acc");
9423               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9424               emitcode ("pop", "dpl");
9425             }
9426         }
9427       else
9428         {                       /* we need to get it byte by byte */
9429           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
9430           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
9431           if (loadBToo)
9432             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
9433         }
9434     }
9435 }
9436
9437 /*-----------------------------------------------------------------*/
9438 /* genFarPointerGet - gget value from far space                    */
9439 /*-----------------------------------------------------------------*/
9440 static void
9441 genFarPointerGet (operand * left,
9442                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
9443 {
9444   int size, offset;
9445   sym_link *retype = getSpec (operandType (result));
9446
9447   D(emitcode (";     genFarPointerGet",""));
9448
9449   aopOp (left, ic, FALSE);
9450   loadDptrFromOperand (left, FALSE);
9451
9452   /* so dptr now contains the address */
9453   aopOp (result, ic, FALSE);
9454
9455   /* if bit then unpack */
9456   if (IS_BITFIELD (retype))
9457     genUnpackBits (result, "dptr", FPOINTER, ifx);
9458   else
9459     {
9460       size = AOP_SIZE (result);
9461       offset = 0;
9462
9463       while (size--)
9464         {
9465           emitcode ("movx", "a,@dptr");
9466           if (!ifx)
9467             aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9468           if (size || pi)
9469             emitcode ("inc", "dptr");
9470         }
9471     }
9472
9473   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9474     {
9475     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9476     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9477     pi->generated = 1;
9478   }
9479
9480   if (ifx && !ifx->generated)
9481     {
9482       genIfxJump (ifx, "a", left, NULL, result);
9483     }
9484
9485   freeAsmop (left, NULL, ic, TRUE);
9486   freeAsmop (result, NULL, ic, TRUE);
9487 }
9488
9489 /*-----------------------------------------------------------------*/
9490 /* genCodePointerGet - gget value from code space                  */
9491 /*-----------------------------------------------------------------*/
9492 static void
9493 genCodePointerGet (operand * left,
9494                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
9495 {
9496   int size, offset;
9497   sym_link *retype = getSpec (operandType (result));
9498
9499   D(emitcode (";     genCodePointerGet",""));
9500
9501   aopOp (left, ic, FALSE);
9502   loadDptrFromOperand (left, FALSE);
9503
9504   /* so dptr now contains the address */
9505   aopOp (result, ic, FALSE);
9506
9507   /* if bit then unpack */
9508   if (IS_BITFIELD (retype))
9509     genUnpackBits (result, "dptr", CPOINTER, ifx);
9510   else
9511     {
9512       size = AOP_SIZE (result);
9513       offset = 0;
9514
9515       while (size--)
9516         {
9517           if (pi)
9518             {
9519               emitcode ("clr", "a");
9520               emitcode ("movc", "a,@a+dptr");
9521               if (!ifx)
9522               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9523               emitcode ("inc", "dptr");
9524             }
9525           else
9526             {
9527               emitcode ("mov", "a,#0x%02x", offset);
9528               emitcode ("movc", "a,@a+dptr");
9529               if (!ifx)
9530               aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9531             }
9532         }
9533     }
9534
9535   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9536     {
9537     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9538     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9539     pi->generated = 1;
9540   }
9541
9542   if (ifx && !ifx->generated)
9543     {
9544       genIfxJump (ifx, "a", left, NULL, result);
9545     }
9546
9547   freeAsmop (left, NULL, ic, TRUE);
9548   freeAsmop (result, NULL, ic, TRUE);
9549 }
9550
9551 /*-----------------------------------------------------------------*/
9552 /* genGenPointerGet - gget value from generic pointer space        */
9553 /*-----------------------------------------------------------------*/
9554 static void
9555 genGenPointerGet (operand * left,
9556                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
9557 {
9558   int size, offset;
9559   sym_link *retype = getSpec (operandType (result));
9560
9561   D(emitcode (";     genGenPointerGet",""));
9562
9563   aopOp (left, ic, FALSE);
9564   loadDptrFromOperand (left, TRUE);
9565
9566   /* so dptr know contains the address */
9567   aopOp (result, ic, FALSE);
9568
9569   /* if bit then unpack */
9570   if (IS_BITFIELD (retype))
9571     genUnpackBits (result, "dptr", GPOINTER, ifx);
9572   else
9573     {
9574       size = AOP_SIZE (result);
9575       offset = 0;
9576
9577       while (size--)
9578         {
9579           emitcode ("lcall", "__gptrget");
9580           if (!ifx)
9581           aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
9582           if (size || pi)
9583             emitcode ("inc", "dptr");
9584         }
9585     }
9586
9587   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
9588     {
9589     aopPut (left, "dpl", 0, isOperandVolatile (left, FALSE));
9590     aopPut (left, "dph", 1, isOperandVolatile (left, FALSE));
9591     pi->generated = 1;
9592   }
9593
9594   if (ifx && !ifx->generated)
9595     {
9596       genIfxJump (ifx, "a", left, NULL, result);
9597     }
9598
9599
9600   freeAsmop (left, NULL, ic, TRUE);
9601   freeAsmop (result, NULL, ic, TRUE);
9602 }
9603
9604 /*-----------------------------------------------------------------*/
9605 /* genPointerGet - generate code for pointer get                   */
9606 /*-----------------------------------------------------------------*/
9607 static void
9608 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
9609 {
9610   operand *left, *result;
9611   sym_link *type, *etype;
9612   int p_type;
9613
9614   D(emitcode (";     genPointerGet",""));
9615
9616   left = IC_LEFT (ic);
9617   result = IC_RESULT (ic);
9618
9619   if (getSize (operandType (result))>1)
9620     ifx = NULL;
9621
9622   /* depending on the type of pointer we need to
9623      move it to the correct pointer register */
9624   type = operandType (left);
9625   etype = getSpec (type);
9626   /* if left is of type of pointer then it is simple */
9627   if (IS_PTR (type) && !IS_FUNC (type->next))
9628     p_type = DCL_TYPE (type);
9629   else
9630     {
9631       /* we have to go by the storage class */
9632       p_type = PTR_TYPE (SPEC_OCLS (etype));
9633     }
9634
9635   /* special case when cast remat */
9636   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
9637       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
9638           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
9639           type = operandType (left);
9640           p_type = DCL_TYPE (type);
9641   }
9642   /* now that we have the pointer type we assign
9643      the pointer values */
9644   switch (p_type)
9645     {
9646
9647     case POINTER:
9648     case IPOINTER:
9649       genNearPointerGet (left, result, ic, pi, ifx);
9650       break;
9651
9652     case PPOINTER:
9653       genPagedPointerGet (left, result, ic, pi, ifx);
9654       break;
9655
9656     case FPOINTER:
9657       genFarPointerGet (left, result, ic, pi, ifx);
9658       break;
9659
9660     case CPOINTER:
9661       genCodePointerGet (left, result, ic, pi, ifx);
9662       break;
9663
9664     case GPOINTER:
9665       genGenPointerGet (left, result, ic, pi, ifx);
9666       break;
9667     }
9668
9669 }
9670
9671
9672
9673 /*-----------------------------------------------------------------*/
9674 /* genPackBits - generates code for packed bit storage             */
9675 /*-----------------------------------------------------------------*/
9676 static void
9677 genPackBits (sym_link * etype,
9678              operand * right,
9679              char *rname, int p_type)
9680 {
9681   int offset = 0;       /* source byte offset */
9682   int rlen = 0;         /* remaining bitfield length */
9683   int blen;             /* bitfield length */
9684   int bstr;             /* bitfield starting bit within byte */
9685   int litval;           /* source literal value (if AOP_LIT) */
9686   unsigned char mask;   /* bitmask within current byte */
9687
9688   D(emitcode (";     genPackBits",""));
9689
9690   blen = SPEC_BLEN (etype);
9691   bstr = SPEC_BSTR (etype);
9692
9693   /* If the bitfield length is less than a byte */
9694   if (blen < 8)
9695     {
9696       mask = ((unsigned char) (0xFF << (blen + bstr)) |
9697               (unsigned char) (0xFF >> (8 - bstr)));
9698
9699       if (AOP_TYPE (right) == AOP_LIT)
9700         {
9701           /* Case with a bitfield length <8 and literal source
9702           */
9703           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9704           litval <<= bstr;
9705           litval &= (~mask) & 0xff;
9706           emitPtrByteGet (rname, p_type, FALSE);
9707           if ((mask|litval)!=0xff)
9708             emitcode ("anl","a,#0x%02x", mask);
9709           if (litval)
9710             emitcode ("orl","a,#0x%02x", litval);
9711         }
9712       else
9713         {
9714           if ((blen==1) && (p_type!=GPOINTER))
9715             {
9716               /* Case with a bitfield length == 1 and no generic pointer
9717               */
9718               if (AOP_TYPE (right) == AOP_CRY)
9719                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
9720               else
9721                 {
9722                   MOVA (aopGet (right, 0, FALSE, FALSE));
9723                   emitcode ("rrc","a");
9724                 }
9725               emitPtrByteGet (rname, p_type, FALSE);
9726               emitcode ("mov","acc.%d,c",bstr);
9727             }
9728           else
9729             {
9730               bool pushedB;
9731               /* Case with a bitfield length < 8 and arbitrary source
9732               */
9733               MOVA (aopGet (right, 0, FALSE, FALSE));
9734               /* shift and mask source value */
9735               AccLsh (bstr);
9736               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9737
9738               pushedB = pushB ();
9739               /* transfer A to B and get next byte */
9740               emitPtrByteGet (rname, p_type, TRUE);
9741
9742               emitcode ("anl", "a,#0x%02x", mask);
9743               emitcode ("orl", "a,b");
9744               if (p_type == GPOINTER)
9745                 emitcode ("pop", "b");
9746
9747               popB (pushedB);
9748            }
9749         }
9750
9751       emitPtrByteSet (rname, p_type, "a");
9752       return;
9753     }
9754
9755   /* Bit length is greater than 7 bits. In this case, copy  */
9756   /* all except the partial byte at the end                 */
9757   for (rlen=blen;rlen>=8;rlen-=8)
9758     {
9759       emitPtrByteSet (rname, p_type,
9760                       aopGet (right, offset++, FALSE, TRUE) );
9761       if (rlen>8)
9762         emitcode ("inc", "%s", rname);
9763     }
9764
9765   /* If there was a partial byte at the end */
9766   if (rlen)
9767     {
9768       mask = (((unsigned char) -1 << rlen) & 0xff);
9769
9770       if (AOP_TYPE (right) == AOP_LIT)
9771         {
9772           /* Case with partial byte and literal source
9773           */
9774           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9775           litval >>= (blen-rlen);
9776           litval &= (~mask) & 0xff;
9777           emitPtrByteGet (rname, p_type, FALSE);
9778           if ((mask|litval)!=0xff)
9779             emitcode ("anl","a,#0x%02x", mask);
9780           if (litval)
9781             emitcode ("orl","a,#0x%02x", litval);
9782         }
9783       else
9784         {
9785           bool pushedB;
9786           /* Case with partial byte and arbitrary source
9787           */
9788           MOVA (aopGet (right, offset++, FALSE, FALSE));
9789           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
9790
9791           pushedB = pushB ();
9792           /* transfer A to B and get next byte */
9793           emitPtrByteGet (rname, p_type, TRUE);
9794
9795           emitcode ("anl", "a,#0x%02x", mask);
9796           emitcode ("orl", "a,b");
9797           if (p_type == GPOINTER)
9798             emitcode ("pop", "b");
9799
9800           popB (pushedB);
9801         }
9802       emitPtrByteSet (rname, p_type, "a");
9803     }
9804
9805 }
9806
9807
9808 /*-----------------------------------------------------------------*/
9809 /* genDataPointerSet - remat pointer to data space                 */
9810 /*-----------------------------------------------------------------*/
9811 static void
9812 genDataPointerSet (operand * right,
9813                    operand * result,
9814                    iCode * ic)
9815 {
9816   int size, offset = 0;
9817   char *l, buffer[256];
9818
9819   D(emitcode (";     genDataPointerSet",""));
9820
9821   aopOp (right, ic, FALSE);
9822
9823   l = aopGet (result, 0, FALSE, TRUE);
9824   size = AOP_SIZE (right);
9825   while (size--)
9826     {
9827       if (offset)
9828         sprintf (buffer, "(%s + %d)", l + 1, offset);
9829       else
9830         sprintf (buffer, "%s", l + 1);
9831       emitcode ("mov", "%s,%s", buffer,
9832                 aopGet (right, offset++, FALSE, FALSE));
9833     }
9834
9835   freeAsmop (right, NULL, ic, TRUE);
9836   freeAsmop (result, NULL, ic, TRUE);
9837 }
9838
9839 /*-----------------------------------------------------------------*/
9840 /* genNearPointerSet - emitcode for near pointer put                */
9841 /*-----------------------------------------------------------------*/
9842 static void
9843 genNearPointerSet (operand * right,
9844                    operand * result,
9845                    iCode * ic,
9846                    iCode * pi)
9847 {
9848   asmop *aop = NULL;
9849   regs *preg = NULL;
9850   char *rname, *l;
9851   sym_link *retype, *letype;
9852   sym_link *ptype = operandType (result);
9853
9854   D(emitcode (";     genNearPointerSet",""));
9855
9856   retype = getSpec (operandType (right));
9857   letype = getSpec (ptype);
9858   aopOp (result, ic, FALSE);
9859
9860   /* if the result is rematerializable &
9861      in data space & not a bit variable */
9862   if (AOP_TYPE (result) == AOP_IMMD &&
9863       DCL_TYPE (ptype) == POINTER &&
9864       !IS_BITVAR (retype) &&
9865       !IS_BITVAR (letype))
9866     {
9867       genDataPointerSet (right, result, ic);
9868       return;
9869     }
9870
9871   /* if the value is already in a pointer register
9872      then don't need anything more */
9873   if (!AOP_INPREG (AOP (result)))
9874     {
9875         if (
9876             //AOP_TYPE (result) == AOP_STK
9877             IS_AOP_PREG(result)
9878             )
9879         {
9880             // Aha, it is a pointer, just in disguise.
9881             rname = aopGet (result, 0, FALSE, FALSE);
9882             if (*rname != '@')
9883             {
9884                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9885                         __FILE__, __LINE__);
9886             }
9887             else
9888             {
9889                 // Expected case.
9890                 emitcode ("mov", "a%s,%s", rname + 1, rname);
9891                 rname++;  // skip the '@'.
9892             }
9893         }
9894         else
9895         {
9896             /* otherwise get a free pointer register */
9897             aop = newAsmop (0);
9898             preg = getFreePtr (ic, &aop, FALSE);
9899             emitcode ("mov", "%s,%s",
9900                       preg->name,
9901                       aopGet (result, 0, FALSE, TRUE));
9902             rname = preg->name;
9903         }
9904     }
9905     else
9906     {
9907         rname = aopGet (result, 0, FALSE, FALSE);
9908     }
9909
9910   aopOp (right, ic, FALSE);
9911
9912   /* if bitfield then unpack the bits */
9913   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9914     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
9915   else
9916     {
9917       /* we have can just get the values */
9918       int size = AOP_SIZE (right);
9919       int offset = 0;
9920
9921       while (size--)
9922         {
9923           l = aopGet (right, offset, FALSE, TRUE);
9924           if (*l == '@')
9925             {
9926               MOVA (l);
9927               emitcode ("mov", "@%s,a", rname);
9928             }
9929           else
9930             emitcode ("mov", "@%s,%s", rname, l);
9931           if (size || pi)
9932             emitcode ("inc", "%s", rname);
9933           offset++;
9934         }
9935     }
9936
9937   /* now some housekeeping stuff */
9938   if (aop) /* we had to allocate for this iCode */
9939     {
9940       if (pi)
9941         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
9942       freeAsmop (NULL, aop, ic, TRUE);
9943     }
9944   else
9945     {
9946       /* we did not allocate which means left
9947          already in a pointer register, then
9948          if size > 0 && this could be used again
9949          we have to point it back to where it
9950          belongs */
9951       if ((AOP_SIZE (right) > 1 &&
9952            !OP_SYMBOL (result)->remat &&
9953            (OP_SYMBOL (result)->liveTo > ic->seq ||
9954             ic->depth)) &&
9955           !pi)
9956         {
9957           int size = AOP_SIZE (right) - 1;
9958           while (size--)
9959             emitcode ("dec", "%s", rname);
9960         }
9961     }
9962
9963   /* done */
9964   if (pi) pi->generated = 1;
9965   freeAsmop (result, NULL, ic, TRUE);
9966   freeAsmop (right, NULL, ic, TRUE);
9967 }
9968
9969 /*-----------------------------------------------------------------*/
9970 /* genPagedPointerSet - emitcode for Paged pointer put             */
9971 /*-----------------------------------------------------------------*/
9972 static void
9973 genPagedPointerSet (operand * right,
9974                     operand * result,
9975                     iCode * ic,
9976                     iCode * pi)
9977 {
9978   asmop *aop = NULL;
9979   regs *preg = NULL;
9980   char *rname, *l;
9981   sym_link *retype, *letype;
9982
9983   D(emitcode (";     genPagedPointerSet",""));
9984
9985   retype = getSpec (operandType (right));
9986   letype = getSpec (operandType (result));
9987
9988   aopOp (result, ic, FALSE);
9989
9990   /* if the value is already in a pointer register
9991      then don't need anything more */
9992   if (!AOP_INPREG (AOP (result)))
9993     {
9994       /* otherwise get a free pointer register */
9995       aop = newAsmop (0);
9996       preg = getFreePtr (ic, &aop, FALSE);
9997       emitcode ("mov", "%s,%s",
9998                 preg->name,
9999                 aopGet (result, 0, FALSE, TRUE));
10000       rname = preg->name;
10001     }
10002   else
10003     rname = aopGet (result, 0, FALSE, FALSE);
10004
10005   aopOp (right, ic, FALSE);
10006
10007   /* if bitfield then unpack the bits */
10008   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10009     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10010   else
10011     {
10012       /* we have can just get the values */
10013       int size = AOP_SIZE (right);
10014       int offset = 0;
10015
10016       while (size--)
10017         {
10018           l = aopGet (right, offset, FALSE, TRUE);
10019
10020           MOVA (l);
10021           emitcode ("movx", "@%s,a", rname);
10022
10023           if (size || pi)
10024             emitcode ("inc", "%s", rname);
10025
10026           offset++;
10027         }
10028     }
10029
10030   /* now some housekeeping stuff */
10031   if (aop) /* we had to allocate for this iCode */
10032     {
10033       if (pi)
10034         aopPut (result, rname, 0, isOperandVolatile (result, FALSE));
10035       freeAsmop (NULL, aop, ic, TRUE);
10036     }
10037   else
10038     {
10039       /* we did not allocate which means left
10040          already in a pointer register, then
10041          if size > 0 && this could be used again
10042          we have to point it back to where it
10043          belongs */
10044       if (AOP_SIZE (right) > 1 &&
10045           !OP_SYMBOL (result)->remat &&
10046           (OP_SYMBOL (result)->liveTo > ic->seq ||
10047            ic->depth))
10048         {
10049           int size = AOP_SIZE (right) - 1;
10050           while (size--)
10051             emitcode ("dec", "%s", rname);
10052         }
10053     }
10054
10055   /* done */
10056   if (pi) pi->generated = 1;
10057   freeAsmop (result, NULL, ic, TRUE);
10058   freeAsmop (right, NULL, ic, TRUE);
10059
10060
10061 }
10062
10063 /*-----------------------------------------------------------------*/
10064 /* genFarPointerSet - set value from far space                     */
10065 /*-----------------------------------------------------------------*/
10066 static void
10067 genFarPointerSet (operand * right,
10068                   operand * result, iCode * ic, iCode * pi)
10069 {
10070   int size, offset;
10071   sym_link *retype = getSpec (operandType (right));
10072   sym_link *letype = getSpec (operandType (result));
10073
10074   D(emitcode (";     genFarPointerSet",""));
10075
10076   aopOp (result, ic, FALSE);
10077   loadDptrFromOperand (result, FALSE);
10078
10079   /* so dptr know contains the address */
10080   aopOp (right, ic, FALSE);
10081
10082   /* if bit then unpack */
10083   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10084     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10085   else
10086     {
10087       size = AOP_SIZE (right);
10088       offset = 0;
10089
10090       while (size--)
10091         {
10092           char *l = aopGet (right, offset++, FALSE, FALSE);
10093           MOVA (l);
10094           emitcode ("movx", "@dptr,a");
10095           if (size || pi)
10096             emitcode ("inc", "dptr");
10097         }
10098     }
10099   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10100     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10101     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10102     pi->generated=1;
10103   }
10104   freeAsmop (result, NULL, ic, TRUE);
10105   freeAsmop (right, NULL, ic, TRUE);
10106 }
10107
10108 /*-----------------------------------------------------------------*/
10109 /* genGenPointerSet - set value from generic pointer space         */
10110 /*-----------------------------------------------------------------*/
10111 static void
10112 genGenPointerSet (operand * right,
10113                   operand * result, iCode * ic, iCode * pi)
10114 {
10115   int size, offset;
10116   sym_link *retype = getSpec (operandType (right));
10117   sym_link *letype = getSpec (operandType (result));
10118
10119   D(emitcode (";     genGenPointerSet",""));
10120
10121   aopOp (result, ic, FALSE);
10122   loadDptrFromOperand (result, TRUE);
10123
10124   /* so dptr know contains the address */
10125   aopOp (right, ic, FALSE);
10126
10127   /* if bit then unpack */
10128   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10129     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10130   else
10131     {
10132       size = AOP_SIZE (right);
10133       offset = 0;
10134
10135       while (size--)
10136         {
10137           char *l = aopGet (right, offset++, FALSE, FALSE);
10138           MOVA (l);
10139           emitcode ("lcall", "__gptrput");
10140           if (size || pi)
10141             emitcode ("inc", "dptr");
10142         }
10143     }
10144
10145   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10146     aopPut (result, "dpl", 0, isOperandVolatile (result, FALSE));
10147     aopPut (result, "dph", 1, isOperandVolatile (result, FALSE));
10148     pi->generated=1;
10149   }
10150   freeAsmop (result, NULL, ic, TRUE);
10151   freeAsmop (right, NULL, ic, TRUE);
10152 }
10153
10154 /*-----------------------------------------------------------------*/
10155 /* genPointerSet - stores the value into a pointer location        */
10156 /*-----------------------------------------------------------------*/
10157 static void
10158 genPointerSet (iCode * ic, iCode *pi)
10159 {
10160   operand *right, *result;
10161   sym_link *type, *etype;
10162   int p_type;
10163
10164   D(emitcode (";     genPointerSet",""));
10165
10166   right = IC_RIGHT (ic);
10167   result = IC_RESULT (ic);
10168
10169   /* depending on the type of pointer we need to
10170      move it to the correct pointer register */
10171   type = operandType (result);
10172   etype = getSpec (type);
10173   /* if left is of type of pointer then it is simple */
10174   if (IS_PTR (type) && !IS_FUNC (type->next))
10175     {
10176       p_type = DCL_TYPE (type);
10177     }
10178   else
10179     {
10180       /* we have to go by the storage class */
10181       p_type = PTR_TYPE (SPEC_OCLS (etype));
10182     }
10183
10184   /* special case when cast remat */
10185   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10186       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10187           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10188           type = operandType (result);
10189           p_type = DCL_TYPE (type);
10190   }
10191   /* now that we have the pointer type we assign
10192      the pointer values */
10193   switch (p_type)
10194     {
10195
10196     case POINTER:
10197     case IPOINTER:
10198       genNearPointerSet (right, result, ic, pi);
10199       break;
10200
10201     case PPOINTER:
10202       genPagedPointerSet (right, result, ic, pi);
10203       break;
10204
10205     case FPOINTER:
10206       genFarPointerSet (right, result, ic, pi);
10207       break;
10208
10209     case GPOINTER:
10210       genGenPointerSet (right, result, ic, pi);
10211       break;
10212
10213     default:
10214       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10215               "genPointerSet: illegal pointer type");
10216     }
10217
10218 }
10219
10220 /*-----------------------------------------------------------------*/
10221 /* genIfx - generate code for Ifx statement                        */
10222 /*-----------------------------------------------------------------*/
10223 static void
10224 genIfx (iCode * ic, iCode * popIc)
10225 {
10226   operand *cond = IC_COND (ic);
10227   int isbit = 0;
10228   char *dup = NULL;
10229
10230   D(emitcode (";     genIfx",""));
10231
10232   aopOp (cond, ic, FALSE);
10233
10234   /* get the value into acc */
10235   if (AOP_TYPE (cond) != AOP_CRY)
10236     toBoolean (cond);
10237   else
10238     {
10239       isbit = 1;
10240       if (AOP(cond)->aopu.aop_dir)
10241         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10242     }
10243   /* the result is now in the accumulator or a directly addressable bit */
10244   freeAsmop (cond, NULL, ic, TRUE);
10245
10246   /* if there was something to be popped then do it */
10247   if (popIc)
10248     genIpop (popIc);
10249
10250   /* if the condition is a bit variable */
10251   if (isbit && dup)
10252     genIfxJump(ic, dup, NULL, NULL, NULL);
10253   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10254     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10255   else if (isbit && !IS_ITEMP (cond))
10256     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10257   else
10258     genIfxJump (ic, "a", NULL, NULL, NULL);
10259
10260   ic->generated = 1;
10261 }
10262
10263 /*-----------------------------------------------------------------*/
10264 /* genAddrOf - generates code for address of                       */
10265 /*-----------------------------------------------------------------*/
10266 static void
10267 genAddrOf (iCode * ic)
10268 {
10269   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10270   int size, offset;
10271
10272   D(emitcode (";     genAddrOf",""));
10273
10274   aopOp (IC_RESULT (ic), ic, FALSE);
10275
10276   /* if the operand is on the stack then we
10277      need to get the stack offset of this
10278      variable */
10279   if (sym->onStack)
10280     {
10281       /* if it has an offset then we need to compute
10282          it */
10283       if (sym->stack)
10284         {
10285           emitcode ("mov", "a,%s", SYM_BP (sym));
10286           emitcode ("add", "a,#0x%02x", ((sym->stack < 0) ?
10287                                          ((char) (sym->stack - _G.nRegsSaved)) :
10288                                          ((char) sym->stack)) & 0xff);
10289           aopPut (IC_RESULT (ic), "a", 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10290         }
10291       else
10292         {
10293           /* we can just move _bp */
10294           aopPut (IC_RESULT (ic), SYM_BP (sym), 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10295         }
10296       /* fill the result with zero */
10297       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10298
10299       offset = 1;
10300       while (size--)
10301         {
10302           aopPut (IC_RESULT (ic), zero, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10303         }
10304
10305       goto release;
10306     }
10307
10308   /* object not on stack then we need the name */
10309   size = AOP_SIZE (IC_RESULT (ic));
10310   offset = 0;
10311
10312   while (size--)
10313     {
10314       char s[SDCC_NAME_MAX];
10315       if (offset)
10316         sprintf (s, "#(%s >> %d)",
10317                  sym->rname,
10318                  offset * 8);
10319       else
10320         sprintf (s, "#%s", sym->rname);
10321       aopPut (IC_RESULT (ic), s, offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10322     }
10323
10324 release:
10325   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10326
10327 }
10328
10329 /*-----------------------------------------------------------------*/
10330 /* genFarFarAssign - assignment when both are in far space         */
10331 /*-----------------------------------------------------------------*/
10332 static void
10333 genFarFarAssign (operand * result, operand * right, iCode * ic)
10334 {
10335   int size = AOP_SIZE (right);
10336   int offset = 0;
10337   char *l;
10338
10339   D(emitcode (";     genFarFarAssign",""));
10340
10341   /* first push the right side on to the stack */
10342   while (size--)
10343     {
10344       l = aopGet (right, offset++, FALSE, FALSE);
10345       MOVA (l);
10346       emitcode ("push", "acc");
10347     }
10348
10349   freeAsmop (right, NULL, ic, FALSE);
10350   /* now assign DPTR to result */
10351   aopOp (result, ic, FALSE);
10352   size = AOP_SIZE (result);
10353   while (size--)
10354     {
10355       emitcode ("pop", "acc");
10356       aopPut (result, "a", --offset, isOperandVolatile (result, FALSE));
10357     }
10358   freeAsmop (result, NULL, ic, FALSE);
10359
10360 }
10361
10362 /*-----------------------------------------------------------------*/
10363 /* genAssign - generate code for assignment                        */
10364 /*-----------------------------------------------------------------*/
10365 static void
10366 genAssign (iCode * ic)
10367 {
10368   operand *result, *right;
10369   int size, offset;
10370   unsigned long lit = 0L;
10371
10372   D(emitcode(";     genAssign",""));
10373
10374   result = IC_RESULT (ic);
10375   right = IC_RIGHT (ic);
10376
10377   /* if they are the same */
10378   if (operandsEqu (result, right) &&
10379       !isOperandVolatile (result, FALSE) &&
10380       !isOperandVolatile (right, FALSE))
10381     return;
10382
10383   aopOp (right, ic, FALSE);
10384
10385   /* special case both in far space */
10386   if (AOP_TYPE (right) == AOP_DPTR &&
10387       IS_TRUE_SYMOP (result) &&
10388       isOperandInFarSpace (result))
10389     {
10390
10391       genFarFarAssign (result, right, ic);
10392       return;
10393     }
10394
10395   aopOp (result, ic, TRUE);
10396
10397   /* if they are the same registers */
10398   if (sameRegs (AOP (right), AOP (result)) &&
10399       !isOperandVolatile (result, FALSE) &&
10400       !isOperandVolatile (right, FALSE))
10401     goto release;
10402
10403   /* if the result is a bit */
10404   if (AOP_TYPE (result) == AOP_CRY)
10405     {
10406
10407       /* if the right size is a literal then
10408          we know what the value is */
10409       if (AOP_TYPE (right) == AOP_LIT)
10410         {
10411           if (((int) operandLitValue (right)))
10412             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10413           else
10414             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10415           goto release;
10416         }
10417
10418       /* the right is also a bit variable */
10419       if (AOP_TYPE (right) == AOP_CRY)
10420         {
10421           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10422           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10423           goto release;
10424         }
10425
10426       /* we need to or */
10427       toBoolean (right);
10428       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10429       goto release;
10430     }
10431
10432   /* bit variables done */
10433   /* general case */
10434   size = AOP_SIZE (result);
10435   offset = 0;
10436   if (AOP_TYPE (right) == AOP_LIT)
10437     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
10438   if ((size > 1) &&
10439       (AOP_TYPE (result) != AOP_REG) &&
10440       (AOP_TYPE (right) == AOP_LIT) &&
10441       !IS_FLOAT (operandType (right)) &&
10442       (lit < 256L))
10443     {
10444       while ((size) && (lit))
10445         {
10446           aopPut (result,
10447                   aopGet (right, offset, FALSE, FALSE),
10448                   offset,
10449                   isOperandVolatile (result, FALSE));
10450           lit >>= 8;
10451           offset++;
10452           size--;
10453         }
10454       emitcode ("clr", "a");
10455       while (size--)
10456         {
10457           aopPut (result, "a", offset, isOperandVolatile (result, FALSE));
10458           offset++;
10459         }
10460     }
10461   else
10462     {
10463       while (size--)
10464         {
10465           aopPut (result,
10466                   aopGet (right, offset, FALSE, FALSE),
10467                   offset,
10468                   isOperandVolatile (result, FALSE));
10469           offset++;
10470         }
10471     }
10472
10473 release:
10474   freeAsmop (right, NULL, ic, TRUE);
10475   freeAsmop (result, NULL, ic, TRUE);
10476 }
10477
10478 /*-----------------------------------------------------------------*/
10479 /* genJumpTab - generates code for jump table                      */
10480 /*-----------------------------------------------------------------*/
10481 static void
10482 genJumpTab (iCode * ic)
10483 {
10484   symbol *jtab,*jtablo,*jtabhi;
10485   char *l;
10486   unsigned int count;
10487
10488   D(emitcode (";     genJumpTab",""));
10489
10490   count = elementsInSet( IC_JTLABELS (ic) );
10491
10492   if( count <= 16 )
10493     {
10494       /* this algorithm needs 9 cycles and 7 + 3*n bytes
10495          if the switch argument is in a register.
10496          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
10497       /* (MB) What if peephole converts ljmp to sjmp or ret ???
10498          How will multiply by three be updated ???*/
10499       aopOp (IC_JTCOND (ic), ic, FALSE);
10500       /* get the condition into accumulator */
10501       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10502       MOVA (l);
10503       /* multiply by three */
10504       emitcode ("add", "a,acc");
10505       emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
10506       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10507
10508       jtab = newiTempLabel (NULL);
10509       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
10510       emitcode ("jmp", "@a+dptr");
10511       emitcode ("", "%05d$:", jtab->key + 100);
10512       /* now generate the jump labels */
10513       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10514            jtab = setNextItem (IC_JTLABELS (ic)))
10515         emitcode ("ljmp", "%05d$", jtab->key + 100);
10516     }
10517   else
10518     {
10519       /* this algorithm needs 14 cycles and 13 + 2*n bytes
10520          if the switch argument is in a register.
10521          For n>6 this algorithm may be more compact */
10522       jtablo = newiTempLabel (NULL);
10523       jtabhi = newiTempLabel (NULL);
10524
10525       /* get the condition into accumulator.
10526          Using b as temporary storage, if register push/pop is needed */
10527       aopOp (IC_JTCOND (ic), ic, FALSE);
10528       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
10529       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
10530           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
10531         {
10532           // (MB) what if B is in use???
10533           wassertl(!BINUSE, "B was in use");
10534           emitcode ("mov", "b,%s", l);
10535           l = "b";
10536         }
10537       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
10538       MOVA (l);
10539       if( count <= 112 )
10540         {
10541           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
10542           emitcode ("movc", "a,@a+pc");
10543           emitcode ("push", "acc");
10544
10545           MOVA (l);
10546           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
10547           emitcode ("movc", "a,@a+pc");
10548           emitcode ("push", "acc");
10549         }
10550       else
10551         {
10552           /* this scales up to n<=255, but needs two more bytes
10553              and changes dptr */
10554           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
10555           emitcode ("movc", "a,@a+dptr");
10556           emitcode ("push", "acc");
10557
10558           MOVA (l);
10559           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
10560           emitcode ("movc", "a,@a+dptr");
10561           emitcode ("push", "acc");
10562         }
10563
10564       emitcode ("ret", "");
10565
10566       /* now generate jump table, LSB */
10567       emitcode ("", "%05d$:", jtablo->key + 100);
10568       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10569            jtab = setNextItem (IC_JTLABELS (ic)))
10570         emitcode (".db", "%05d$", jtab->key + 100);
10571
10572       /* now generate jump table, MSB */
10573       emitcode ("", "%05d$:", jtabhi->key + 100);
10574       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
10575            jtab = setNextItem (IC_JTLABELS (ic)))
10576          emitcode (".db", "%05d$>>8", jtab->key + 100);
10577     }
10578 }
10579
10580 /*-----------------------------------------------------------------*/
10581 /* genCast - gen code for casting                                  */
10582 /*-----------------------------------------------------------------*/
10583 static void
10584 genCast (iCode * ic)
10585 {
10586   operand *result = IC_RESULT (ic);
10587   sym_link *ctype = operandType (IC_LEFT (ic));
10588   sym_link *rtype = operandType (IC_RIGHT (ic));
10589   operand *right = IC_RIGHT (ic);
10590   int size, offset;
10591
10592   D(emitcode(";     genCast",""));
10593
10594   /* if they are equivalent then do nothing */
10595   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
10596     return;
10597
10598   aopOp (right, ic, FALSE);
10599   aopOp (result, ic, FALSE);
10600
10601   /* if the result is a bit (and not a bitfield) */
10602   // if (AOP_TYPE (result) == AOP_CRY)
10603   if (IS_BITVAR (OP_SYMBOL (result)->type)
10604       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
10605     {
10606       /* if the right size is a literal then
10607          we know what the value is */
10608       if (AOP_TYPE (right) == AOP_LIT)
10609         {
10610           if (((int) operandLitValue (right)))
10611             aopPut (result, one, 0, isOperandVolatile (result, FALSE));
10612           else
10613             aopPut (result, zero, 0, isOperandVolatile (result, FALSE));
10614
10615           goto release;
10616         }
10617
10618       /* the right is also a bit variable */
10619       if (AOP_TYPE (right) == AOP_CRY)
10620         {
10621           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
10622           aopPut (result, "c", 0, isOperandVolatile (result, FALSE));
10623           goto release;
10624         }
10625
10626       /* we need to or */
10627       toBoolean (right);
10628       aopPut (result, "a", 0, isOperandVolatile (result, FALSE));
10629       goto release;
10630     }
10631
10632
10633   /* if they are the same size : or less */
10634   if (AOP_SIZE (result) <= AOP_SIZE (right))
10635     {
10636
10637       /* if they are in the same place */
10638       if (sameRegs (AOP (right), AOP (result)))
10639         goto release;
10640
10641       /* if they in different places then copy */
10642       size = AOP_SIZE (result);
10643       offset = 0;
10644       while (size--)
10645         {
10646           aopPut (result,
10647                   aopGet (right, offset, FALSE, FALSE),
10648                   offset,
10649                   isOperandVolatile (result, FALSE));
10650           offset++;
10651         }
10652       goto release;
10653     }
10654
10655
10656   /* if the result is of type pointer */
10657   if (IS_PTR (ctype))
10658     {
10659
10660       int p_type;
10661       sym_link *type = operandType (right);
10662       sym_link *etype = getSpec (type);
10663
10664       /* pointer to generic pointer */
10665       if (IS_GENPTR (ctype))
10666         {
10667           if (IS_PTR (type))
10668             p_type = DCL_TYPE (type);
10669           else
10670             {
10671               if (SPEC_SCLS(etype)==S_REGISTER) {
10672                 // let's assume it is a generic pointer
10673                 p_type=GPOINTER;
10674               } else {
10675                 /* we have to go by the storage class */
10676                 p_type = PTR_TYPE (SPEC_OCLS (etype));
10677               }
10678             }
10679
10680           /* the first two bytes are known */
10681           size = GPTRSIZE - 1;
10682           offset = 0;
10683           while (size--)
10684             {
10685               aopPut (result,
10686                       aopGet (right, offset, FALSE, FALSE),
10687                       offset,
10688                       isOperandVolatile (result, FALSE));
10689               offset++;
10690             }
10691           /* the last byte depending on type */
10692             {
10693                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
10694                 char gpValStr[10];
10695
10696                 if (gpVal == -1)
10697                 {
10698                     // pointerTypeToGPByte will have bitched.
10699                     exit(1);
10700                 }
10701
10702                 sprintf(gpValStr, "#0x%x", gpVal);
10703                 aopPut (result, gpValStr, GPTRSIZE - 1, isOperandVolatile (result, FALSE));
10704             }
10705           goto release;
10706         }
10707
10708       /* just copy the pointers */
10709       size = AOP_SIZE (result);
10710       offset = 0;
10711       while (size--)
10712         {
10713           aopPut (result,
10714                   aopGet (right, offset, FALSE, FALSE),
10715                   offset,
10716                   isOperandVolatile (result, FALSE));
10717           offset++;
10718         }
10719       goto release;
10720     }
10721
10722   /* so we now know that the size of destination is greater
10723      than the size of the source */
10724   /* we move to result for the size of source */
10725   size = AOP_SIZE (right);
10726   offset = 0;
10727   while (size--)
10728     {
10729       aopPut (result,
10730               aopGet (right, offset, FALSE, FALSE),
10731               offset,
10732               isOperandVolatile (result, FALSE));
10733       offset++;
10734     }
10735
10736   /* now depending on the sign of the source && destination */
10737   size = AOP_SIZE (result) - AOP_SIZE (right);
10738   /* if unsigned or not an integral type */
10739   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
10740     {
10741       while (size--)
10742         aopPut (result, zero, offset++, isOperandVolatile (result, FALSE));
10743     }
10744   else
10745     {
10746       /* we need to extend the sign :{ */
10747       char *l = aopGet (right, AOP_SIZE (right) - 1,
10748                         FALSE, FALSE);
10749       MOVA (l);
10750       emitcode ("rlc", "a");
10751       emitcode ("subb", "a,acc");
10752       while (size--)
10753         aopPut (result, "a", offset++, isOperandVolatile (result, FALSE));
10754     }
10755
10756   /* we are done hurray !!!! */
10757
10758 release:
10759   freeAsmop (right, NULL, ic, TRUE);
10760   freeAsmop (result, NULL, ic, TRUE);
10761
10762 }
10763
10764 /*-----------------------------------------------------------------*/
10765 /* genDjnz - generate decrement & jump if not zero instrucion      */
10766 /*-----------------------------------------------------------------*/
10767 static int
10768 genDjnz (iCode * ic, iCode * ifx)
10769 {
10770   symbol *lbl, *lbl1;
10771   if (!ifx)
10772     return 0;
10773
10774   D(emitcode (";     genDjnz",""));
10775
10776   /* if the if condition has a false label
10777      then we cannot save */
10778   if (IC_FALSE (ifx))
10779     return 0;
10780
10781   /* if the minus is not of the form
10782      a = a - 1 */
10783   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
10784       !IS_OP_LITERAL (IC_RIGHT (ic)))
10785     return 0;
10786
10787   if (operandLitValue (IC_RIGHT (ic)) != 1)
10788     return 0;
10789
10790   /* if the size of this greater than one then no
10791      saving */
10792   if (getSize (operandType (IC_RESULT (ic))) > 1)
10793     return 0;
10794
10795   /* otherwise we can save BIG */
10796   lbl = newiTempLabel (NULL);
10797   lbl1 = newiTempLabel (NULL);
10798
10799   aopOp (IC_RESULT (ic), ic, FALSE);
10800
10801   if (AOP_NEEDSACC(IC_RESULT(ic)))
10802   {
10803       /* If the result is accessed indirectly via
10804        * the accumulator, we must explicitly write
10805        * it back after the decrement.
10806        */
10807       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
10808
10809       if (strcmp(rByte, "a"))
10810       {
10811            /* Something is hopelessly wrong */
10812            fprintf(stderr, "*** warning: internal error at %s:%d\n",
10813                    __FILE__, __LINE__);
10814            /* We can just give up; the generated code will be inefficient,
10815             * but what the hey.
10816             */
10817            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10818            return 0;
10819       }
10820       emitcode ("dec", "%s", rByte);
10821       aopPut (IC_RESULT (ic), rByte, 0, isOperandVolatile (IC_RESULT (ic), FALSE));
10822       emitcode ("jnz", "%05d$", lbl->key + 100);
10823   }
10824   else if (IS_AOP_PREG (IC_RESULT (ic)))
10825     {
10826       emitcode ("dec", "%s",
10827                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10828       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
10829       emitcode ("jnz", "%05d$", lbl->key + 100);
10830     }
10831   else
10832     {
10833       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
10834                 lbl->key + 100);
10835     }
10836   emitcode ("sjmp", "%05d$", lbl1->key + 100);
10837   emitcode ("", "%05d$:", lbl->key + 100);
10838   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
10839   emitcode ("", "%05d$:", lbl1->key + 100);
10840
10841   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10842   ifx->generated = 1;
10843   return 1;
10844 }
10845
10846 /*-----------------------------------------------------------------*/
10847 /* genReceive - generate code for a receive iCode                  */
10848 /*-----------------------------------------------------------------*/
10849 static void
10850 genReceive (iCode * ic)
10851 {
10852   int size = getSize (operandType (IC_RESULT (ic)));
10853   int offset = 0;
10854
10855   D(emitcode (";     genReceive",""));
10856
10857   if (ic->argreg == 1)
10858     { /* first parameter */
10859       if (isOperandInFarSpace (IC_RESULT (ic)) &&
10860           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
10861            IS_TRUE_SYMOP (IC_RESULT (ic))))
10862         {
10863           regs *tempRegs[4];
10864           int receivingA = 0;
10865           int roffset = 0;
10866
10867           for (offset = 0; offset<size; offset++)
10868             if (!strcmp (fReturn[offset], "a"))
10869               receivingA = 1;
10870
10871           if (!receivingA)
10872             {
10873               if (size==1 || getTempRegs(tempRegs, size-1, ic))
10874                 {
10875                   for (offset = size-1; offset>0; offset--)
10876                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
10877                   emitcode("mov","a,%s", fReturn[0]);
10878                   _G.accInUse++;
10879                   aopOp (IC_RESULT (ic), ic, FALSE);
10880                   _G.accInUse--;
10881                   aopPut (IC_RESULT (ic), "a", offset,
10882                           isOperandVolatile (IC_RESULT (ic), FALSE));
10883                   for (offset = 1; offset<size; offset++)
10884                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset,
10885                             isOperandVolatile (IC_RESULT (ic), FALSE));
10886                   goto release;
10887                 }
10888             }
10889           else
10890             {
10891               if (getTempRegs(tempRegs, size, ic))
10892                 {
10893                   for (offset = 0; offset<size; offset++)
10894                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
10895                   aopOp (IC_RESULT (ic), ic, FALSE);
10896                   for (offset = 0; offset<size; offset++)
10897                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset,
10898                             isOperandVolatile (IC_RESULT (ic), FALSE));
10899                   goto release;
10900                 }
10901             }
10902
10903           offset = fReturnSizeMCS51 - size;
10904           while (size--)
10905             {
10906               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
10907                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
10908               offset++;
10909             }
10910           aopOp (IC_RESULT (ic), ic, FALSE);
10911           size = AOP_SIZE (IC_RESULT (ic));
10912           offset = 0;
10913           while (size--)
10914             {
10915               emitcode ("pop", "acc");
10916               aopPut (IC_RESULT (ic), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10917             }
10918         }
10919       else
10920         {
10921           _G.accInUse++;
10922           aopOp (IC_RESULT (ic), ic, FALSE);
10923           _G.accInUse--;
10924           assignResultValue (IC_RESULT (ic), NULL);
10925         }
10926     }
10927   else if (ic->argreg > 12)
10928     { /* bit parameters */
10929       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
10930         {
10931           aopOp (IC_RESULT (ic), ic, FALSE);
10932           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
10933           outBitC(IC_RESULT (ic));
10934         }
10935     }
10936   else
10937     { /* other parameters */
10938       int rb1off ;
10939       aopOp (IC_RESULT (ic), ic, FALSE);
10940       rb1off = ic->argreg;
10941       while (size--)
10942         {
10943           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
10944         }
10945     }
10946
10947 release:
10948   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10949 }
10950
10951 /*-----------------------------------------------------------------*/
10952 /* genDummyRead - generate code for dummy read of volatiles        */
10953 /*-----------------------------------------------------------------*/
10954 static void
10955 genDummyRead (iCode * ic)
10956 {
10957   operand *op;
10958   int size, offset;
10959
10960   D(emitcode(";     genDummyRead",""));
10961
10962   op = IC_RIGHT (ic);
10963   if (op && IS_SYMOP (op))
10964     {
10965       aopOp (op, ic, FALSE);
10966
10967       /* if the result is a bit */
10968       if (AOP_TYPE (op) == AOP_CRY)
10969         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10970       else
10971         {
10972           /* bit variables done */
10973           /* general case */
10974           size = AOP_SIZE (op);
10975           offset = 0;
10976           while (size--)
10977           {
10978             MOVA (aopGet (op, offset, FALSE, FALSE));
10979             offset++;
10980           }
10981         }
10982
10983       freeAsmop (op, NULL, ic, TRUE);
10984     }
10985
10986   op = IC_LEFT (ic);
10987   if (op && IS_SYMOP (op))
10988     {
10989       aopOp (op, ic, FALSE);
10990
10991       /* if the result is a bit */
10992       if (AOP_TYPE (op) == AOP_CRY)
10993         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
10994       else
10995         {
10996           /* bit variables done */
10997           /* general case */
10998           size = AOP_SIZE (op);
10999           offset = 0;
11000           while (size--)
11001           {
11002             MOVA (aopGet (op, offset, FALSE, FALSE));
11003             offset++;
11004           }
11005         }
11006
11007       freeAsmop (op, NULL, ic, TRUE);
11008     }
11009 }
11010
11011 /*-----------------------------------------------------------------*/
11012 /* genCritical - generate code for start of a critical sequence    */
11013 /*-----------------------------------------------------------------*/
11014 static void
11015 genCritical (iCode *ic)
11016 {
11017   symbol *tlbl = newiTempLabel (NULL);
11018
11019   D(emitcode(";     genCritical",""));
11020
11021   if (IC_RESULT (ic))
11022     {
11023       aopOp (IC_RESULT (ic), ic, TRUE);
11024       aopPut (IC_RESULT (ic), one, 0, 0);
11025       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11026       aopPut (IC_RESULT (ic), zero, 0, 0);
11027       emitcode ("", "%05d$:", (tlbl->key + 100));
11028       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11029     }
11030   else
11031     {
11032       emitcode ("setb", "c");
11033       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11034       emitcode ("clr", "c");
11035       emitcode ("", "%05d$:", (tlbl->key + 100));
11036       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11037     }
11038 }
11039
11040 /*-----------------------------------------------------------------*/
11041 /* genEndCritical - generate code for end of a critical sequence   */
11042 /*-----------------------------------------------------------------*/
11043 static void
11044 genEndCritical (iCode *ic)
11045 {
11046   D(emitcode(";     genEndCritical",""));
11047
11048   if (IC_RIGHT (ic))
11049     {
11050       aopOp (IC_RIGHT (ic), ic, FALSE);
11051       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11052         {
11053           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11054           emitcode ("mov", "ea,c");
11055         }
11056       else
11057         {
11058           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11059             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11060           emitcode ("rrc", "a");
11061           emitcode ("mov", "ea,c");
11062         }
11063       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11064     }
11065   else
11066     {
11067       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11068       emitcode ("mov", "ea,c");
11069     }
11070 }
11071
11072 /*-----------------------------------------------------------------*/
11073 /* gen51Code - generate code for 8051 based controllers            */
11074 /*-----------------------------------------------------------------*/
11075 void
11076 gen51Code (iCode * lic)
11077 {
11078   iCode *ic;
11079   int cln = 0;
11080   /* int cseq = 0; */
11081
11082   _G.currentFunc = NULL;
11083   lineHead = lineCurr = NULL;
11084
11085   /* print the allocation information */
11086   if (allocInfo && currFunc)
11087     printAllocInfo (currFunc, codeOutFile);
11088   /* if debug information required */
11089   if (options.debug && currFunc)
11090     {
11091       debugFile->writeFunction (currFunc, lic);
11092     }
11093   /* stack pointer name */
11094   if (options.useXstack)
11095     spname = "_spx";
11096   else
11097     spname = "sp";
11098
11099
11100   for (ic = lic; ic; ic = ic->next)
11101     {
11102       _G.current_iCode = ic;
11103
11104       if (ic->lineno && cln != ic->lineno)
11105         {
11106           if (options.debug)
11107             {
11108               debugFile->writeCLine (ic);
11109             }
11110           if (!options.noCcodeInAsm) {
11111             emitcode ("", ";%s:%d: %s", ic->filename, ic->lineno,
11112                       printCLine(ic->filename, ic->lineno));
11113           }
11114           cln = ic->lineno;
11115         }
11116       #if 0
11117       if (ic->seqPoint && ic->seqPoint != cseq)
11118         {
11119           emitcode ("", "; sequence point %d", ic->seqPoint);
11120           cseq = ic->seqPoint;
11121         }
11122       #endif
11123       if (options.iCodeInAsm) {
11124         char regsInUse[80];
11125         int i;
11126
11127         for (i=0; i<8; i++) {
11128           sprintf (&regsInUse[i],
11129                    "%c", ic->riu & (1<<i) ? i+'0' : '-');
11130         }
11131         regsInUse[i]=0;
11132         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11133       }
11134       /* if the result is marked as
11135          spilt and rematerializable or code for
11136          this has already been generated then
11137          do nothing */
11138       if (resultRemat (ic) || ic->generated)
11139         continue;
11140
11141       /* depending on the operation */
11142       switch (ic->op)
11143         {
11144         case '!':
11145           genNot (ic);
11146           break;
11147
11148         case '~':
11149           genCpl (ic);
11150           break;
11151
11152         case UNARYMINUS:
11153           genUminus (ic);
11154           break;
11155
11156         case IPUSH:
11157           genIpush (ic);
11158           break;
11159
11160         case IPOP:
11161           /* IPOP happens only when trying to restore a
11162              spilt live range, if there is an ifx statement
11163              following this pop then the if statement might
11164              be using some of the registers being popped which
11165              would destory the contents of the register so
11166              we need to check for this condition and handle it */
11167           if (ic->next &&
11168               ic->next->op == IFX &&
11169               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11170             genIfx (ic->next, ic);
11171           else
11172             genIpop (ic);
11173           break;
11174
11175         case CALL:
11176           genCall (ic);
11177           break;
11178
11179         case PCALL:
11180           genPcall (ic);
11181           break;
11182
11183         case FUNCTION:
11184           genFunction (ic);
11185           break;
11186
11187         case ENDFUNCTION:
11188           genEndFunction (ic);
11189           break;
11190
11191         case RETURN:
11192           genRet (ic);
11193           break;
11194
11195         case LABEL:
11196           genLabel (ic);
11197           break;
11198
11199         case GOTO:
11200           genGoto (ic);
11201           break;
11202
11203         case '+':
11204           genPlus (ic);
11205           break;
11206
11207         case '-':
11208           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11209             genMinus (ic);
11210           break;
11211
11212         case '*':
11213           genMult (ic);
11214           break;
11215
11216         case '/':
11217           genDiv (ic);
11218           break;
11219
11220         case '%':
11221           genMod (ic);
11222           break;
11223
11224         case '>':
11225           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11226           break;
11227
11228         case '<':
11229           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11230           break;
11231
11232         case LE_OP:
11233         case GE_OP:
11234         case NE_OP:
11235
11236           /* note these two are xlated by algebraic equivalence
11237              during parsing SDCC.y */
11238           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11239                   "got '>=' or '<=' shouldn't have come here");
11240           break;
11241
11242         case EQ_OP:
11243           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11244           break;
11245
11246         case AND_OP:
11247           genAndOp (ic);
11248           break;
11249
11250         case OR_OP:
11251           genOrOp (ic);
11252           break;
11253
11254         case '^':
11255           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11256           break;
11257
11258         case '|':
11259           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11260           break;
11261
11262         case BITWISEAND:
11263           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11264           break;
11265
11266         case INLINEASM:
11267           genInline (ic);
11268           break;
11269
11270         case RRC:
11271           genRRC (ic);
11272           break;
11273
11274         case RLC:
11275           genRLC (ic);
11276           break;
11277
11278         case GETHBIT:
11279           genGetHbit (ic);
11280           break;
11281
11282         case GETABIT:
11283           genGetAbit (ic);
11284           break;
11285
11286         case GETBYTE:
11287           genGetByte (ic);
11288           break;
11289
11290         case GETWORD:
11291           genGetWord (ic);
11292           break;
11293
11294         case LEFT_OP:
11295           genLeftShift (ic);
11296           break;
11297
11298         case RIGHT_OP:
11299           genRightShift (ic);
11300           break;
11301
11302         case GET_VALUE_AT_ADDRESS:
11303           genPointerGet (ic,
11304                          hasInc (IC_LEFT (ic), ic,
11305                                  getSize (operandType (IC_RESULT (ic)))),
11306                          ifxForOp (IC_RESULT (ic), ic) );
11307           break;
11308
11309         case '=':
11310           if (POINTER_SET (ic))
11311             genPointerSet (ic, hasInc (IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
11312           else
11313             genAssign (ic);
11314           break;
11315
11316         case IFX:
11317           genIfx (ic, NULL);
11318           break;
11319
11320         case ADDRESS_OF:
11321           genAddrOf (ic);
11322           break;
11323
11324         case JUMPTABLE:
11325           genJumpTab (ic);
11326           break;
11327
11328         case CAST:
11329           genCast (ic);
11330           break;
11331
11332         case RECEIVE:
11333           genReceive (ic);
11334           break;
11335
11336         case SEND:
11337           addSet (&_G.sendSet, ic);
11338           break;
11339
11340         case DUMMY_READ_VOLATILE:
11341           genDummyRead (ic);
11342           break;
11343
11344         case CRITICAL:
11345           genCritical (ic);
11346           break;
11347
11348         case ENDCRITICAL:
11349           genEndCritical (ic);
11350           break;
11351
11352         case SWAP:
11353           genSwap (ic);
11354           break;
11355
11356         default:
11357           ic = ic;
11358         }
11359     }
11360
11361   _G.current_iCode = NULL;
11362
11363   /* now we are ready to call the
11364      peep hole optimizer */
11365   if (!options.nopeep)
11366     peepHole (&lineHead);
11367
11368   /* now do the actual printing */
11369   printLine (lineHead, codeOutFile);
11370   return;
11371 }