b476551b38d6a179dbb67e3c2038f4df927e4721
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.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 "rtrack.h"
45 #include "gen.h"
46 #include "dbuf_string.h"
47
48 char *aopLiteral (value * val, int offset);
49 char *aopLiteralLong (value * val, int offset, int size);
50 extern int allocInfo;
51
52 /* this is the down and dirty file with all kinds of
53    kludgy & hacky stuff. This is what it is all about
54    CODE GENERATION for a specific MCU . some of the
55    routines may be reusable, will have to see */
56
57 static char *zero = "#0x00";
58 static char *one = "#0x01";
59 static char *spname;
60
61 char *fReturn8051[] =
62 {"dpl", "dph", "b", "a"};
63 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
64 char **fReturn = fReturn8051;
65 static char *accUse[] =
66 {"a", "b"};
67
68 static unsigned short rbank = -1;
69
70 #define REG_WITH_INDEX   mcs51_regWithIdx
71
72 #define AOP(op) op->aop
73 #define AOP_TYPE(op) AOP(op)->type
74 #define AOP_SIZE(op) AOP(op)->size
75 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
76                         AOP_TYPE(x) == AOP_R0))
77
78 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
79                          AOP_TYPE(x) == AOP_DPTR || \
80                          AOP(x)->paged))
81
82 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
83                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
84                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
85
86 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
87
88 #define R0INB   _G.bu.bs.r0InB
89 #define R1INB   _G.bu.bs.r1InB
90 #define OPINB   _G.bu.bs.OpInB
91 #define BINUSE  _G.bu.BInUse
92
93 static struct
94   {
95     short r0Pushed;
96     short r1Pushed;
97     union
98       {
99         struct
100           {
101             short r0InB : 2;//2 so we can see it overflow
102             short r1InB : 2;//2 so we can see it overflow
103             short OpInB : 2;//2 so we can see it overflow
104           } bs;
105         short BInUse;
106       } bu;
107     short accInUse;
108     short inLine;
109     short debugLine;
110     short nRegsSaved;
111     set *sendSet;
112     iCode *current_iCode;
113     symbol *currentFunc;
114   }
115 _G;
116
117 static char *rb1regs[] = {
118     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
119     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
120 };
121
122 extern struct dbuf_s *codeOutBuf;
123 static void saveRBank (int, iCode *, bool);
124
125 #define RESULTONSTACK(x) \
126                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
127                          IC_RESULT(x)->aop->type == AOP_STK )
128
129 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
130 #define MOVB(x)  movb(x)
131
132 #define CLRC     emitcode("clr","c")
133 #define SETC     emitcode("setb","c")
134
135 static lineNode *lineHead = NULL;
136 static lineNode *lineCurr = NULL;
137
138 static unsigned char SLMask[] =
139 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
140  0xE0, 0xC0, 0x80, 0x00};
141 static unsigned char SRMask[] =
142 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
143  0x07, 0x03, 0x01, 0x00};
144
145 #define LSB     0
146 #define MSB16   1
147 #define MSB24   2
148 #define MSB32   3
149
150 /*-----------------------------------------------------------------*/
151 /* emitcode - writes the code into a file : for now it is simple    */
152 /*-----------------------------------------------------------------*/
153 void
154 emitcode (const char *inst, const char *fmt,...)
155 {
156   va_list ap;
157   struct dbuf_s dbuf;
158   const char *lbp, *lb;
159
160   dbuf_init (&dbuf, INITIAL_INLINEASM);
161
162   va_start (ap, fmt);
163
164   if (inst && *inst)
165     {
166       dbuf_append_str (&dbuf, inst);
167
168       if (fmt && *fmt)
169         {
170           dbuf_append_char (&dbuf, '\t');
171           dbuf_tvprintf (&dbuf, fmt, ap);
172         }
173     }
174   else
175     {
176       dbuf_tvprintf (&dbuf, fmt, ap);
177     }
178
179   lbp = lb = dbuf_c_str(&dbuf);
180
181   while (isspace ((unsigned char)*lbp))
182     {
183       lbp++;
184     }
185
186   if (lbp && *lbp)
187     {
188       rtrackUpdate (lbp);
189
190       lineCurr = (lineCurr ?
191                   connectLine (lineCurr, newLineNode (lb)) :
192                   (lineHead = newLineNode (lb)));
193     }
194
195   lineCurr->isInline = _G.inLine;
196   lineCurr->isDebug = _G.debugLine;
197   lineCurr->ic = _G.current_iCode;
198   lineCurr->isComment = (*lbp==';');
199   va_end (ap);
200
201   dbuf_destroy(&dbuf);
202 }
203
204 static void
205 emitLabel (symbol *tlbl)
206 {
207   emitcode ("", "%05d$:", tlbl->key + 100);
208   lineCurr->isLabel = 1;
209 }
210
211 /*-----------------------------------------------------------------*/
212 /* mcs51_emitDebuggerSymbol - associate the current code location  */
213 /*   with a debugger symbol                                        */
214 /*-----------------------------------------------------------------*/
215 void
216 mcs51_emitDebuggerSymbol (char * debugSym)
217 {
218   _G.debugLine = 1;
219   emitcode ("", "%s ==.", debugSym);
220   _G.debugLine = 0;
221 }
222
223 /*-----------------------------------------------------------------*/
224 /* mova - moves specified value into accumulator                   */
225 /*-----------------------------------------------------------------*/
226 static void
227 mova (const char *x)
228 {
229   /* do some early peephole optimization */
230   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
231     return;
232
233   /* if it is a literal mov try to get it cheaper */
234   if (*x == '#' &&
235       rtrackMoveALit(x))
236     return;
237
238   emitcode("mov", "a,%s", x);
239 }
240
241 /*-----------------------------------------------------------------*/
242 /* movb - moves specified value into register b                    */
243 /*-----------------------------------------------------------------*/
244 static void
245 movb (const char *x)
246 {
247   /* do some early peephole optimization */
248   if (!strncmp(x, "b", 2))
249     return;
250
251   /* if it is a literal mov try to get it cheaper */
252   if (*x == '#')
253     {
254       emitcode("mov","b,%s", rtrackGetLit(x));
255       return;
256     }
257
258   emitcode("mov","b,%s", x);
259 }
260
261 /*-----------------------------------------------------------------*/
262 /* movc - moves specified value into the carry                     */
263 /*-----------------------------------------------------------------*/
264 static void
265 movc (const char *s)
266 {
267   if (!strcmp (s, zero))
268     CLRC;
269   else if (!strcmp (s, one))
270     SETC;
271   else if (strcmp (s, "c"))
272     {/* it's not in carry already */
273       MOVA (s);
274       /* set C, if a >= 1 */
275       emitcode ("add", "a,#0xff");
276     }
277 }
278
279 /*-----------------------------------------------------------------*/
280 /* pushB - saves register B if necessary                           */
281 /*-----------------------------------------------------------------*/
282 static bool
283 pushB (void)
284 {
285   bool pushedB = FALSE;
286
287   if (BINUSE)
288     {
289       emitcode ("push", "b");
290 //    printf("B was in use !\n");
291       pushedB = TRUE;
292     }
293   else
294     {
295       OPINB++;
296     }
297   return pushedB;
298 }
299
300 /*-----------------------------------------------------------------*/
301 /* popB - restores value of register B if necessary                */
302 /*-----------------------------------------------------------------*/
303 static void
304 popB (bool pushedB)
305 {
306   if (pushedB)
307     {
308       emitcode ("pop", "b");
309     }
310   else
311     {
312       OPINB--;
313     }
314 }
315
316 /*-----------------------------------------------------------------*/
317 /* pushReg - saves register                                        */
318 /*-----------------------------------------------------------------*/
319 static bool
320 pushReg (int index, bool bits_pushed)
321 {
322   regs * reg = REG_WITH_INDEX (index);
323   if (reg->type == REG_BIT)
324     {
325       if (!bits_pushed)
326         emitcode ("push", "%s", reg->base);
327       return TRUE;
328     }
329   else
330     emitcode ("push", "%s", reg->dname);
331   return bits_pushed;
332 }
333
334 /*-----------------------------------------------------------------*/
335 /* popReg - restores register                                      */
336 /*-----------------------------------------------------------------*/
337 static bool
338 popReg (int index, bool bits_popped)
339 {
340   regs * reg = REG_WITH_INDEX (index);
341   if (reg->type == REG_BIT)
342     {
343       if (!bits_popped)
344         emitcode ("pop", "%s", reg->base);
345       return TRUE;
346     }
347   else
348     emitcode ("pop", "%s", reg->dname);
349   return bits_popped;
350 }
351
352 /*-----------------------------------------------------------------*/
353 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
354 /*-----------------------------------------------------------------*/
355 static regs *
356 getFreePtr (iCode * ic, asmop ** aopp, bool result)
357 {
358   bool r0iu, r1iu;
359   bool r0ou, r1ou;
360
361   /* the logic: if r0 & r1 used in the instruction
362      then we are in trouble otherwise */
363
364   /* first check if r0 & r1 are used by this
365      instruction, in which case we are in trouble */
366   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
367   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
368   if (r0iu && r1iu) {
369       goto endOfWorld;
370     }
371
372   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
373   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
374
375   /* if no usage of r0 then return it */
376   if (!r0iu && !r0ou)
377     {
378       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
379       (*aopp)->type = AOP_R0;
380
381       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
382     }
383
384   /* if no usage of r1 then return it */
385   if (!r1iu && !r1ou)
386     {
387       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
388       (*aopp)->type = AOP_R1;
389
390       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
391     }
392
393   /* now we know they both have usage */
394   /* if r0 not used in this instruction */
395   if (!r0iu)
396     {
397       /* push it if not already pushed */
398       if (ic->op == IPUSH)
399         {
400           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
401           R0INB++;
402         }
403       else if (!_G.r0Pushed)
404         {
405           emitcode ("push", "%s",
406                     REG_WITH_INDEX (R0_IDX)->dname);
407           _G.r0Pushed++;
408         }
409
410       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
411       (*aopp)->type = AOP_R0;
412
413       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
414     }
415
416   /* if r1 not used then */
417
418   if (!r1iu)
419     {
420       /* push it if not already pushed */
421       if (ic->op == IPUSH)
422         {
423           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
424           R1INB++;
425         }
426       else if (!_G.r1Pushed)
427         {
428           emitcode ("push", "%s",
429                     REG_WITH_INDEX (R1_IDX)->dname);
430           _G.r1Pushed++;
431         }
432
433       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
434       (*aopp)->type = AOP_R1;
435       return REG_WITH_INDEX (R1_IDX);
436     }
437
438 endOfWorld:
439   /* I said end of world, but not quite end of world yet */
440   /* if this is a result then we can push it on the stack */
441   if (result)
442     {
443       (*aopp)->type = AOP_STK;
444       return NULL;
445     }
446   /* in the case that result AND left AND right needs a pointer reg
447      we can safely use the result's */
448   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
449     {
450       (*aopp)->type = AOP_R0;
451       return REG_WITH_INDEX (R0_IDX);
452     }
453   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
454     {
455       (*aopp)->type = AOP_R1;
456       return REG_WITH_INDEX (R1_IDX);
457     }
458
459   /* now this is REALLY the end of the world */
460   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
461           "getFreePtr should never reach here");
462   exit (1);
463 }
464
465
466 /*-----------------------------------------------------------------*/
467 /* getTempRegs - initialize an array of pointers to GPR registers */
468 /*               that are not in use. Returns 1 if the requested   */
469 /*               number of registers were available, 0 otherwise.  */
470 /*-----------------------------------------------------------------*/
471 int
472 getTempRegs(regs **tempRegs, int size, iCode *ic)
473 {
474   bitVect * freeRegs;
475   int i;
476   int offset;
477
478   if (!ic)
479     ic = _G.current_iCode;
480   if (!ic)
481     return 0;
482   if (!_G.currentFunc)
483     return 0;
484
485   freeRegs = newBitVect(8);
486   bitVectSetBit (freeRegs, R2_IDX);
487   bitVectSetBit (freeRegs, R3_IDX);
488   bitVectSetBit (freeRegs, R4_IDX);
489   bitVectSetBit (freeRegs, R5_IDX);
490   bitVectSetBit (freeRegs, R6_IDX);
491   bitVectSetBit (freeRegs, R7_IDX);
492
493   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
494     {
495       bitVect * newfreeRegs;
496       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
497       freeBitVect(freeRegs);
498       freeRegs = newfreeRegs;
499     }
500   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
501
502   offset = 0;
503   for (i=0; i<freeRegs->size; i++)
504     {
505       if (bitVectBitValue(freeRegs,i))
506         tempRegs[offset++] = REG_WITH_INDEX(i);
507       if (offset>=size)
508         {
509           freeBitVect(freeRegs);
510           return 1;
511         }
512     }
513
514   freeBitVect(freeRegs);
515   return 0;
516 }
517
518
519 /*-----------------------------------------------------------------*/
520 /* newAsmop - creates a new asmOp                                  */
521 /*-----------------------------------------------------------------*/
522 static asmop *
523 newAsmop (short type)
524 {
525   asmop *aop;
526
527   aop = Safe_calloc (1, sizeof (asmop));
528   aop->type = type;
529   aop->allocated = 1;
530   return aop;
531 }
532
533 /*-----------------------------------------------------------------*/
534 /* pointerCode - returns the code for a pointer type               */
535 /*-----------------------------------------------------------------*/
536 static int
537 pointerCode (sym_link * etype)
538 {
539
540   return PTR_TYPE (SPEC_OCLS (etype));
541
542 }
543
544 /*-----------------------------------------------------------------*/
545 /* leftRightUseAcc - returns size of accumulator use by operands   */
546 /*-----------------------------------------------------------------*/
547 static int
548 leftRightUseAcc(iCode *ic)
549 {
550   operand *op;
551   int size;
552   int accuseSize = 0;
553   int accuse = 0;
554
555   if (!ic)
556     {
557       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
558               "null iCode pointer");
559       return 0;
560     }
561
562   if (ic->op == IFX)
563     {
564       op = IC_COND (ic);
565       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
566         {
567           accuse = 1;
568           size = getSize (OP_SYMBOL (op)->type);
569           if (size>accuseSize)
570             accuseSize = size;
571         }
572     }
573   else if (ic->op == JUMPTABLE)
574     {
575       op = IC_JTCOND (ic);
576       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
577         {
578           accuse = 1;
579           size = getSize (OP_SYMBOL (op)->type);
580           if (size>accuseSize)
581             accuseSize = size;
582         }
583     }
584   else
585     {
586       op = IC_LEFT (ic);
587       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
588         {
589           accuse = 1;
590           size = getSize (OP_SYMBOL (op)->type);
591           if (size>accuseSize)
592             accuseSize = size;
593         }
594       op = IC_RIGHT (ic);
595       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
596         {
597           accuse = 1;
598           size = getSize (OP_SYMBOL (op)->type);
599           if (size>accuseSize)
600             accuseSize = size;
601         }
602     }
603
604   if (accuseSize)
605     return accuseSize;
606   else
607     return accuse;
608 }
609
610 /*-----------------------------------------------------------------*/
611 /* aopForSym - for a true symbol                                   */
612 /*-----------------------------------------------------------------*/
613 static asmop *
614 aopForSym (iCode * ic, symbol * sym, bool result)
615 {
616   asmop *aop;
617   memmap *space;
618   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
619
620   wassertl (ic != NULL, "Got a null iCode");
621   wassertl (sym != NULL, "Got a null symbol");
622
623   space = SPEC_OCLS (sym->etype);
624
625   /* if already has one */
626   if (sym->aop)
627     {
628       sym->aop->allocated++;
629       return sym->aop;
630     }
631
632   /* assign depending on the storage class */
633   /* if it is on the stack or indirectly addressable */
634   /* space we need to assign either r0 or r1 to it   */
635   if (sym->onStack || sym->iaccess)
636     {
637       sym->aop = aop = newAsmop (0);
638       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
639       aop->size = getSize (sym->type);
640
641       /* now assign the address of the variable to
642          the pointer register */
643       if (aop->type != AOP_STK)
644         {
645           if (sym->onStack)
646             {
647               signed char offset = ((sym->stack < 0) ?
648                          ((signed char) (sym->stack - _G.nRegsSaved)) :
649                          ((signed char) sym->stack)) & 0xff;
650
651               if ((abs(offset) <= 3) ||
652                   (accuse && (abs(offset) <= 7)))
653                 {
654                   emitcode ("mov", "%s,%s",
655                             aop->aopu.aop_ptr->name, SYM_BP (sym));
656                   while (offset < 0)
657                     {
658                       emitcode ("dec", aop->aopu.aop_ptr->name);
659                       offset++;
660                     }
661                   while (offset > 0)
662                     {
663                       emitcode ("inc", aop->aopu.aop_ptr->name);
664                       offset--;
665                     }
666                 }
667               else
668                 {
669                   if (accuse)
670                     emitcode ("push", "acc");
671                   emitcode ("mov", "a,%s", SYM_BP (sym));
672                   emitcode ("add", "a,#0x%02x", offset & 0xff);
673                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
674                   if (accuse)
675                     emitcode ("pop", "acc");
676                 }
677             }
678           else
679             {
680               emitcode ("mov", "%s,#%s",
681                         aop->aopu.aop_ptr->name,
682                         sym->rname);
683             }
684           aop->paged = space->paged;
685         }
686       else
687         aop->aopu.aop_stk = sym->stack;
688       return aop;
689     }
690
691   /* if in bit space */
692   if (IN_BITSPACE (space))
693     {
694       sym->aop = aop = newAsmop (AOP_CRY);
695       aop->aopu.aop_dir = sym->rname;
696       aop->size = getSize (sym->type);
697       return aop;
698     }
699   /* if it is in direct space */
700   if (IN_DIRSPACE (space))
701     {
702       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
703       //printTypeChainRaw(sym->type, NULL);
704       //printf("space = %s\n", space ? space->sname : "NULL");
705       sym->aop = aop = newAsmop (AOP_DIR);
706       aop->aopu.aop_dir = sym->rname;
707       aop->size = getSize (sym->type);
708       return aop;
709     }
710
711   /* special case for a function */
712   if (IS_FUNC (sym->type))
713     {
714       sym->aop = aop = newAsmop (AOP_IMMD);
715       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
716       aop->size = getSize (sym->type);
717       return aop;
718     }
719
720   /* only remaining is far space */
721   /* in which case DPTR gets the address */
722   sym->aop = aop = newAsmop (AOP_DPTR);
723   emitcode ("mov", "dptr,#%s", sym->rname);
724   aop->size = getSize (sym->type);
725
726   /* if it is in code space */
727   if (IN_CODESPACE (space))
728     aop->code = 1;
729
730   return aop;
731 }
732
733 /*-----------------------------------------------------------------*/
734 /* aopForRemat - rematerialzes an object                           */
735 /*-----------------------------------------------------------------*/
736 static asmop *
737 aopForRemat (symbol * sym)
738 {
739   iCode *ic = sym->rematiCode;
740   asmop *aop = newAsmop (AOP_IMMD);
741   int ptr_type = 0;
742   int val = 0;
743
744   for (;;)
745     {
746       if (ic->op == '+')
747         val += (int) operandLitValue (IC_RIGHT (ic));
748       else if (ic->op == '-')
749         val -= (int) operandLitValue (IC_RIGHT (ic));
750       else if (IS_CAST_ICODE(ic)) {
751               sym_link *from_type = operandType(IC_RIGHT(ic));
752               aop->aopu.aop_immd.from_cast_remat = 1;
753               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
754               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
755               continue;
756       } else break;
757
758       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
759     }
760
761   if (val)
762     {
763       SNPRINTF (buffer, sizeof(buffer),
764                 "(%s %c 0x%04x)",
765                 OP_SYMBOL (IC_LEFT (ic))->rname,
766                 val >= 0 ? '+' : '-',
767                 abs (val) & 0xffff);
768     }
769   else
770     {
771       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
772     }
773
774   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
775   /* set immd2 field if required */
776   if (aop->aopu.aop_immd.from_cast_remat)
777     {
778       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
779       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
780     }
781
782   return aop;
783 }
784
785 /*-----------------------------------------------------------------*/
786 /* regsInCommon - two operands have some registers in common       */
787 /*-----------------------------------------------------------------*/
788 static bool
789 regsInCommon (operand * op1, operand * op2)
790 {
791   symbol *sym1, *sym2;
792   int i;
793
794   /* if they have registers in common */
795   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
796     return FALSE;
797
798   sym1 = OP_SYMBOL (op1);
799   sym2 = OP_SYMBOL (op2);
800
801   if (sym1->nRegs == 0 || sym2->nRegs == 0)
802     return FALSE;
803
804   for (i = 0; i < sym1->nRegs; i++)
805     {
806       int j;
807       if (!sym1->regs[i])
808         continue;
809
810       for (j = 0; j < sym2->nRegs; j++)
811         {
812           if (!sym2->regs[j])
813             continue;
814
815           if (sym2->regs[j] == sym1->regs[i])
816             return TRUE;
817         }
818     }
819
820   return FALSE;
821 }
822
823 /*-----------------------------------------------------------------*/
824 /* operandsEqu - equivalent                                        */
825 /*-----------------------------------------------------------------*/
826 static bool
827 operandsEqu (operand * op1, operand * op2)
828 {
829   symbol *sym1, *sym2;
830
831   /* if they're not symbols */
832   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
833     return FALSE;
834
835   sym1 = OP_SYMBOL (op1);
836   sym2 = OP_SYMBOL (op2);
837
838   /* if both are itemps & one is spilt
839      and the other is not then false */
840   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
841       sym1->isspilt != sym2->isspilt)
842     return FALSE;
843
844   /* if they are the same */
845   if (sym1 == sym2)
846     return TRUE;
847
848   /* if they have the same rname */
849   if (sym1->rname[0] && sym2->rname[0] &&
850       strcmp (sym1->rname, sym2->rname) == 0 &&
851       !(IS_PARM (op2) && IS_ITEMP (op1)))
852     return TRUE;
853
854   /* if left is a tmp & right is not */
855   if (IS_ITEMP (op1) &&
856       !IS_ITEMP (op2) &&
857       sym1->isspilt &&
858       (sym1->usl.spillLoc == sym2))
859     return TRUE;
860
861   if (IS_ITEMP (op2) &&
862       !IS_ITEMP (op1) &&
863       sym2->isspilt &&
864       sym1->level > 0 &&
865       (sym2->usl.spillLoc == sym1))
866     return TRUE;
867
868   return FALSE;
869 }
870
871 /*-----------------------------------------------------------------*/
872 /* sameByte - two asmops have the same address at given offsets    */
873 /*-----------------------------------------------------------------*/
874 static bool
875 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
876 {
877   if (aop1 == aop2 && off1 == off2)
878     return TRUE;
879
880   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
881     return FALSE;
882
883   if (aop1->type != aop2->type)
884     return FALSE;
885
886   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
887     return FALSE;
888
889   return TRUE;
890 }
891
892 /*-----------------------------------------------------------------*/
893 /* sameRegs - two asmops have the same registers                   */
894 /*-----------------------------------------------------------------*/
895 static bool
896 sameRegs (asmop * aop1, asmop * aop2)
897 {
898   int i;
899
900   if (aop1 == aop2)
901     return TRUE;
902
903   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
904     return FALSE;
905
906   if (aop1->type != aop2->type)
907     return FALSE;
908
909   if (aop1->size != aop2->size)
910     return FALSE;
911
912   for (i = 0; i < aop1->size; i++)
913     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
914       return FALSE;
915
916   return TRUE;
917 }
918
919 /*-----------------------------------------------------------------*/
920 /* aopOp - allocates an asmop for an operand  :                    */
921 /*-----------------------------------------------------------------*/
922 static void
923 aopOp (operand * op, iCode * ic, bool result)
924 {
925   asmop *aop;
926   symbol *sym;
927   int i;
928
929   if (!op)
930     return;
931
932   /* if this a literal */
933   if (IS_OP_LITERAL (op))
934     {
935       op->aop = aop = newAsmop (AOP_LIT);
936       aop->aopu.aop_lit = op->operand.valOperand;
937       aop->size = getSize (operandType (op));
938       return;
939     }
940
941   /* if already has a asmop then continue */
942   if (op->aop)
943     {
944       op->aop->allocated++;
945       return;
946     }
947
948   /* if the underlying symbol has a aop */
949   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
950     {
951       op->aop = OP_SYMBOL (op)->aop;
952       op->aop->allocated++;
953       return;
954     }
955
956   /* if this is a true symbol */
957   if (IS_TRUE_SYMOP (op))
958     {
959       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
960       return;
961     }
962
963   /* this is a temporary : this has
964      only five choices :
965      a) register
966      b) spillocation
967      c) rematerialize
968      d) conditional
969      e) can be a return use only */
970
971   sym = OP_SYMBOL (op);
972
973   /* if the type is a conditional */
974   if (sym->regType == REG_CND)
975     {
976       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
977       aop->size = 0;
978       return;
979     }
980
981   /* if it is spilt then two situations
982      a) is rematerialize
983      b) has a spill location */
984   if (sym->isspilt || sym->nRegs == 0)
985     {
986
987       /* rematerialize it NOW */
988       if (sym->remat)
989         {
990           sym->aop = op->aop = aop = aopForRemat (sym);
991           aop->size = getSize (sym->type);
992           return;
993         }
994
995       if (sym->accuse)
996         {
997           int i;
998           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
999           aop->size = getSize (sym->type);
1000           for (i = 0; i < 2; i++)
1001             aop->aopu.aop_str[i] = accUse[i];
1002           return;
1003         }
1004
1005       if (sym->ruonly)
1006         {
1007           unsigned i;
1008
1009           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1010           aop->size = getSize (sym->type);
1011           for (i = 0; i < fReturnSizeMCS51; i++)
1012             aop->aopu.aop_str[i] = fReturn[i];
1013           return;
1014         }
1015
1016       if (sym->usl.spillLoc)
1017         {
1018           asmop *oldAsmOp = NULL;
1019
1020           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1021             {
1022               /* force a new aop if sizes differ */
1023               oldAsmOp = sym->usl.spillLoc->aop;
1024               sym->usl.spillLoc->aop = NULL;
1025             }
1026           sym->aop = op->aop = aop =
1027                      aopForSym (ic, sym->usl.spillLoc, result);
1028           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1029             {
1030               /* Don't reuse the new aop, go with the last one */
1031               sym->usl.spillLoc->aop = oldAsmOp;
1032             }
1033           aop->size = getSize (sym->type);
1034           return;
1035         }
1036
1037       /* else must be a dummy iTemp */
1038       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1039       aop->size = getSize (sym->type);
1040       return;
1041     }
1042
1043   /* if the type is a bit register */
1044   if (sym->regType == REG_BIT)
1045     {
1046       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1047       aop->size = sym->nRegs;//1???
1048       aop->aopu.aop_reg[0] = sym->regs[0];
1049       aop->aopu.aop_dir = sym->regs[0]->name;
1050       return;
1051     }
1052
1053   /* must be in a register */
1054   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1055   aop->size = sym->nRegs;
1056   for (i = 0; i < sym->nRegs; i++)
1057     aop->aopu.aop_reg[i] = sym->regs[i];
1058 }
1059
1060 /*-----------------------------------------------------------------*/
1061 /* freeAsmop - free up the asmop given to an operand               */
1062 /*----------------------------------------------------------------*/
1063 static void
1064 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1065 {
1066   asmop *aop;
1067
1068   if (!op)
1069     aop = aaop;
1070   else
1071     aop = op->aop;
1072
1073   if (!aop)
1074     return;
1075
1076   aop->allocated--;
1077
1078   if (aop->allocated)
1079     goto dealloc;
1080
1081   /* depending on the asmop type only three cases need work
1082      AOP_R0, AOP_R1 & AOP_STK */
1083   switch (aop->type)
1084     {
1085     case AOP_R0:
1086       if (R0INB)
1087         {
1088           emitcode ("mov", "r0,b");
1089           R0INB--;
1090         }
1091       else if (_G.r0Pushed)
1092         {
1093           if (pop)
1094             {
1095               emitcode ("pop", "ar0");
1096               _G.r0Pushed--;
1097             }
1098         }
1099       bitVectUnSetBit (ic->rUsed, R0_IDX);
1100       break;
1101
1102     case AOP_R1:
1103       if (R1INB)
1104         {
1105           emitcode ("mov", "r1,b");
1106           R1INB--;
1107         }
1108       else if (_G.r1Pushed)
1109         {
1110           if (pop)
1111             {
1112               emitcode ("pop", "ar1");
1113               _G.r1Pushed--;
1114             }
1115         }
1116       bitVectUnSetBit (ic->rUsed, R1_IDX);
1117       break;
1118
1119     case AOP_STK:
1120       {
1121         int sz = aop->size;
1122         int stk = aop->aopu.aop_stk + aop->size - 1;
1123         bitVectUnSetBit (ic->rUsed, R0_IDX);
1124         bitVectUnSetBit (ic->rUsed, R1_IDX);
1125
1126         getFreePtr (ic, &aop, FALSE);
1127
1128         if (stk)
1129           {
1130             emitcode ("mov", "a,_bp");
1131             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1132             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1133           }
1134         else
1135           {
1136             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1137           }
1138
1139         while (sz--)
1140           {
1141             emitcode ("pop", "acc");
1142             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1143             if (!sz)
1144               break;
1145             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1146           }
1147         op->aop = aop;
1148         freeAsmop (op, NULL, ic, TRUE);
1149         if (_G.r1Pushed)
1150           {
1151             emitcode ("pop", "ar1");
1152             _G.r1Pushed--;
1153           }
1154         if (_G.r0Pushed)
1155           {
1156             emitcode ("pop", "ar0");
1157             _G.r0Pushed--;
1158           }
1159       }
1160       break;
1161     }
1162
1163 dealloc:
1164   /* all other cases just dealloc */
1165   if (op)
1166     {
1167       op->aop = NULL;
1168       if (IS_SYMOP (op))
1169         {
1170           OP_SYMBOL (op)->aop = NULL;
1171           /* if the symbol has a spill */
1172           if (SPIL_LOC (op))
1173             SPIL_LOC (op)->aop = NULL;
1174         }
1175     }
1176 }
1177
1178 /*------------------------------------------------------------------*/
1179 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1180 /*                      pop r0 or r1 off stack if pushed            */
1181 /*------------------------------------------------------------------*/
1182 static void
1183 freeForBranchAsmop (operand * op)
1184 {
1185   asmop *aop;
1186
1187   if (!op)
1188     return;
1189
1190   aop = op->aop;
1191
1192   if (!aop)
1193     return;
1194
1195   if (!aop->allocated)
1196     return;
1197
1198   switch (aop->type)
1199     {
1200     case AOP_R0:
1201       if (R0INB)
1202         {
1203           emitcode ("mov", "r0,b");
1204         }
1205       else if (_G.r0Pushed)
1206         {
1207           emitcode ("pop", "ar0");
1208         }
1209       break;
1210
1211     case AOP_R1:
1212       if (R1INB)
1213         {
1214           emitcode ("mov", "r1,b");
1215         }
1216       else if (_G.r1Pushed)
1217         {
1218           emitcode ("pop", "ar1");
1219         }
1220       break;
1221
1222     case AOP_STK:
1223       {
1224         int sz = aop->size;
1225         int stk = aop->aopu.aop_stk + aop->size - 1;
1226
1227         emitcode ("mov", "b,r0");
1228         if (stk)
1229           {
1230             emitcode ("mov", "a,_bp");
1231             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1232             emitcode ("mov", "r0,a");
1233           }
1234         else
1235           {
1236             emitcode ("mov", "r0,_bp");
1237           }
1238
1239         while (sz--)
1240           {
1241             emitcode ("pop", "acc");
1242             emitcode ("mov", "@r0,a");
1243             if (!sz)
1244               break;
1245             emitcode ("dec", "r0");
1246           }
1247         emitcode ("mov", "r0,b");
1248       }
1249     }
1250
1251 }
1252
1253 /*-----------------------------------------------------------------*/
1254 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1255 /*                 clobber the accumulator                         */
1256 /*-----------------------------------------------------------------*/
1257 static bool
1258 aopGetUsesAcc (operand * oper, int offset)
1259 {
1260   asmop * aop = AOP (oper);
1261
1262   if (offset > (aop->size - 1))
1263     return FALSE;
1264
1265   switch (aop->type)
1266     {
1267
1268     case AOP_R0:
1269     case AOP_R1:
1270       if (aop->paged)
1271         return TRUE;
1272       return FALSE;
1273     case AOP_DPTR:
1274       return TRUE;
1275     case AOP_IMMD:
1276       return FALSE;
1277     case AOP_DIR:
1278       return FALSE;
1279     case AOP_REG:
1280       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1281       return FALSE;
1282     case AOP_CRY:
1283       return TRUE;
1284     case AOP_ACC:
1285       if (offset)
1286         return FALSE;
1287       return TRUE;
1288     case AOP_LIT:
1289       return FALSE;
1290     case AOP_STR:
1291       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1292         return TRUE;
1293       return FALSE;
1294     case AOP_DUMMY:
1295       return FALSE;
1296     default:
1297       /* Error case --- will have been caught already */
1298       wassert(0);
1299       return FALSE;
1300     }
1301 }
1302
1303 /*-------------------------------------------------------------------*/
1304 /* aopGet - for fetching value of the aop                            */
1305 /*-------------------------------------------------------------------*/
1306 static char *
1307 aopGet (operand * oper, int offset, bool bit16, bool dname)
1308 {
1309   asmop * aop = AOP (oper);
1310
1311   /* offset is greater than
1312      size then zero */
1313   if (offset > (aop->size - 1) &&
1314       aop->type != AOP_LIT)
1315     return zero;
1316
1317   /* depending on type */
1318   switch (aop->type)
1319     {
1320     case AOP_DUMMY:
1321       return zero;
1322
1323     case AOP_R0:
1324     case AOP_R1:
1325       /* if we need to increment it */
1326       while (offset > aop->coff)
1327         {
1328           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1329           aop->coff++;
1330         }
1331
1332       while (offset < aop->coff)
1333         {
1334           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1335           aop->coff--;
1336         }
1337
1338       aop->coff = offset;
1339       if (aop->paged)
1340         {
1341           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1342           return (dname ? "acc" : "a");
1343         }
1344       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1345       return Safe_strdup(buffer);
1346
1347     case AOP_DPTR:
1348       if (aop->code && aop->coff==0 && offset>=1) {
1349         emitcode ("mov", "a,#0x%02x", offset);
1350         emitcode ("movc", "a,@a+dptr");
1351         return (dname ? "acc" : "a");
1352       }
1353
1354       while (offset > aop->coff)
1355         {
1356           emitcode ("inc", "dptr");
1357           aop->coff++;
1358         }
1359
1360       while (offset < aop->coff)
1361         {
1362           emitcode ("lcall", "__decdptr");
1363           aop->coff--;
1364         }
1365
1366       aop->coff = offset;
1367       if (aop->code)
1368         {
1369           emitcode ("clr", "a");
1370           emitcode ("movc", "a,@a+dptr");
1371         }
1372       else
1373         {
1374           emitcode ("movx", "a,@dptr");
1375         }
1376       return (dname ? "acc" : "a");
1377
1378     case AOP_IMMD:
1379       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1380         {
1381           SNPRINTF(buffer, sizeof(buffer),
1382                    "%s",aop->aopu.aop_immd.aop_immd2);
1383         }
1384       else if (bit16)
1385         {
1386           SNPRINTF(buffer, sizeof(buffer),
1387                    "#%s", aop->aopu.aop_immd.aop_immd1);
1388         }
1389       else if (offset)
1390         {
1391           SNPRINTF (buffer, sizeof(buffer),
1392                     "#(%s >> %d)",
1393                     aop->aopu.aop_immd.aop_immd1,
1394                     offset * 8);
1395         }
1396       else
1397         {
1398           SNPRINTF (buffer, sizeof(buffer),
1399                     "#%s",
1400                     aop->aopu.aop_immd.aop_immd1);
1401         }
1402       return Safe_strdup(buffer);
1403
1404     case AOP_DIR:
1405       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1406         {
1407           SNPRINTF (buffer, sizeof(buffer),
1408                     "(%s >> %d)",
1409                     aop->aopu.aop_dir, offset * 8);
1410         }
1411       else if (offset)
1412         {
1413           SNPRINTF (buffer, sizeof(buffer),
1414                     "(%s + %d)",
1415                     aop->aopu.aop_dir,
1416                     offset);
1417         }
1418       else
1419         {
1420           SNPRINTF (buffer, sizeof(buffer),
1421                     "%s",
1422                     aop->aopu.aop_dir);
1423         }
1424
1425       return Safe_strdup(buffer);
1426
1427     case AOP_REG:
1428       if (dname)
1429         return aop->aopu.aop_reg[offset]->dname;
1430       else
1431         return aop->aopu.aop_reg[offset]->name;
1432
1433     case AOP_CRY:
1434       emitcode ("clr", "a");
1435       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1436       emitcode ("rlc", "a");
1437       return (dname ? "acc" : "a");
1438
1439     case AOP_ACC:
1440       if (!offset && dname)
1441         return "acc";
1442       return aop->aopu.aop_str[offset];
1443
1444     case AOP_LIT:
1445       return aopLiteral (aop->aopu.aop_lit, offset);
1446
1447     case AOP_STR:
1448       aop->coff = offset;
1449       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1450           dname)
1451         return "acc";
1452
1453       return aop->aopu.aop_str[offset];
1454
1455     }
1456
1457   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1458           "aopget got unsupported aop->type");
1459   exit (1);
1460 }
1461
1462 /*-----------------------------------------------------------------*/
1463 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1464 /*                 clobber the accumulator                         */
1465 /*-----------------------------------------------------------------*/
1466 static bool
1467 aopPutUsesAcc (operand * oper, const char *s, int offset)
1468 {
1469   asmop * aop = AOP (oper);
1470
1471   if (offset > (aop->size - 1))
1472     return FALSE;
1473
1474   switch (aop->type)
1475     {
1476     case AOP_DUMMY:
1477       return TRUE;
1478     case AOP_DIR:
1479       return FALSE;
1480     case AOP_REG:
1481       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1482       return FALSE;
1483     case AOP_DPTR:
1484       return TRUE;
1485     case AOP_R0:
1486     case AOP_R1:
1487       return ((aop->paged) || (*s == '@'));
1488     case AOP_STK:
1489       return (*s == '@');
1490     case AOP_CRY:
1491       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1492     case AOP_STR:
1493       return FALSE;
1494     case AOP_IMMD:
1495       return FALSE;
1496     case AOP_ACC:
1497       return FALSE;
1498     default:
1499       /* Error case --- will have been caught already */
1500       wassert(0);
1501       return FALSE;
1502     }
1503 }
1504
1505 /*-----------------------------------------------------------------*/
1506 /* aopPut - puts a string for a aop and indicates if acc is in use */
1507 /*-----------------------------------------------------------------*/
1508 static bool
1509 aopPut (operand * result, const char *s, int offset)
1510 {
1511   bool bvolatile = isOperandVolatile (result, FALSE);
1512   bool accuse = FALSE;
1513   asmop * aop = AOP (result);
1514
1515   if (aop->size && offset > (aop->size - 1))
1516     {
1517       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1518               "aopPut got offset > aop->size");
1519       exit (1);
1520     }
1521
1522   /* will assign value to value */
1523   /* depending on where it is ofcourse */
1524   switch (aop->type)
1525     {
1526     case AOP_DUMMY:
1527       MOVA (s);         /* read s in case it was volatile */
1528       accuse = TRUE;
1529       break;
1530
1531     case AOP_DIR:
1532       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1533         {
1534           SNPRINTF (buffer, sizeof(buffer),
1535                     "(%s >> %d)",
1536                     aop->aopu.aop_dir, offset * 8);
1537         }
1538       else if (offset)
1539         {
1540           SNPRINTF (buffer, sizeof(buffer),
1541                     "(%s + %d)",
1542                     aop->aopu.aop_dir, offset);
1543         }
1544       else
1545         {
1546           SNPRINTF (buffer, sizeof(buffer),
1547                     "%s",
1548                     aop->aopu.aop_dir);
1549         }
1550
1551       if (strcmp (buffer, s) || bvolatile)
1552         {
1553           emitcode ("mov", "%s,%s", buffer, s);
1554         }
1555       if (!strcmp (buffer, "acc"))
1556         {
1557           accuse = TRUE;
1558         }
1559       break;
1560
1561     case AOP_REG:
1562       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1563           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1564         {
1565           if (*s == '@' ||
1566               strcmp (s, "r0") == 0 ||
1567               strcmp (s, "r1") == 0 ||
1568               strcmp (s, "r2") == 0 ||
1569               strcmp (s, "r3") == 0 ||
1570               strcmp (s, "r4") == 0 ||
1571               strcmp (s, "r5") == 0 ||
1572               strcmp (s, "r6") == 0 ||
1573               strcmp (s, "r7") == 0)
1574             {
1575               emitcode ("mov", "%s,%s",
1576                         aop->aopu.aop_reg[offset]->dname, s);
1577             }
1578           else
1579             {
1580               emitcode ("mov", "%s,%s",
1581                         aop->aopu.aop_reg[offset]->name, s);
1582             }
1583         }
1584       break;
1585
1586     case AOP_DPTR:
1587       if (aop->code)
1588         {
1589           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1590                   "aopPut writing to code space");
1591           exit (1);
1592         }
1593
1594       while (offset > aop->coff)
1595         {
1596           aop->coff++;
1597           emitcode ("inc", "dptr");
1598         }
1599
1600       while (offset < aop->coff)
1601         {
1602           aop->coff--;
1603           emitcode ("lcall", "__decdptr");
1604         }
1605
1606       aop->coff = offset;
1607
1608       /* if not in accumulator */
1609       MOVA (s);
1610
1611       emitcode ("movx", "@dptr,a");
1612       break;
1613
1614     case AOP_R0:
1615     case AOP_R1:
1616       while (offset > aop->coff)
1617         {
1618           aop->coff++;
1619           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1620         }
1621       while (offset < aop->coff)
1622         {
1623           aop->coff--;
1624           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1625         }
1626       aop->coff = offset;
1627
1628       if (aop->paged)
1629         {
1630           MOVA (s);
1631           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1632         }
1633       else if (*s == '@')
1634         {
1635           MOVA (s);
1636           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1637         }
1638       else if (strcmp (s, "r0") == 0 ||
1639                strcmp (s, "r1") == 0 ||
1640                strcmp (s, "r2") == 0 ||
1641                strcmp (s, "r3") == 0 ||
1642                strcmp (s, "r4") == 0 ||
1643                strcmp (s, "r5") == 0 ||
1644                strcmp (s, "r6") == 0 ||
1645                strcmp (s, "r7") == 0)
1646         {
1647           char buffer[10];
1648           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1649           emitcode ("mov", "@%s,%s",
1650                     aop->aopu.aop_ptr->name, buffer);
1651         }
1652       else
1653         {
1654           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1655         }
1656       break;
1657
1658     case AOP_STK:
1659       if (strcmp (s, "a") == 0)
1660         {
1661           emitcode ("push", "acc");
1662         }
1663       else if (*s=='@')
1664         {
1665           MOVA(s);
1666           emitcode ("push", "acc");
1667         }
1668       else if (strcmp (s, "r0") == 0 ||
1669                strcmp (s, "r1") == 0 ||
1670                strcmp (s, "r2") == 0 ||
1671                strcmp (s, "r3") == 0 ||
1672                strcmp (s, "r4") == 0 ||
1673                strcmp (s, "r5") == 0 ||
1674                strcmp (s, "r6") == 0 ||
1675                strcmp (s, "r7") == 0)
1676         {
1677           char buffer[10];
1678           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1679           emitcode ("push", buffer);
1680         }
1681       else
1682         {
1683           emitcode ("push", s);
1684         }
1685
1686       break;
1687
1688     case AOP_CRY:
1689       /* if not bit variable */
1690       if (!aop->aopu.aop_dir)
1691         {
1692           /* inefficient: move carry into A and use jz/jnz */
1693           emitcode ("clr", "a");
1694           emitcode ("rlc", "a");
1695           accuse = TRUE;
1696         }
1697       else
1698         {
1699           if (s == zero)
1700             emitcode ("clr", "%s", aop->aopu.aop_dir);
1701           else if (s == one)
1702             emitcode ("setb", "%s", aop->aopu.aop_dir);
1703           else if (!strcmp (s, "c"))
1704             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1705           else if (strcmp (s, aop->aopu.aop_dir))
1706             {
1707               MOVA (s);
1708               /* set C, if a >= 1 */
1709               emitcode ("add", "a,#0xff");
1710               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1711             }
1712         }
1713       break;
1714
1715     case AOP_STR:
1716       aop->coff = offset;
1717       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1718         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1719       break;
1720
1721     case AOP_ACC:
1722       accuse = TRUE;
1723       aop->coff = offset;
1724       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1725         break;
1726
1727       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1728         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1729       break;
1730
1731     default:
1732       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1733               "aopPut got unsupported aop->type");
1734       exit (1);
1735     }
1736
1737     return accuse;
1738 }
1739
1740
1741 #if 0
1742 /*-----------------------------------------------------------------*/
1743 /* pointToEnd :- points to the last byte of the operand            */
1744 /*-----------------------------------------------------------------*/
1745 static void
1746 pointToEnd (asmop * aop)
1747 {
1748   int count;
1749   if (!aop)
1750     return;
1751
1752   aop->coff = count = (aop->size - 1);
1753   switch (aop->type)
1754     {
1755     case AOP_R0:
1756     case AOP_R1:
1757       while (count--)
1758         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1759       break;
1760     case AOP_DPTR:
1761       while (count--)
1762         emitcode ("inc", "dptr");
1763       break;
1764     }
1765
1766 }
1767 #endif
1768
1769 /*-----------------------------------------------------------------*/
1770 /* reAdjustPreg - points a register back to where it should        */
1771 /*-----------------------------------------------------------------*/
1772 static void
1773 reAdjustPreg (asmop * aop)
1774 {
1775   if ((aop->coff==0) || (aop->size <= 1))
1776     return;
1777
1778   switch (aop->type)
1779     {
1780     case AOP_R0:
1781     case AOP_R1:
1782       while (aop->coff--)
1783         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1784       break;
1785     case AOP_DPTR:
1786       while (aop->coff--)
1787         {
1788           emitcode ("lcall", "__decdptr");
1789         }
1790       break;
1791     }
1792   aop->coff = 0;
1793 }
1794
1795 /*-----------------------------------------------------------------*/
1796 /* opIsGptr: returns non-zero if the passed operand is       */
1797 /* a generic pointer type.             */
1798 /*-----------------------------------------------------------------*/
1799 static int
1800 opIsGptr (operand * op)
1801 {
1802   sym_link *type = operandType (op);
1803
1804   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1805     {
1806       return 1;
1807     }
1808   return 0;
1809 }
1810
1811 /*-----------------------------------------------------------------*/
1812 /* getDataSize - get the operand data size                         */
1813 /*-----------------------------------------------------------------*/
1814 static int
1815 getDataSize (operand * op)
1816 {
1817   int size;
1818   size = AOP_SIZE (op);
1819   if (size == GPTRSIZE)
1820     {
1821       sym_link *type = operandType (op);
1822       if (IS_GENPTR (type))
1823         {
1824           /* generic pointer; arithmetic operations
1825            * should ignore the high byte (pointer type).
1826            */
1827           size--;
1828         }
1829     }
1830   return size;
1831 }
1832
1833 /*-----------------------------------------------------------------*/
1834 /* outAcc - output Acc                                             */
1835 /*-----------------------------------------------------------------*/
1836 static void
1837 outAcc (operand * result)
1838 {
1839   int size, offset;
1840   size = getDataSize (result);
1841   if (size)
1842     {
1843       aopPut (result, "a", 0);
1844       size--;
1845       offset = 1;
1846       /* unsigned or positive */
1847       while (size--)
1848         {
1849           aopPut (result, zero, offset++);
1850         }
1851     }
1852 }
1853
1854 /*-----------------------------------------------------------------*/
1855 /* outBitC - output a bit C                                        */
1856 /*-----------------------------------------------------------------*/
1857 static void
1858 outBitC (operand * result)
1859 {
1860   /* if the result is bit */
1861   if (AOP_TYPE (result) == AOP_CRY)
1862     {
1863       aopPut (result, "c", 0);
1864     }
1865   else
1866     {
1867       emitcode ("clr", "a");
1868       emitcode ("rlc", "a");
1869       outAcc (result);
1870     }
1871 }
1872
1873 /*-----------------------------------------------------------------*/
1874 /* toBoolean - emit code for orl a,operator(sizeop)                */
1875 /*-----------------------------------------------------------------*/
1876 static void
1877 toBoolean (operand * oper)
1878 {
1879   int size = AOP_SIZE (oper) - 1;
1880   int offset = 1;
1881   bool AccUsed = FALSE;
1882   bool pushedB;
1883
1884   while (!AccUsed && size--)
1885     {
1886       AccUsed |= aopGetUsesAcc(oper, offset++);
1887     }
1888
1889   size = AOP_SIZE (oper) - 1;
1890   offset = 1;
1891   MOVA (aopGet (oper, 0, FALSE, FALSE));
1892   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1893     {
1894       pushedB = pushB ();
1895       emitcode("mov", "b,a");
1896       while (--size)
1897         {
1898           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1899           emitcode ("orl", "b,a");
1900         }
1901       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1902       emitcode ("orl", "a,b");
1903       popB (pushedB);
1904     }
1905   else
1906     {
1907       while (size--)
1908         {
1909           emitcode ("orl", "a,%s",
1910                     aopGet (oper, offset++, FALSE, FALSE));
1911         }
1912     }
1913 }
1914
1915
1916 /*-------------------------------------------------------------------*/
1917 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1918 /*-------------------------------------------------------------------*/
1919 static char *
1920 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1921 {
1922   char * l;
1923
1924   if (aopGetUsesAcc (oper, offset))
1925     {
1926       emitcode("mov", "b,a");
1927       MOVA (aopGet (oper, offset, bit16, dname));
1928       emitcode("xch", "a,b");
1929       aopPut (oper, "a", offset);
1930       emitcode("xch", "a,b");
1931       l = "b";
1932     }
1933   else
1934     {
1935       l = aopGet (oper, offset, bit16, dname);
1936       emitcode("xch", "a,%s", l);
1937     }
1938   return l;
1939 }
1940
1941
1942 /*-----------------------------------------------------------------*/
1943 /* genNot - generate code for ! operation                          */
1944 /*-----------------------------------------------------------------*/
1945 static void
1946 genNot (iCode * ic)
1947 {
1948   symbol *tlbl;
1949
1950   D (emitcode (";", "genNot"));
1951
1952   /* assign asmOps to operand & result */
1953   aopOp (IC_LEFT (ic), ic, FALSE);
1954   aopOp (IC_RESULT (ic), ic, TRUE);
1955
1956   /* if in bit space then a special case */
1957   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1958     {
1959       /* if left==result then cpl bit */
1960       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1961         {
1962           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1963         }
1964       else
1965         {
1966           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1967           emitcode ("cpl", "c");
1968           outBitC (IC_RESULT (ic));
1969         }
1970       goto release;
1971     }
1972
1973   toBoolean (IC_LEFT (ic));
1974
1975   /* set C, if a == 0 */
1976   tlbl = newiTempLabel (NULL);
1977   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
1978   emitLabel (tlbl);
1979   outBitC (IC_RESULT (ic));
1980
1981 release:
1982   /* release the aops */
1983   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1984   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1985 }
1986
1987
1988 /*-----------------------------------------------------------------*/
1989 /* genCpl - generate code for complement                           */
1990 /*-----------------------------------------------------------------*/
1991 static void
1992 genCpl (iCode * ic)
1993 {
1994   int offset = 0;
1995   int size;
1996   symbol *tlbl;
1997   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
1998
1999   D(emitcode (";", "genCpl"));
2000
2001   /* assign asmOps to operand & result */
2002   aopOp (IC_LEFT (ic), ic, FALSE);
2003   aopOp (IC_RESULT (ic), ic, TRUE);
2004
2005   /* special case if in bit space */
2006   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2007     {
2008       char *l;
2009
2010       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2011           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2012         {
2013           /* promotion rules are responsible for this strange result:
2014              bit -> int -> ~int -> bit
2015              uchar -> int -> ~int -> bit
2016           */
2017           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2018           goto release;
2019         }
2020
2021       tlbl=newiTempLabel(NULL);
2022       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2023       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2024           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2025           IS_AOP_PREG (IC_LEFT (ic)))
2026         {
2027           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2028         }
2029       else
2030         {
2031           MOVA (l);
2032           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2033         }
2034       emitLabel (tlbl);
2035       outBitC (IC_RESULT(ic));
2036       goto release;
2037     }
2038
2039   size = AOP_SIZE (IC_RESULT (ic));
2040   while (size--)
2041     {
2042       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2043       MOVA (l);
2044       emitcode ("cpl", "a");
2045       aopPut (IC_RESULT (ic), "a", offset++);
2046     }
2047
2048
2049 release:
2050   /* release the aops */
2051   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2052   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2053 }
2054
2055 /*-----------------------------------------------------------------*/
2056 /* genUminusFloat - unary minus for floating points                */
2057 /*-----------------------------------------------------------------*/
2058 static void
2059 genUminusFloat (operand * op, operand * result)
2060 {
2061   int size, offset = 0;
2062   char *l;
2063
2064   D (emitcode (";", "genUminusFloat"));
2065
2066   /* for this we just copy and then flip the bit */
2067
2068   size = AOP_SIZE (op) - 1;
2069
2070   while (size--)
2071     {
2072       aopPut (result,
2073               aopGet (op, offset, FALSE, FALSE),
2074               offset);
2075       offset++;
2076     }
2077
2078   l = aopGet (op, offset, FALSE, FALSE);
2079   MOVA (l);
2080
2081   emitcode ("cpl", "acc.7");
2082   aopPut (result, "a", offset);
2083 }
2084
2085 /*-----------------------------------------------------------------*/
2086 /* genUminus - unary minus code generation                         */
2087 /*-----------------------------------------------------------------*/
2088 static void
2089 genUminus (iCode * ic)
2090 {
2091   int offset, size;
2092   sym_link *optype;
2093
2094   D (emitcode (";", "genUminus"));
2095
2096   /* assign asmops */
2097   aopOp (IC_LEFT (ic), ic, FALSE);
2098   aopOp (IC_RESULT (ic), ic, TRUE);
2099
2100   /* if both in bit space then special
2101      case */
2102   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2103       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2104     {
2105
2106       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2107       emitcode ("cpl", "c");
2108       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2109       goto release;
2110     }
2111
2112   optype = operandType (IC_LEFT (ic));
2113
2114   /* if float then do float stuff */
2115   if (IS_FLOAT (optype))
2116     {
2117       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2118       goto release;
2119     }
2120
2121   /* otherwise subtract from zero */
2122   size = AOP_SIZE (IC_LEFT (ic));
2123   offset = 0;
2124   while (size--)
2125     {
2126       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2127       if (!strcmp (l, "a"))
2128         {
2129           if (offset == 0)
2130             SETC;
2131           emitcode ("cpl", "a");
2132           emitcode ("addc", "a,#0");
2133         }
2134       else
2135         {
2136           if (offset == 0)
2137             CLRC;
2138           emitcode ("clr", "a");
2139           emitcode ("subb", "a,%s", l);
2140         }
2141       aopPut (IC_RESULT (ic), "a", offset++);
2142     }
2143
2144   /* if any remaining bytes in the result */
2145   /* we just need to propagate the sign   */
2146   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2147     {
2148       emitcode ("rlc", "a");
2149       emitcode ("subb", "a,acc");
2150       while (size--)
2151         aopPut (IC_RESULT (ic), "a", offset++);
2152     }
2153
2154 release:
2155   /* release the aops */
2156   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2157   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2158 }
2159
2160 /*-----------------------------------------------------------------*/
2161 /* saveRegisters - will look for a call and save the registers     */
2162 /*-----------------------------------------------------------------*/
2163 static void
2164 saveRegisters (iCode * lic)
2165 {
2166   int i;
2167   iCode *ic;
2168   bitVect *rsave;
2169
2170   /* look for call */
2171   for (ic = lic; ic; ic = ic->next)
2172     if (ic->op == CALL || ic->op == PCALL)
2173       break;
2174
2175   if (!ic)
2176     {
2177       fprintf (stderr, "found parameter push with no function call\n");
2178       return;
2179     }
2180
2181   /* if the registers have been saved already or don't need to be then
2182      do nothing */
2183   if (ic->regsSaved)
2184     return;
2185   if (IS_SYMOP(IC_LEFT(ic)) &&
2186       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2187        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2188     return;
2189
2190   /* save the registers in use at this time but skip the
2191      ones for the result */
2192   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2193                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2194
2195   ic->regsSaved = 1;
2196   if (options.useXstack)
2197     {
2198       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2199       int nBits = bitVectnBitsOn (rsavebits);
2200       int count = bitVectnBitsOn (rsave);
2201
2202       if (nBits != 0)
2203         {
2204           count = count - nBits + 1;
2205           /* remove all but the first bits as they are pushed all at once */
2206           rsave = bitVectCplAnd (rsave, rsavebits);
2207           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2208         }
2209
2210       if (count == 1)
2211         {
2212           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2213           if (reg->type == REG_BIT)
2214             {
2215               emitcode ("mov", "a,%s", reg->base);
2216             }
2217           else
2218             {
2219               emitcode ("mov", "a,%s", reg->name);
2220             }
2221           emitcode ("mov", "r0,%s", spname);
2222           emitcode ("inc", "%s", spname);// allocate before use
2223           emitcode ("movx", "@r0,a");
2224           if (bitVectBitValue (rsave, R0_IDX))
2225             emitcode ("mov", "r0,a");
2226         }
2227       else if (count != 0)
2228         {
2229           if (bitVectBitValue (rsave, R0_IDX))
2230             {
2231               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2232             }
2233           emitcode ("mov", "r0,%s", spname);
2234           MOVA ("r0");
2235           emitcode ("add", "a,#%d", count);
2236           emitcode ("mov", "%s,a", spname);
2237           for (i = 0; i < mcs51_nRegs; i++)
2238             {
2239               if (bitVectBitValue (rsave, i))
2240                 {
2241                   regs * reg = REG_WITH_INDEX (i);
2242                   if (i == R0_IDX)
2243                     {
2244                       emitcode ("pop", "acc");
2245                       emitcode ("push", "acc");
2246                     }
2247                   else if (reg->type == REG_BIT)
2248                     {
2249                       emitcode ("mov", "a,%s", reg->base);
2250                     }
2251                   else
2252                     {
2253                       emitcode ("mov", "a,%s", reg->name);
2254                     }
2255                   emitcode ("movx", "@r0,a");
2256                   if (--count)
2257                     {
2258                       emitcode ("inc", "r0");
2259                     }
2260                 }
2261             }
2262           if (bitVectBitValue (rsave, R0_IDX))
2263             {
2264               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2265             }
2266         }
2267     }
2268   else
2269     {
2270       bool bits_pushed = FALSE;
2271       for (i = 0; i < mcs51_nRegs; i++)
2272         {
2273           if (bitVectBitValue (rsave, i))
2274             {
2275               bits_pushed = pushReg (i, bits_pushed);
2276             }
2277         }
2278     }
2279 }
2280
2281 /*-----------------------------------------------------------------*/
2282 /* unsaveRegisters - pop the pushed registers                      */
2283 /*-----------------------------------------------------------------*/
2284 static void
2285 unsaveRegisters (iCode * ic)
2286 {
2287   int i;
2288   bitVect *rsave;
2289
2290   /* restore the registers in use at this time but skip the
2291      ones for the result */
2292   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2293                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2294
2295   if (options.useXstack)
2296     {
2297       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2298       int nBits = bitVectnBitsOn (rsavebits);
2299       int count = bitVectnBitsOn (rsave);
2300
2301       if (nBits != 0)
2302         {
2303           count = count - nBits + 1;
2304           /* remove all but the first bits as they are popped all at once */
2305           rsave = bitVectCplAnd (rsave, rsavebits);
2306           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2307         }
2308
2309       if (count == 1)
2310         {
2311           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2312           emitcode ("mov", "r0,%s", spname);
2313           emitcode ("dec", "r0");
2314           emitcode ("movx", "a,@r0");
2315           if (reg->type == REG_BIT)
2316             {
2317               emitcode ("mov", "%s,a", reg->base);
2318             }
2319           else
2320             {
2321               emitcode ("mov", "%s,a", reg->name);
2322             }
2323           emitcode ("dec", "%s", spname);
2324         }
2325       else if (count != 0)
2326         {
2327           emitcode ("mov", "r0,%s", spname);
2328           for (i = mcs51_nRegs; i >= 0; i--)
2329             {
2330               if (bitVectBitValue (rsave, i))
2331                 {
2332                   regs * reg = REG_WITH_INDEX (i);
2333                   emitcode ("dec", "r0");
2334                   emitcode ("movx", "a,@r0");
2335                   if (i == R0_IDX)
2336                     {
2337                       emitcode ("push", "acc");
2338                     }
2339                   else if (reg->type == REG_BIT)
2340                     {
2341                       emitcode ("mov", "%s,a", reg->base);
2342                     }
2343                   else
2344                     {
2345                       emitcode ("mov", "%s,a", reg->name);
2346                     }
2347                 }
2348             }
2349           emitcode ("mov", "%s,r0", spname);
2350           if (bitVectBitValue (rsave, R0_IDX))
2351             {
2352               emitcode ("pop", "ar0");
2353             }
2354         }
2355     }
2356   else
2357     {
2358       bool bits_popped = FALSE;
2359       for (i = mcs51_nRegs; i >= 0; i--)
2360         {
2361           if (bitVectBitValue (rsave, i))
2362             {
2363               bits_popped = popReg (i, bits_popped);
2364             }
2365         }
2366     }
2367 }
2368
2369
2370 /*-----------------------------------------------------------------*/
2371 /* pushSide -                                                      */
2372 /*-----------------------------------------------------------------*/
2373 static void
2374 pushSide (operand * oper, int size)
2375 {
2376   int offset = 0;
2377   while (size--)
2378     {
2379       char *l = aopGet (oper, offset++, FALSE, TRUE);
2380       if (AOP_TYPE (oper) != AOP_REG &&
2381           AOP_TYPE (oper) != AOP_DIR &&
2382           strcmp (l, "a"))
2383         {
2384           MOVA (l);
2385           emitcode ("push", "acc");
2386         }
2387       else
2388         {
2389           emitcode ("push", "%s", l);
2390         }
2391     }
2392 }
2393
2394 /*-----------------------------------------------------------------*/
2395 /* assignResultValue - also indicates if acc is in use afterwards  */
2396 /*-----------------------------------------------------------------*/
2397 static bool
2398 assignResultValue (operand * oper, operand * func)
2399 {
2400   int offset = 0;
2401   int size = AOP_SIZE (oper);
2402   bool accuse = FALSE;
2403   bool pushedA = FALSE;
2404
2405   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2406     {
2407       outBitC (oper);
2408       return FALSE;
2409     }
2410
2411   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2412     {
2413       emitcode ("push", "acc");
2414       pushedA = TRUE;
2415     }
2416   while (size--)
2417     {
2418       if ((offset == 3) && pushedA)
2419         emitcode ("pop", "acc");
2420       accuse |= aopPut (oper, fReturn[offset], offset);
2421       offset++;
2422     }
2423   return accuse;
2424 }
2425
2426
2427 /*-----------------------------------------------------------------*/
2428 /* genXpush - pushes onto the external stack                       */
2429 /*-----------------------------------------------------------------*/
2430 static void
2431 genXpush (iCode * ic)
2432 {
2433   asmop *aop = newAsmop (0);
2434   regs *r;
2435   int size, offset = 0;
2436
2437   D (emitcode (";", "genXpush"));
2438
2439   aopOp (IC_LEFT (ic), ic, FALSE);
2440   r = getFreePtr (ic, &aop, FALSE);
2441
2442   size = AOP_SIZE (IC_LEFT (ic));
2443
2444   if (size == 1)
2445     {
2446       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2447       emitcode ("mov", "%s,%s", r->name, spname);
2448       emitcode ("inc", "%s", spname); // allocate space first
2449       emitcode ("movx", "@%s,a", r->name);
2450     }
2451   else
2452     {
2453       // allocate space first
2454       emitcode ("mov", "%s,%s", r->name, spname);
2455       MOVA (r->name);
2456       emitcode ("add", "a,#%d", size);
2457       emitcode ("mov", "%s,a", spname);
2458
2459       while (size--)
2460         {
2461           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2462           emitcode ("movx", "@%s,a", r->name);
2463           emitcode ("inc", "%s", r->name);
2464         }
2465     }
2466
2467   freeAsmop (NULL, aop, ic, TRUE);
2468   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2469 }
2470
2471 /*-----------------------------------------------------------------*/
2472 /* genIpush - generate code for pushing this gets a little complex */
2473 /*-----------------------------------------------------------------*/
2474 static void
2475 genIpush (iCode * ic)
2476 {
2477   int size, offset = 0;
2478   char *l;
2479   char *prev = "";
2480
2481   D (emitcode (";", "genIpush"));
2482
2483   /* if this is not a parm push : ie. it is spill push
2484      and spill push is always done on the local stack */
2485   if (!ic->parmPush)
2486     {
2487
2488       /* and the item is spilt then do nothing */
2489       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2490         return;
2491
2492       aopOp (IC_LEFT (ic), ic, FALSE);
2493       size = AOP_SIZE (IC_LEFT (ic));
2494       /* push it on the stack */
2495       while (size--)
2496         {
2497           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2498           if (*l == '#')
2499             {
2500               MOVA (l);
2501               l = "acc";
2502             }
2503           emitcode ("push", "%s", l);
2504         }
2505       return;
2506     }
2507
2508   /* this is a parameter push: in this case we call
2509      the routine to find the call and save those
2510      registers that need to be saved */
2511   saveRegisters (ic);
2512
2513   /* if use external stack then call the external
2514      stack pushing routine */
2515   if (options.useXstack)
2516     {
2517       genXpush (ic);
2518       return;
2519     }
2520
2521   /* then do the push */
2522   aopOp (IC_LEFT (ic), ic, FALSE);
2523
2524   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2525   size = AOP_SIZE (IC_LEFT (ic));
2526
2527   while (size--)
2528     {
2529       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2530       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2531           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2532         {
2533           if (strcmp (l, prev) || *l == '@')
2534             MOVA (l);
2535           emitcode ("push", "acc");
2536         }
2537       else
2538         {
2539           emitcode ("push", "%s", l);
2540         }
2541       prev = l;
2542     }
2543
2544   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2545 }
2546
2547 /*-----------------------------------------------------------------*/
2548 /* genIpop - recover the registers: can happen only for spilling   */
2549 /*-----------------------------------------------------------------*/
2550 static void
2551 genIpop (iCode * ic)
2552 {
2553   int size, offset;
2554
2555   D (emitcode (";", "genIpop"));
2556
2557   /* if the temp was not pushed then */
2558   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2559     return;
2560
2561   aopOp (IC_LEFT (ic), ic, FALSE);
2562   size = AOP_SIZE (IC_LEFT (ic));
2563   offset = (size - 1);
2564   while (size--)
2565     {
2566       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2567                                      FALSE, TRUE));
2568     }
2569
2570   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2571 }
2572
2573 /*-----------------------------------------------------------------*/
2574 /* saveRBank - saves an entire register bank on the stack          */
2575 /*-----------------------------------------------------------------*/
2576 static void
2577 saveRBank (int bank, iCode * ic, bool pushPsw)
2578 {
2579   int i;
2580   int count = 8 + ((mcs51_nRegs > 8) ? 1 : 0) + (pushPsw ? 1 : 0);
2581   asmop *aop = NULL;
2582   regs *r = NULL;
2583
2584   if (options.useXstack)
2585     {
2586       if (!ic)
2587         {
2588           /* Assume r0 is available for use. */
2589           r = REG_WITH_INDEX (R0_IDX);;
2590         }
2591       else
2592         {
2593           aop = newAsmop (0);
2594           r = getFreePtr (ic, &aop, FALSE);
2595         }
2596       // allocate space first
2597       emitcode ("mov", "%s,%s", r->name, spname);
2598       MOVA (r->name);
2599       emitcode ("add", "a,#%d", count);
2600       emitcode ("mov", "%s,a", spname);
2601     }
2602
2603   for (i = 0; i < 8; i++)
2604     {
2605       if (options.useXstack)
2606         {
2607           emitcode ("mov", "a,(%s+%d)",
2608                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2609           emitcode ("movx", "@%s,a", r->name);
2610           if (--count)
2611             emitcode ("inc", "%s", r->name);
2612         }
2613       else
2614         emitcode ("push", "(%s+%d)",
2615                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2616     }
2617
2618   if (mcs51_nRegs > 8)
2619     {
2620       if (options.useXstack)
2621         {
2622           emitcode ("mov", "a,bits");
2623           emitcode ("movx", "@%s,a", r->name);
2624           if (--count)
2625             emitcode ("inc", "%s", r->name);
2626         }
2627       else
2628         {
2629           emitcode ("push", "bits");
2630         }
2631       BitBankUsed = 1;
2632     }
2633
2634   if (pushPsw)
2635     {
2636       if (options.useXstack)
2637         {
2638           emitcode ("mov", "a,psw");
2639           emitcode ("movx", "@%s,a", r->name);
2640         }
2641       else
2642         {
2643           emitcode ("push", "psw");
2644         }
2645
2646       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2647     }
2648
2649   if (aop)
2650     {
2651       freeAsmop (NULL, aop, ic, TRUE);
2652     }
2653
2654   if (ic)
2655   {
2656     ic->bankSaved = 1;
2657   }
2658 }
2659
2660 /*-----------------------------------------------------------------*/
2661 /* unsaveRBank - restores the register bank from stack             */
2662 /*-----------------------------------------------------------------*/
2663 static void
2664 unsaveRBank (int bank, iCode * ic, bool popPsw)
2665 {
2666   int i;
2667   asmop *aop = NULL;
2668   regs *r = NULL;
2669
2670   if (options.useXstack)
2671     {
2672       if (!ic)
2673         {
2674           /* Assume r0 is available for use. */
2675           r = REG_WITH_INDEX (R0_IDX);;
2676         }
2677       else
2678         {
2679           aop = newAsmop (0);
2680           r = getFreePtr (ic, &aop, FALSE);
2681         }
2682       emitcode ("mov", "%s,%s", r->name, spname);
2683     }
2684
2685   if (popPsw)
2686     {
2687       if (options.useXstack)
2688         {
2689           emitcode ("dec", "%s", r->name);
2690           emitcode ("movx", "a,@%s", r->name);
2691           emitcode ("mov", "psw,a");
2692         }
2693       else
2694         {
2695           emitcode ("pop", "psw");
2696         }
2697     }
2698
2699   if (mcs51_nRegs > 8)
2700     {
2701       if (options.useXstack)
2702         {
2703           emitcode ("dec", "%s", r->name);
2704           emitcode ("movx", "a,@%s", r->name);
2705           emitcode ("mov", "bits,a");
2706         }
2707       else
2708         {
2709           emitcode ("pop", "bits");
2710         }
2711     }
2712
2713   for (i = 7; i >= 0; i--)
2714     {
2715       if (options.useXstack)
2716         {
2717           emitcode ("dec", "%s", r->name);
2718           emitcode ("movx", "a,@%s", r->name);
2719           emitcode ("mov", "(%s+%d),a",
2720                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2721         }
2722       else
2723         {
2724           emitcode ("pop", "(%s+%d)",
2725                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2726         }
2727     }
2728
2729   if (options.useXstack)
2730     {
2731       emitcode ("mov", "%s,%s", spname, r->name);
2732     }
2733
2734   if (aop)
2735     {
2736       freeAsmop (NULL, aop, ic, TRUE);
2737     }
2738 }
2739
2740 /*-----------------------------------------------------------------*/
2741 /* genSend - gen code for SEND                                     */
2742 /*-----------------------------------------------------------------*/
2743 static void genSend(set *sendSet)
2744 {
2745   iCode *sic;
2746   int bit_count = 0;
2747
2748   /* first we do all bit parameters */
2749   for (sic = setFirstItem (sendSet); sic;
2750        sic = setNextItem (sendSet))
2751     {
2752       if (sic->argreg > 12)
2753         {
2754           int bit = sic->argreg-13;
2755
2756           aopOp (IC_LEFT (sic), sic, FALSE);
2757
2758           /* if left is a literal then
2759              we know what the value is */
2760           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2761             {
2762               if (((int) operandLitValue (IC_LEFT (sic))))
2763                   emitcode ("setb", "b[%d]", bit);
2764               else
2765                   emitcode ("clr", "b[%d]", bit);
2766             }
2767           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2768             {
2769               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2770                 if (strcmp (l, "c"))
2771                     emitcode ("mov", "c,%s", l);
2772                 emitcode ("mov", "b[%d],c", bit);
2773             }
2774           else
2775             {
2776               /* we need to or */
2777               toBoolean (IC_LEFT (sic));
2778               /* set C, if a >= 1 */
2779               emitcode ("add", "a,#0xff");
2780               emitcode ("mov", "b[%d],c", bit);
2781             }
2782           bit_count++;
2783           BitBankUsed = 1;
2784
2785           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2786         }
2787     }
2788
2789   if (bit_count)
2790     {
2791       saveRegisters (setFirstItem (sendSet));
2792       emitcode ("mov", "bits,b");
2793     }
2794
2795   /* then we do all other parameters */
2796   for (sic = setFirstItem (sendSet); sic;
2797        sic = setNextItem (sendSet))
2798     {
2799       if (sic->argreg <= 12)
2800         {
2801           int size, offset = 0;
2802           aopOp (IC_LEFT (sic), sic, FALSE);
2803           size = AOP_SIZE (IC_LEFT (sic));
2804
2805           if (sic->argreg == 1)
2806             {
2807               while (size--)
2808                 {
2809                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2810                   if (strcmp (l, fReturn[offset]))
2811                     {
2812                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2813                     }
2814                   offset++;
2815                 }
2816             }
2817           else
2818             {
2819               while (size--)
2820                 {
2821                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2822                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2823                   offset++;
2824                 }
2825             }
2826           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2827         }
2828     }
2829 }
2830
2831 /*-----------------------------------------------------------------*/
2832 /* selectRegBank - emit code to select the register bank           */
2833 /*-----------------------------------------------------------------*/
2834 static void
2835 selectRegBank (short bank, bool keepFlags)
2836 {
2837   /* if f.e. result is in carry */
2838   if (keepFlags)
2839     {
2840       emitcode ("anl", "psw,#0xE7");
2841       if (bank)
2842         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2843     }
2844   else
2845     {
2846       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2847     }
2848 }
2849
2850 /*-----------------------------------------------------------------*/
2851 /* genCall - generates a call statement                            */
2852 /*-----------------------------------------------------------------*/
2853 static void
2854 genCall (iCode * ic)
2855 {
2856   sym_link *dtype;
2857   sym_link *etype;
2858 //  bool restoreBank = FALSE;
2859   bool swapBanks = FALSE;
2860   bool accuse = FALSE;
2861   bool accPushed = FALSE;
2862   bool resultInF0 = FALSE;
2863   bool assignResultGenerated = FALSE;
2864
2865   D (emitcode (";", "genCall"));
2866
2867   dtype = operandType (IC_LEFT (ic));
2868   etype = getSpec(dtype);
2869   /* if send set is not empty then assign */
2870   if (_G.sendSet)
2871     {
2872         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2873             genSend(reverseSet(_G.sendSet));
2874         } else {
2875             genSend(_G.sendSet);
2876         }
2877       _G.sendSet = NULL;
2878     }
2879
2880   /* if we are calling a not _naked function that is not using
2881      the same register bank then we need to save the
2882      destination registers on the stack */
2883   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2884       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2885        !IFFUNC_ISISR (dtype))
2886     {
2887       swapBanks = TRUE;
2888     }
2889
2890   /* if caller saves & we have not saved then */
2891   if (!ic->regsSaved)
2892       saveRegisters (ic);
2893
2894   if (swapBanks)
2895     {
2896         emitcode ("mov", "psw,#0x%02x",
2897            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2898     }
2899
2900   /* make the call */
2901   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2902     {
2903       if (IFFUNC_CALLEESAVES(dtype))
2904         {
2905           werror (E_BANKED_WITH_CALLEESAVES);
2906         }
2907       else
2908         {
2909           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2910                      OP_SYMBOL (IC_LEFT (ic))->rname :
2911                      OP_SYMBOL (IC_LEFT (ic))->name);
2912
2913           emitcode ("mov", "r0,#%s", l);
2914           emitcode ("mov", "r1,#(%s >> 8)", l);
2915           emitcode ("mov", "r2,#(%s >> 16)", l);
2916           emitcode ("lcall", "__sdcc_banked_call");
2917         }
2918     }
2919   else
2920     {
2921       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2922                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2923                                 OP_SYMBOL (IC_LEFT (ic))->name));
2924     }
2925
2926   if (swapBanks)
2927     {
2928       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2929     }
2930
2931   /* if we need assign a result value */
2932   if ((IS_ITEMP (IC_RESULT (ic)) &&
2933        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2934        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2935         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2936         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2937       IS_TRUE_SYMOP (IC_RESULT (ic)))
2938     {
2939
2940       _G.accInUse++;
2941       aopOp (IC_RESULT (ic), ic, FALSE);
2942       _G.accInUse--;
2943
2944       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2945       assignResultGenerated = TRUE;
2946
2947       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2948     }
2949
2950   /* adjust the stack for parameters if required */
2951   if (ic->parmBytes)
2952     {
2953       int i;
2954       if (ic->parmBytes > 3)
2955         {
2956           if (accuse)
2957             {
2958               emitcode ("push", "acc");
2959               accPushed = TRUE;
2960             }
2961           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2962               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2963               !assignResultGenerated)
2964             {
2965               emitcode ("mov", "F0,c");
2966               resultInF0 = TRUE;
2967             }
2968
2969           emitcode ("mov", "a,%s", spname);
2970           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2971           emitcode ("mov", "%s,a", spname);
2972
2973           /* unsaveRegisters from xstack needs acc, but */
2974           /* unsaveRegisters from stack needs this popped */
2975           if (accPushed && !options.useXstack)
2976             {
2977               emitcode ("pop", "acc");
2978               accPushed = FALSE;
2979             }
2980         }
2981       else
2982         for (i = 0; i < ic->parmBytes; i++)
2983           emitcode ("dec", "%s", spname);
2984     }
2985
2986   /* if we had saved some registers then unsave them */
2987   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2988     {
2989       if (accuse && !accPushed && options.useXstack)
2990         {
2991           /* xstack needs acc, but doesn't touch normal stack */
2992           emitcode ("push", "acc");
2993           accPushed = TRUE;
2994         }
2995       unsaveRegisters (ic);
2996     }
2997
2998 //  /* if register bank was saved then pop them */
2999 //  if (restoreBank)
3000 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3001
3002   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3003     {
3004       if (resultInF0)
3005           emitcode ("mov", "c,F0");
3006
3007       aopOp (IC_RESULT (ic), ic, FALSE);
3008       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3009       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3010     }
3011
3012   if (accPushed)
3013     emitcode ("pop", "acc");
3014 }
3015
3016 /*-----------------------------------------------------------------*/
3017 /* genPcall - generates a call by pointer statement                */
3018 /*-----------------------------------------------------------------*/
3019 static void
3020 genPcall (iCode * ic)
3021 {
3022   sym_link *dtype;
3023   sym_link *etype;
3024   symbol *rlbl = newiTempLabel (NULL);
3025 //  bool restoreBank=FALSE;
3026   bool swapBanks = FALSE;
3027   bool resultInF0 = FALSE;
3028
3029   D (emitcode (";", "genPcall"));
3030
3031   dtype = operandType (IC_LEFT (ic))->next;
3032   etype = getSpec(dtype);
3033   /* if caller saves & we have not saved then */
3034   if (!ic->regsSaved)
3035     saveRegisters (ic);
3036
3037   /* if we are calling a not _naked function that is not using
3038      the same register bank then we need to save the
3039      destination registers on the stack */
3040   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
3041       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3042       !IFFUNC_ISISR (dtype))
3043     {
3044 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3045 //    restoreBank=TRUE;
3046       swapBanks = TRUE;
3047       // need caution message to user here
3048     }
3049
3050   if (IS_LITERAL(etype))
3051     {
3052       /* if send set is not empty then assign */
3053       if (_G.sendSet)
3054         {
3055           genSend(reverseSet(_G.sendSet));
3056           _G.sendSet = NULL;
3057         }
3058
3059       if (swapBanks)
3060         {
3061           emitcode ("mov", "psw,#0x%02x",
3062            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3063         }
3064
3065       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
3066         {
3067           if (IFFUNC_CALLEESAVES(dtype))
3068             {
3069               werror (E_BANKED_WITH_CALLEESAVES);
3070             }
3071           else
3072             {
3073               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3074
3075               emitcode ("mov", "r0,#%s", l);
3076               emitcode ("mov", "r1,#(%s >> 8)", l);
3077               emitcode ("mov", "r2,#(%s >> 16)", l);
3078               emitcode ("lcall", "__sdcc_banked_call");
3079             }
3080         }
3081       else
3082         {
3083           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3084         }
3085     }
3086   else
3087     {
3088       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
3089         {
3090           if (IFFUNC_CALLEESAVES(dtype))
3091             {
3092               werror (E_BANKED_WITH_CALLEESAVES);
3093             }
3094           else
3095             {
3096               aopOp (IC_LEFT (ic), ic, FALSE);
3097
3098               if (!swapBanks)
3099                 {
3100                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3101                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3102                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3103                 }
3104               else
3105                 {
3106                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3107                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3108                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3109                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3110                 }
3111
3112               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3113
3114               /* if send set is not empty then assign */
3115               if (_G.sendSet)
3116                 {
3117                   genSend(reverseSet(_G.sendSet));
3118                   _G.sendSet = NULL;
3119                 }
3120
3121               if (swapBanks)
3122                 {
3123                   emitcode ("mov", "psw,#0x%02x",
3124                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3125                 }
3126
3127               /* make the call */
3128               emitcode ("lcall", "__sdcc_banked_call");
3129             }
3130         }
3131       else
3132         {
3133           /* push the return address on to the stack */
3134           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3135           emitcode ("push", "acc");
3136           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3137           emitcode ("push", "acc");
3138
3139           /* now push the calling address */
3140           aopOp (IC_LEFT (ic), ic, FALSE);
3141
3142           pushSide (IC_LEFT (ic), FPTRSIZE);
3143
3144           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3145
3146           /* if send set is not empty the assign */
3147           if (_G.sendSet)
3148             {
3149               genSend(reverseSet(_G.sendSet));
3150               _G.sendSet = NULL;
3151             }
3152
3153           if (swapBanks)
3154             {
3155               emitcode ("mov", "psw,#0x%02x",
3156                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3157             }
3158
3159           /* make the call */
3160           emitcode ("ret", "");
3161           emitLabel (rlbl);
3162         }
3163     }
3164   if (swapBanks)
3165     {
3166       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3167     }
3168
3169   /* if we need assign a result value */
3170   if ((IS_ITEMP (IC_RESULT (ic)) &&
3171        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3172        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3173         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3174       IS_TRUE_SYMOP (IC_RESULT (ic)))
3175     {
3176
3177       _G.accInUse++;
3178       aopOp (IC_RESULT (ic), ic, FALSE);
3179       _G.accInUse--;
3180
3181       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3182
3183       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3184     }
3185
3186   /* adjust the stack for parameters if required */
3187   if (ic->parmBytes)
3188     {
3189       int i;
3190       if (ic->parmBytes > 3)
3191         {
3192           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3193               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3194             {
3195               emitcode ("mov", "F0,c");
3196               resultInF0 = TRUE;
3197             }
3198
3199           emitcode ("mov", "a,%s", spname);
3200           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3201           emitcode ("mov", "%s,a", spname);
3202         }
3203       else
3204         for (i = 0; i < ic->parmBytes; i++)
3205           emitcode ("dec", "%s", spname);
3206     }
3207
3208 //  /* if register bank was saved then unsave them */
3209 //  if (restoreBank)
3210 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3211
3212   /* if we had saved some registers then unsave them */
3213   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3214     unsaveRegisters (ic);
3215
3216   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3217     {
3218       if (resultInF0)
3219           emitcode ("mov", "c,F0");
3220
3221       aopOp (IC_RESULT (ic), ic, FALSE);
3222       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3223       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3224     }
3225 }
3226
3227 /*-----------------------------------------------------------------*/
3228 /* resultRemat - result  is rematerializable                       */
3229 /*-----------------------------------------------------------------*/
3230 static int
3231 resultRemat (iCode * ic)
3232 {
3233   if (SKIP_IC (ic) || ic->op == IFX)
3234     return 0;
3235
3236   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3237     {
3238       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3239       if (sym->remat && !POINTER_SET (ic))
3240         return 1;
3241     }
3242
3243   return 0;
3244 }
3245
3246 /*-----------------------------------------------------------------*/
3247 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3248 /*-----------------------------------------------------------------*/
3249 static int
3250 regsCmp(void *p1, void *p2)
3251 {
3252   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3253 }
3254
3255 static bool
3256 inExcludeList (char *s)
3257 {
3258   const char *p = setFirstItem(options.excludeRegsSet);
3259
3260   if (p == NULL || STRCASECMP(p, "none") == 0)
3261     return FALSE;
3262
3263
3264   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3265 }
3266
3267 /*-----------------------------------------------------------------*/
3268 /* genFunction - generated code for function entry                 */
3269 /*-----------------------------------------------------------------*/
3270 static void
3271 genFunction (iCode * ic)
3272 {
3273   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3274   sym_link *ftype;
3275   bool     switchedPSW = FALSE;
3276   int      calleesaves_saved_register = -1;
3277   int      stackAdjust = sym->stack;
3278   int      accIsFree = sym->recvSize < 4;
3279   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3280   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3281
3282   _G.nRegsSaved = 0;
3283   /* create the function header */
3284   emitcode (";", "-----------------------------------------");
3285   emitcode (";", " function %s", sym->name);
3286   emitcode (";", "-----------------------------------------");
3287
3288   emitcode ("", "%s:", sym->rname);
3289   lineCurr->isLabel = 1;
3290   ftype = operandType (IC_LEFT (ic));
3291   _G.currentFunc = sym;
3292
3293   if (IFFUNC_ISNAKED(ftype))
3294   {
3295       emitcode(";", "naked function: no prologue.");
3296       return;
3297   }
3298
3299   /* here we need to generate the equates for the
3300      register bank if required */
3301   if (FUNC_REGBANK (ftype) != rbank)
3302     {
3303       int i;
3304
3305       rbank = FUNC_REGBANK (ftype);
3306       for (i = 0; i < mcs51_nRegs; i++)
3307         {
3308           if (regs8051[i].type != REG_BIT)
3309             {
3310               if (strcmp (regs8051[i].base, "0") == 0)
3311                 emitcode ("", "%s = 0x%02x",
3312                           regs8051[i].dname,
3313                           8 * rbank + regs8051[i].offset);
3314               else
3315                 emitcode ("", "%s = %s + 0x%02x",
3316                           regs8051[i].dname,
3317                           regs8051[i].base,
3318                           8 * rbank + regs8051[i].offset);
3319             }
3320         }
3321     }
3322
3323   /* if this is an interrupt service routine then
3324      save acc, b, dpl, dph  */
3325   if (IFFUNC_ISISR (sym->type))
3326     {
3327       if (!inExcludeList ("acc"))
3328         emitcode ("push", "acc");
3329       if (!inExcludeList ("b"))
3330         emitcode ("push", "b");
3331       if (!inExcludeList ("dpl"))
3332         emitcode ("push", "dpl");
3333       if (!inExcludeList ("dph"))
3334         emitcode ("push", "dph");
3335       /* if this isr has no bank i.e. is going to
3336          run with bank 0 , then we need to save more
3337          registers :-) */
3338       if (!FUNC_REGBANK (sym->type))
3339         {
3340           int i;
3341
3342           /* if this function does not call any other
3343              function then we can be economical and
3344              save only those registers that are used */
3345           if (!IFFUNC_HASFCALL(sym->type))
3346             {
3347               /* if any registers used */
3348               if (sym->regsUsed)
3349                 {
3350                   bool bits_pushed = FALSE;
3351                   /* save the registers used */
3352                   for (i = 0; i < sym->regsUsed->size; i++)
3353                     {
3354                       if (bitVectBitValue (sym->regsUsed, i))
3355                         bits_pushed = pushReg (i, bits_pushed);
3356                     }
3357                 }
3358             }
3359           else
3360             {
3361               /* this function has a function call. We cannot
3362                  determine register usage so we will have to push the
3363                  entire bank */
3364                 saveRBank (0, ic, FALSE);
3365                 if (options.parms_in_bank1) {
3366                     for (i=0; i < 8 ; i++ ) {
3367                         emitcode ("push","%s",rb1regs[i]);
3368                     }
3369                 }
3370             }
3371         }
3372         else
3373         {
3374             /* This ISR uses a non-zero bank.
3375              *
3376              * We assume that the bank is available for our
3377              * exclusive use.
3378              *
3379              * However, if this ISR calls a function which uses some
3380              * other bank, we must save that bank entirely.
3381              */
3382             unsigned long banksToSave = 0;
3383
3384             if (IFFUNC_HASFCALL(sym->type))
3385             {
3386
3387 #define MAX_REGISTER_BANKS 4
3388
3389                 iCode *i;
3390                 int ix;
3391
3392                 for (i = ic; i; i = i->next)
3393                 {
3394                     if (i->op == ENDFUNCTION)
3395                     {
3396                         /* we got to the end OK. */
3397                         break;
3398                     }
3399
3400                     if (i->op == CALL)
3401                     {
3402                         sym_link *dtype;
3403
3404                         dtype = operandType (IC_LEFT(i));
3405                         if (dtype
3406                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3407                         {
3408                              /* Mark this bank for saving. */
3409                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3410                              {
3411                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3412                              }
3413                              else
3414                              {
3415                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3416                              }
3417
3418                              /* And note that we don't need to do it in
3419                               * genCall.
3420                               */
3421                              i->bankSaved = 1;
3422                         }
3423                     }
3424                     if (i->op == PCALL)
3425                     {
3426                         /* This is a mess; we have no idea what
3427                          * register bank the called function might
3428                          * use.
3429                          *
3430                          * The only thing I can think of to do is
3431                          * throw a warning and hope.
3432                          */
3433                         werror(W_FUNCPTR_IN_USING_ISR);
3434                     }
3435                 }
3436
3437                 if (banksToSave && options.useXstack)
3438                 {
3439                     /* Since we aren't passing it an ic,
3440                      * saveRBank will assume r0 is available to abuse.
3441                      *
3442                      * So switch to our (trashable) bank now, so
3443                      * the caller's R0 isn't trashed.
3444                      */
3445                     emitcode ("push", "psw");
3446                     emitcode ("mov", "psw,#0x%02x",
3447                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3448                     switchedPSW = TRUE;
3449                 }
3450
3451                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3452                 {
3453                      if (banksToSave & (1 << ix))
3454                      {
3455                          saveRBank(ix, NULL, FALSE);
3456                      }
3457                 }
3458             }
3459             // TODO: this needs a closer look
3460             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3461         }
3462
3463       /* Set the register bank to the desired value if nothing else */
3464       /* has done so yet. */
3465       if (!switchedPSW)
3466         {
3467           emitcode ("push", "psw");
3468           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3469         }
3470     }
3471   else
3472     {
3473       /* This is a non-ISR function. The caller has already switched register */
3474       /* banks, if necessary, so just handle the callee-saves option. */
3475
3476       /* if callee-save to be used for this function
3477          then save the registers being used in this function */
3478       if (IFFUNC_CALLEESAVES(sym->type))
3479         {
3480           int i;
3481
3482           /* if any registers used */
3483           if (sym->regsUsed)
3484             {
3485               bool bits_pushed = FALSE;
3486               /* save the registers used */
3487               for (i = 0; i < sym->regsUsed->size; i++)
3488                 {
3489                   if (bitVectBitValue (sym->regsUsed, i))
3490                     {
3491                       /* remember one saved register for later usage */
3492                       if (calleesaves_saved_register < 0)
3493                         calleesaves_saved_register = i;
3494                       bits_pushed = pushReg (i, bits_pushed);
3495                       _G.nRegsSaved++;
3496                     }
3497                 }
3498             }
3499         }
3500     }
3501
3502   if (fReentrant)
3503     {
3504       if (options.useXstack)
3505         {
3506           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3507             {
3508               emitcode ("mov", "r0,%s", spname);
3509               emitcode ("inc", "%s", spname);
3510               emitcode ("xch", "a,_bpx");
3511               emitcode ("movx", "@r0,a");
3512               emitcode ("inc", "r0");
3513               emitcode ("mov", "a,r0");
3514               emitcode ("xch", "a,_bpx");
3515             }
3516           if (sym->stack)
3517             {
3518               emitcode ("push", "_bp");     /* save the callers stack  */
3519               emitcode ("mov", "_bp,sp");
3520             }
3521         }
3522       else
3523         {
3524           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3525             {
3526               /* set up the stack */
3527               emitcode ("push", "_bp");     /* save the callers stack  */
3528               emitcode ("mov", "_bp,sp");
3529             }
3530         }
3531     }
3532
3533   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3534   /* before setting up the stack frame completely. */
3535   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3536     {
3537       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3538
3539       if (rsym->isitmp)
3540         {
3541           if (rsym && rsym->regType == REG_CND)
3542             rsym = NULL;
3543           if (rsym && (rsym->accuse || rsym->ruonly))
3544             rsym = NULL;
3545           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3546             rsym = rsym->usl.spillLoc;
3547         }
3548
3549       /* If the RECEIVE operand immediately spills to the first entry on the */
3550       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3551       /* rather than the usual @r0/r1 machinations. */
3552       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3553         {
3554           int ofs;
3555
3556           _G.current_iCode = ric;
3557           D(emitcode (";     genReceive",""));
3558           for (ofs=0; ofs < sym->recvSize; ofs++)
3559             {
3560               if (!strcmp (fReturn[ofs], "a"))
3561                 emitcode ("push", "acc");
3562               else
3563                 emitcode ("push", fReturn[ofs]);
3564             }
3565           stackAdjust -= sym->recvSize;
3566           if (stackAdjust<0)
3567             {
3568               assert (stackAdjust>=0);
3569               stackAdjust = 0;
3570             }
3571           _G.current_iCode = ic;
3572           ric->generated = 1;
3573           accIsFree = 1;
3574         }
3575       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3576       /* to free up the accumulator. */
3577       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3578         {
3579           int ofs;
3580
3581           _G.current_iCode = ric;
3582           D(emitcode (";     genReceive",""));
3583           for (ofs=0; ofs < sym->recvSize; ofs++)
3584             {
3585               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3586             }
3587           _G.current_iCode = ic;
3588           ric->generated = 1;
3589           accIsFree = 1;
3590         }
3591     }
3592
3593   /* adjust the stack for the function */
3594   if (stackAdjust)
3595     {
3596       int i = stackAdjust;
3597       if (i > 256)
3598         werror (W_STACK_OVERFLOW, sym->name);
3599
3600       if (i > 3 && accIsFree)
3601         {
3602           emitcode ("mov", "a,sp");
3603           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3604           emitcode ("mov", "sp,a");
3605         }
3606       else if (i > 5)
3607         {
3608           /* The accumulator is not free, so we will need another register */
3609           /* to clobber. No need to worry about a possible conflict with */
3610           /* the above early RECEIVE optimizations since they would have */
3611           /* freed the accumulator if they were generated. */
3612
3613           if (IFFUNC_CALLEESAVES(sym->type))
3614             {
3615               /* if it's a callee-saves function we need a saved register */
3616               if (calleesaves_saved_register >= 0)
3617                 {
3618                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3619                   emitcode ("mov", "a,sp");
3620                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3621                   emitcode ("mov", "sp,a");
3622                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3623                 }
3624               else
3625                 /* do it the hard way */
3626                 while (i--)
3627                   emitcode ("inc", "sp");
3628             }
3629           else
3630             {
3631               /* not callee-saves, we can clobber r0 */
3632               emitcode ("mov", "r0,a");
3633               emitcode ("mov", "a,sp");
3634               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3635               emitcode ("mov", "sp,a");
3636               emitcode ("mov", "a,r0");
3637             }
3638         }
3639       else
3640         while (i--)
3641           emitcode ("inc", "sp");
3642     }
3643
3644   if (sym->xstack)
3645     {
3646       char i = ((char) sym->xstack & 0xff);
3647
3648       if (i > 3 && accIsFree)
3649         {
3650           emitcode ("mov", "a,_spx");
3651           emitcode ("add", "a,#0x%02x", i & 0xff);
3652           emitcode ("mov", "_spx,a");
3653         }
3654       else if (i > 5)
3655         {
3656           emitcode ("push", "acc");
3657           emitcode ("mov", "a,_spx");
3658           emitcode ("add", "a,#0x%02x", i & 0xff);
3659           emitcode ("mov", "_spx,a");
3660           emitcode ("pop", "acc");
3661         }
3662       else
3663         {
3664           while (i--)
3665             emitcode ("inc", "_spx");
3666         }
3667     }
3668
3669   /* if critical function then turn interrupts off */
3670   if (IFFUNC_ISCRITICAL (ftype))
3671     {
3672       symbol *tlbl = newiTempLabel (NULL);
3673       emitcode ("setb", "c");
3674       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3675       emitcode ("clr", "c");
3676       emitLabel (tlbl);
3677       emitcode ("push", "psw"); /* save old ea via c in psw */
3678     }
3679 }
3680
3681 /*-----------------------------------------------------------------*/
3682 /* genEndFunction - generates epilogue for functions               */
3683 /*-----------------------------------------------------------------*/
3684 static void
3685 genEndFunction (iCode * ic)
3686 {
3687   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3688   lineNode *lnp = lineCurr;
3689   bitVect  *regsUsed;
3690   bitVect  *regsUsedPrologue;
3691   bitVect  *regsUnneeded;
3692   int      idx;
3693
3694   _G.currentFunc = NULL;
3695   if (IFFUNC_ISNAKED(sym->type))
3696   {
3697       emitcode(";", "naked function: no epilogue.");
3698       if (options.debug && currFunc)
3699         debugFile->writeEndFunction (currFunc, ic, 0);
3700       return;
3701   }
3702
3703   if (IFFUNC_ISCRITICAL (sym->type))
3704     {
3705       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3706         {
3707           emitcode ("rlc", "a");   /* save c in a */
3708           emitcode ("pop", "psw"); /* restore ea via c in psw */
3709           emitcode ("mov", "ea,c");
3710           emitcode ("rrc", "a");   /* restore c from a */
3711         }
3712       else
3713         {
3714           emitcode ("pop", "psw"); /* restore ea via c in psw */
3715           emitcode ("mov", "ea,c");
3716         }
3717     }
3718
3719   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3720     {
3721       if (options.useXstack)
3722         {
3723           if (sym->stack)
3724             {
3725               emitcode ("mov", "sp,_bp");
3726               emitcode ("pop", "_bp");
3727             }
3728           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3729             {
3730               emitcode ("xch", "a,_bpx");
3731               emitcode ("mov", "r0,a");
3732               emitcode ("dec", "r0");
3733               emitcode ("movx", "a,@r0");
3734               emitcode ("xch", "a,_bpx");
3735               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3736             }
3737         }
3738       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3739         {
3740           if (sym->stack)
3741             emitcode ("mov", "sp,_bp");
3742           emitcode ("pop", "_bp");
3743         }
3744     }
3745
3746   /* restore the register bank  */
3747   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3748   {
3749     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3750      || !options.useXstack)
3751     {
3752         /* Special case of ISR using non-zero bank with useXstack
3753          * is handled below.
3754          */
3755         emitcode ("pop", "psw");
3756     }
3757   }
3758
3759   if (IFFUNC_ISISR (sym->type))
3760     {
3761
3762       /* now we need to restore the registers */
3763       /* if this isr has no bank i.e. is going to
3764          run with bank 0 , then we need to save more
3765          registers :-) */
3766       if (!FUNC_REGBANK (sym->type))
3767         {
3768           int i;
3769           /* if this function does not call any other
3770              function then we can be economical and
3771              save only those registers that are used */
3772           if (!IFFUNC_HASFCALL(sym->type))
3773             {
3774               /* if any registers used */
3775               if (sym->regsUsed)
3776                 {
3777                   bool bits_popped = FALSE;
3778                   /* save the registers used */
3779                   for (i = sym->regsUsed->size; i >= 0; i--)
3780                     {
3781                       if (bitVectBitValue (sym->regsUsed, i))
3782                         bits_popped = popReg (i, bits_popped);
3783                     }
3784                 }
3785             }
3786           else
3787             {
3788               if (options.parms_in_bank1) {
3789                   for (i = 7 ; i >= 0 ; i-- ) {
3790                       emitcode ("pop","%s",rb1regs[i]);
3791                   }
3792               }
3793               /* this function has  a function call cannot
3794                  determines register usage so we will have to pop the
3795                  entire bank */
3796               unsaveRBank (0, ic, FALSE);
3797             }
3798         }
3799         else
3800         {
3801             /* This ISR uses a non-zero bank.
3802              *
3803              * Restore any register banks saved by genFunction
3804              * in reverse order.
3805              */
3806             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3807             int ix;
3808
3809             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3810             {
3811                 if (savedBanks & (1 << ix))
3812                 {
3813                     unsaveRBank(ix, NULL, FALSE);
3814                 }
3815             }
3816
3817             if (options.useXstack)
3818             {
3819                 /* Restore bank AFTER calling unsaveRBank,
3820                  * since it can trash r0.
3821                  */
3822                 emitcode ("pop", "psw");
3823             }
3824         }
3825
3826       if (!inExcludeList ("dph"))
3827         emitcode ("pop", "dph");
3828       if (!inExcludeList ("dpl"))
3829         emitcode ("pop", "dpl");
3830       if (!inExcludeList ("b"))
3831         emitcode ("pop", "b");
3832       if (!inExcludeList ("acc"))
3833         emitcode ("pop", "acc");
3834
3835       /* if debug then send end of function */
3836       if (options.debug && currFunc)
3837         {
3838           debugFile->writeEndFunction (currFunc, ic, 1);
3839         }
3840
3841       emitcode ("reti", "");
3842     }
3843   else
3844     {
3845       if (IFFUNC_CALLEESAVES(sym->type))
3846         {
3847           int i;
3848
3849           /* if any registers used */
3850           if (sym->regsUsed)
3851             {
3852               /* save the registers used */
3853               for (i = sym->regsUsed->size; i >= 0; i--)
3854                 {
3855                   if (bitVectBitValue (sym->regsUsed, i) ||
3856                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3857                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3858                 }
3859             }
3860           else if (mcs51_ptrRegReq)
3861             {
3862               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3863               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3864             }
3865
3866         }
3867
3868       /* if debug then send end of function */
3869       if (options.debug && currFunc)
3870         {
3871           debugFile->writeEndFunction (currFunc, ic, 1);
3872         }
3873
3874       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3875         {
3876           emitcode ("ljmp", "__sdcc_banked_ret");
3877         }
3878       else
3879         {
3880           emitcode ("ret", "");
3881         }
3882     }
3883
3884   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3885     return;
3886
3887   /* If this was an interrupt handler using bank 0 that called another */
3888   /* function, then all registers must be saved; nothing to optimized. */
3889   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3890       && !FUNC_REGBANK(sym->type))
3891     return;
3892
3893   /* There are no push/pops to optimize if not callee-saves or ISR */
3894   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3895     return;
3896
3897   /* If there were stack parameters, we cannot optimize without also    */
3898   /* fixing all of the stack offsets; this is too dificult to consider. */
3899   if (FUNC_HASSTACKPARM(sym->type))
3900     return;
3901
3902   /* Compute the registers actually used */
3903   regsUsed = newBitVect (mcs51_nRegs);
3904   regsUsedPrologue = newBitVect (mcs51_nRegs);
3905   while (lnp)
3906     {
3907       if (lnp->ic && lnp->ic->op == FUNCTION)
3908         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3909       else
3910         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3911
3912       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3913           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3914         break;
3915       if (!lnp->prev)
3916         break;
3917       lnp = lnp->prev;
3918     }
3919
3920   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3921       && !bitVectBitValue (regsUsed, CND_IDX))
3922     {
3923       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3924       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3925           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3926         bitVectUnSetBit (regsUsed, CND_IDX);
3927     }
3928   else
3929     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3930
3931   /* If this was an interrupt handler that called another function */
3932   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3933   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3934     {
3935       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3936       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3937       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3938       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3939       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3940     }
3941
3942   /* Remove the unneeded push/pops */
3943   regsUnneeded = newBitVect (mcs51_nRegs);
3944   while (lnp)
3945     {
3946       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3947         {
3948           if (!strncmp(lnp->line, "push", 4))
3949             {
3950               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3951               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3952                 {
3953                   connectLine (lnp->prev, lnp->next);
3954                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3955                 }
3956             }
3957           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3958             {
3959               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3960               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3961                 {
3962                   connectLine (lnp->prev, lnp->next);
3963                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3964                 }
3965             }
3966         }
3967       lnp = lnp->next;
3968     }
3969
3970   for (idx = 0; idx < regsUnneeded->size; idx++)
3971     if (bitVectBitValue (regsUnneeded, idx))
3972       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
3973
3974   freeBitVect (regsUnneeded);
3975   freeBitVect (regsUsed);
3976   freeBitVect (regsUsedPrologue);
3977 }
3978
3979 /*-----------------------------------------------------------------*/
3980 /* genRet - generate code for return statement                     */
3981 /*-----------------------------------------------------------------*/
3982 static void
3983 genRet (iCode * ic)
3984 {
3985   int size, offset = 0, pushed = 0;
3986
3987   D (emitcode (";", "genRet"));
3988
3989   /* if we have no return value then
3990      just generate the "ret" */
3991   if (!IC_LEFT (ic))
3992     goto jumpret;
3993
3994   /* we have something to return then
3995      move the return value into place */
3996   aopOp (IC_LEFT (ic), ic, FALSE);
3997   size = AOP_SIZE (IC_LEFT (ic));
3998
3999   if (IS_BIT(_G.currentFunc->etype))
4000     {
4001       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
4002         emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4003       else
4004         movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4005     }
4006   else
4007     {
4008       while (size--)
4009         {
4010           char *l;
4011           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4012             {
4013               /* #NOCHANGE */
4014               l = aopGet (IC_LEFT (ic), offset++,
4015                           FALSE, TRUE);
4016               emitcode ("push", "%s", l);
4017               pushed++;
4018             }
4019           else
4020             {
4021               l = aopGet (IC_LEFT (ic), offset,
4022                           FALSE, FALSE);
4023               if (strcmp (fReturn[offset], l))
4024                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4025             }
4026         }
4027
4028       while (pushed)
4029         {
4030           pushed--;
4031           if (strcmp (fReturn[pushed], "a"))
4032             emitcode ("pop", fReturn[pushed]);
4033           else
4034             emitcode ("pop", "acc");
4035         }
4036     }
4037   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4038
4039 jumpret:
4040   /* generate a jump to the return label
4041      if the next is not the return statement */
4042   if (!(ic->next && ic->next->op == LABEL &&
4043         IC_LABEL (ic->next) == returnLabel))
4044
4045     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4046
4047 }
4048
4049 /*-----------------------------------------------------------------*/
4050 /* genLabel - generates a label                                    */
4051 /*-----------------------------------------------------------------*/
4052 static void
4053 genLabel (iCode * ic)
4054 {
4055   /* special case never generate */
4056   if (IC_LABEL (ic) == entryLabel)
4057     return;
4058
4059   emitLabel (IC_LABEL (ic));
4060 }
4061
4062 /*-----------------------------------------------------------------*/
4063 /* genGoto - generates a ljmp                                      */
4064 /*-----------------------------------------------------------------*/
4065 static void
4066 genGoto (iCode * ic)
4067 {
4068   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4069 }
4070
4071 /*-----------------------------------------------------------------*/
4072 /* findLabelBackwards: walks back through the iCode chain looking  */
4073 /* for the given label. Returns number of iCode instructions     */
4074 /* between that label and given ic.          */
4075 /* Returns zero if label not found.          */
4076 /*-----------------------------------------------------------------*/
4077 static int
4078 findLabelBackwards (iCode * ic, int key)
4079 {
4080   int count = 0;
4081
4082   while (ic->prev)
4083     {
4084       ic = ic->prev;
4085       count++;
4086
4087       /* If we have any pushes or pops, we cannot predict the distance.
4088          I don't like this at all, this should be dealt with in the
4089          back-end */
4090       if (ic->op == IPUSH || ic->op == IPOP) {
4091         return 0;
4092       }
4093
4094       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4095         {
4096           return count;
4097         }
4098     }
4099
4100   return 0;
4101 }
4102
4103 /*-----------------------------------------------------------------*/
4104 /* genPlusIncr :- does addition with increment if possible         */
4105 /*-----------------------------------------------------------------*/
4106 static bool
4107 genPlusIncr (iCode * ic)
4108 {
4109   unsigned int icount;
4110   unsigned int size = getDataSize (IC_RESULT (ic));
4111
4112   /* will try to generate an increment */
4113   /* if the right side is not a literal
4114      we cannot */
4115   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4116     return FALSE;
4117
4118   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4119
4120   D(emitcode (";","genPlusIncr"));
4121
4122   /* if increment >=16 bits in register or direct space */
4123   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4124         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4125         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4126       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4127       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4128       (size > 1) &&
4129       (icount == 1))
4130     {
4131       symbol *tlbl;
4132       int emitTlbl;
4133       int labelRange;
4134
4135       /* If the next instruction is a goto and the goto target
4136        * is < 10 instructions previous to this, we can generate
4137        * jumps straight to that target.
4138        */
4139       if (ic->next && ic->next->op == GOTO
4140           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4141           && labelRange <= 10)
4142         {
4143           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4144           tlbl = IC_LABEL (ic->next);
4145           emitTlbl = 0;
4146         }
4147       else
4148         {
4149           tlbl = newiTempLabel (NULL);
4150           emitTlbl = 1;
4151         }
4152       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4153       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4154           IS_AOP_PREG (IC_RESULT (ic)))
4155         emitcode ("cjne", "%s,#0x00,%05d$",
4156                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4157                   tlbl->key + 100);
4158       else
4159         {
4160           emitcode ("clr", "a");
4161           emitcode ("cjne", "a,%s,%05d$",
4162                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4163                     tlbl->key + 100);
4164         }
4165
4166       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4167       if (size > 2)
4168         {
4169           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4170               IS_AOP_PREG (IC_RESULT (ic)))
4171             emitcode ("cjne", "%s,#0x00,%05d$",
4172                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4173                       tlbl->key + 100);
4174           else
4175             emitcode ("cjne", "a,%s,%05d$",
4176                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4177                       tlbl->key + 100);
4178
4179           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4180         }
4181       if (size > 3)
4182         {
4183           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4184               IS_AOP_PREG (IC_RESULT (ic)))
4185             emitcode ("cjne", "%s,#0x00,%05d$",
4186                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4187                       tlbl->key + 100);
4188           else
4189             {
4190               emitcode ("cjne", "a,%s,%05d$",
4191                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4192                         tlbl->key + 100);
4193             }
4194           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4195         }
4196
4197       if (emitTlbl)
4198         {
4199           emitLabel (tlbl);
4200         }
4201       return TRUE;
4202     }
4203
4204   /* if result is dptr */
4205   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4206       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4207       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4208       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4209     {
4210       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4211         return FALSE;
4212
4213       if (icount > 9)
4214         return FALSE;
4215
4216       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4217         return FALSE;
4218
4219       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4220       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4221       while (icount--)
4222         emitcode ("inc", "dptr");
4223
4224       return TRUE;
4225     }
4226
4227   /* if the literal value of the right hand side
4228      is greater than 4 then it is not worth it */
4229   if (icount > 4)
4230     return FALSE;
4231
4232   /* if the sizes are greater than 1 then we cannot */
4233   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4234       AOP_SIZE (IC_LEFT (ic)) > 1)
4235     return FALSE;
4236
4237   /* we can if the aops of the left & result match or
4238      if they are in registers and the registers are the
4239      same */
4240   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4241     {
4242       if (icount > 3)
4243         {
4244           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4245           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4246           aopPut (IC_RESULT (ic), "a", 0);
4247         }
4248       else
4249         {
4250           while (icount--)
4251             {
4252               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4253             }
4254         }
4255
4256       return TRUE;
4257     }
4258
4259   if (icount == 1)
4260     {
4261       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4262       emitcode ("inc", "a");
4263       aopPut (IC_RESULT (ic), "a", 0);
4264       return TRUE;
4265     }
4266
4267   return FALSE;
4268 }
4269
4270 /*-----------------------------------------------------------------*/
4271 /* outBitAcc - output a bit in acc                                 */
4272 /*-----------------------------------------------------------------*/
4273 static void
4274 outBitAcc (operand * result)
4275 {
4276   symbol *tlbl = newiTempLabel (NULL);
4277   /* if the result is a bit */
4278   if (AOP_TYPE (result) == AOP_CRY)
4279     {
4280       aopPut (result, "a", 0);
4281     }
4282   else
4283     {
4284       emitcode ("jz", "%05d$", tlbl->key + 100);
4285       emitcode ("mov", "a,%s", one);
4286       emitLabel (tlbl);
4287       outAcc (result);
4288     }
4289 }
4290
4291 /*-----------------------------------------------------------------*/
4292 /* genPlusBits - generates code for addition of two bits           */
4293 /*-----------------------------------------------------------------*/
4294 static void
4295 genPlusBits (iCode * ic)
4296 {
4297   D (emitcode (";", "genPlusBits"));
4298
4299   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4300     {
4301       symbol *lbl = newiTempLabel (NULL);
4302       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4303       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4304       emitcode ("cpl", "c");
4305       emitLabel (lbl);
4306       outBitC (IC_RESULT (ic));
4307     }
4308   else
4309     {
4310       emitcode ("clr", "a");
4311       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4312       emitcode ("rlc", "a");
4313       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4314       emitcode ("addc", "a,%s", zero);
4315       outAcc (IC_RESULT (ic));
4316     }
4317 }
4318
4319 #if 0
4320 /* This is the original version of this code.
4321
4322  * This is being kept around for reference,
4323  * because I am not entirely sure I got it right...
4324  */
4325 static void
4326 adjustArithmeticResult (iCode * ic)
4327 {
4328   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4329       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4330       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4331     aopPut (IC_RESULT (ic),
4332             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4333             2);
4334
4335   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4336       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4337       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4338     aopPut (IC_RESULT (ic),
4339             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4340             2);
4341
4342   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4343       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4344       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4345       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4346       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4347     {
4348       char buffer[5];
4349       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4350       aopPut (IC_RESULT (ic), buffer, 2);
4351     }
4352 }
4353 #else
4354 /* This is the pure and virtuous version of this code.
4355  * I'm pretty certain it's right, but not enough to toss the old
4356  * code just yet...
4357  */
4358 static void
4359 adjustArithmeticResult (iCode * ic)
4360 {
4361   if (opIsGptr (IC_RESULT (ic)) &&
4362       opIsGptr (IC_LEFT (ic)) &&
4363       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4364     {
4365       aopPut (IC_RESULT (ic),
4366               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4367               GPTRSIZE - 1);
4368     }
4369
4370   if (opIsGptr (IC_RESULT (ic)) &&
4371       opIsGptr (IC_RIGHT (ic)) &&
4372       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4373     {
4374       aopPut (IC_RESULT (ic),
4375               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4376               GPTRSIZE - 1);
4377     }
4378
4379   if (opIsGptr (IC_RESULT (ic)) &&
4380       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4381       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4382       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4383       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4384     {
4385       char buffer[5];
4386       SNPRINTF (buffer, sizeof(buffer),
4387                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4388       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4389     }
4390 }
4391 #endif
4392
4393 /*-----------------------------------------------------------------*/
4394 /* genPlus - generates code for addition                           */
4395 /*-----------------------------------------------------------------*/
4396 static void
4397 genPlus (iCode * ic)
4398 {
4399   int size, offset = 0;
4400   int skip_bytes = 0;
4401   char *add = "add";
4402   bool swappedLR = FALSE;
4403   operand *leftOp, *rightOp;
4404   operand * op;
4405
4406   D (emitcode (";", "genPlus"));
4407
4408   /* special cases :- */
4409
4410   aopOp (IC_LEFT (ic), ic, FALSE);
4411   aopOp (IC_RIGHT (ic), ic, FALSE);
4412   aopOp (IC_RESULT (ic), ic, TRUE);
4413
4414   /* if literal, literal on the right or
4415      if left requires ACC or right is already
4416      in ACC */
4417   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4418       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4419       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4420     {
4421       operand *t = IC_RIGHT (ic);
4422       IC_RIGHT (ic) = IC_LEFT (ic);
4423       IC_LEFT (ic) = t;
4424       swappedLR = TRUE;
4425     }
4426
4427   /* if both left & right are in bit
4428      space */
4429   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4430       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4431     {
4432       genPlusBits (ic);
4433       goto release;
4434     }
4435
4436   /* if left in bit space & right literal */
4437   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4438       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4439     {
4440       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4441       /* if result in bit space */
4442       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4443         {
4444           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4445             emitcode ("cpl", "c");
4446           outBitC (IC_RESULT (ic));
4447         }
4448       else
4449         {
4450           size = getDataSize (IC_RESULT (ic));
4451           while (size--)
4452             {
4453               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4454               emitcode ("addc", "a,%s", zero);
4455               aopPut (IC_RESULT (ic), "a", offset++);
4456             }
4457         }
4458       goto release;
4459     }
4460
4461   /* if I can do an increment instead
4462      of add then GOOD for ME */
4463   if (genPlusIncr (ic) == TRUE)
4464     goto release;
4465
4466   size = getDataSize (IC_RESULT (ic));
4467   leftOp = IC_LEFT(ic);
4468   rightOp = IC_RIGHT(ic);
4469   op = IC_LEFT(ic);
4470
4471   /* if this is an add for an array access
4472      at a 256 byte boundary */
4473   if ( 2 == size
4474        && AOP_TYPE (op) == AOP_IMMD
4475        && IS_SYMOP (op)
4476        && IS_SPEC (OP_SYM_ETYPE (op))
4477        && SPEC_ABSA (OP_SYM_ETYPE (op))
4478        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4479      )
4480     {
4481       D(emitcode (";     genPlus aligned array",""));
4482       aopPut (IC_RESULT (ic),
4483               aopGet (rightOp, 0, FALSE, FALSE),
4484               0);
4485
4486       if( 1 == getDataSize (IC_RIGHT (ic)) )
4487         {
4488           aopPut (IC_RESULT (ic),
4489                   aopGet (leftOp, 1, FALSE, FALSE),
4490                   1);
4491         }
4492       else
4493         {
4494           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4495           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4496           aopPut (IC_RESULT (ic), "a", 1);
4497         }
4498       goto release;
4499     }
4500
4501   /* if the lower bytes of a literal are zero skip the addition */
4502   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4503     {
4504        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4505               (skip_bytes+1 < size))
4506          {
4507            skip_bytes++;
4508          }
4509        if (skip_bytes)
4510          D(emitcode (";     genPlus shortcut",""));
4511     }
4512
4513   while (size--)
4514     {
4515       if( offset >= skip_bytes )
4516         {
4517           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4518             {
4519               bool pushedB;
4520               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4521               pushedB = pushB ();
4522               emitcode("xch", "a,b");
4523               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4524               emitcode (add, "a,b");
4525               popB (pushedB);
4526             }
4527           else if (aopGetUsesAcc (leftOp, offset))
4528             {
4529               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4530               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4531             }
4532           else
4533             {
4534               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4535               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4536             }
4537           aopPut (IC_RESULT (ic), "a", offset);
4538           add = "addc";  /* further adds must propagate carry */
4539         }
4540       else
4541         {
4542           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4543               isOperandVolatile (IC_RESULT (ic), FALSE))
4544             {
4545               /* just move */
4546               aopPut (IC_RESULT (ic),
4547                       aopGet (leftOp, offset, FALSE, FALSE),
4548                       offset);
4549             }
4550         }
4551       offset++;
4552     }
4553
4554   adjustArithmeticResult (ic);
4555
4556 release:
4557   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4558   if (!swappedLR)
4559     {
4560       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4561       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4562     }
4563   else
4564     {
4565       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4566       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4567     }
4568 }
4569
4570 /*-----------------------------------------------------------------*/
4571 /* genMinusDec :- does subtraction with decrement if possible      */
4572 /*-----------------------------------------------------------------*/
4573 static bool
4574 genMinusDec (iCode * ic)
4575 {
4576   unsigned int icount;
4577   unsigned int size = getDataSize (IC_RESULT (ic));
4578
4579   /* will try to generate an increment */
4580   /* if the right side is not a literal
4581      we cannot */
4582   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4583     return FALSE;
4584
4585   /* if the literal value of the right hand side
4586      is greater than 4 then it is not worth it */
4587   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4588     return FALSE;
4589
4590   D (emitcode (";", "genMinusDec"));
4591
4592   /* if decrement >=16 bits in register or direct space */
4593   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4594         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4595         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4596       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4597       (size > 1) &&
4598       (icount == 1))
4599     {
4600       symbol *tlbl;
4601       int emitTlbl;
4602       int labelRange;
4603
4604       /* If the next instruction is a goto and the goto target
4605        * is <= 10 instructions previous to this, we can generate
4606        * jumps straight to that target.
4607        */
4608       if (ic->next && ic->next->op == GOTO
4609           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4610           && labelRange <= 10)
4611         {
4612           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4613           tlbl = IC_LABEL (ic->next);
4614           emitTlbl = 0;
4615         }
4616       else
4617         {
4618           tlbl = newiTempLabel (NULL);
4619           emitTlbl = 1;
4620         }
4621
4622       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4623       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4624           IS_AOP_PREG (IC_RESULT (ic)))
4625         emitcode ("cjne", "%s,#0xff,%05d$"
4626                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4627                   ,tlbl->key + 100);
4628       else
4629         {
4630           emitcode ("mov", "a,#0xff");
4631           emitcode ("cjne", "a,%s,%05d$"
4632                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4633                     ,tlbl->key + 100);
4634         }
4635       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4636       if (size > 2)
4637         {
4638           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4639               IS_AOP_PREG (IC_RESULT (ic)))
4640             emitcode ("cjne", "%s,#0xff,%05d$"
4641                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4642                       ,tlbl->key + 100);
4643           else
4644             {
4645               emitcode ("cjne", "a,%s,%05d$"
4646                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4647                         ,tlbl->key + 100);
4648             }
4649           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4650         }
4651       if (size > 3)
4652         {
4653           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4654               IS_AOP_PREG (IC_RESULT (ic)))
4655             emitcode ("cjne", "%s,#0xff,%05d$"
4656                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4657                       ,tlbl->key + 100);
4658           else
4659             {
4660               emitcode ("cjne", "a,%s,%05d$"
4661                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4662                         ,tlbl->key + 100);
4663             }
4664           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4665         }
4666       if (emitTlbl)
4667         {
4668           emitLabel (tlbl);
4669         }
4670       return TRUE;
4671     }
4672
4673   /* if the sizes are greater than 1 then we cannot */
4674   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4675       AOP_SIZE (IC_LEFT (ic)) > 1)
4676     return FALSE;
4677
4678   /* we can if the aops of the left & result match or
4679      if they are in registers and the registers are the
4680      same */
4681   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4682     {
4683       char *l;
4684
4685       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4686         {
4687           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4688           l = "a";
4689         }
4690       else
4691         {
4692           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4693         }
4694
4695       while (icount--)
4696         {
4697           emitcode ("dec", "%s", l);
4698         }
4699
4700       if (AOP_NEEDSACC (IC_RESULT (ic)))
4701         aopPut (IC_RESULT (ic), "a", 0);
4702
4703       return TRUE;
4704     }
4705
4706   if (icount == 1)
4707     {
4708       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4709       emitcode ("dec", "a");
4710       aopPut (IC_RESULT (ic), "a", 0);
4711       return TRUE;
4712     }
4713
4714   return FALSE;
4715 }
4716
4717 /*-----------------------------------------------------------------*/
4718 /* addSign - complete with sign                                    */
4719 /*-----------------------------------------------------------------*/
4720 static void
4721 addSign (operand * result, int offset, int sign)
4722 {
4723   int size = (getDataSize (result) - offset);
4724   if (size > 0)
4725     {
4726       if (sign)
4727         {
4728           emitcode ("rlc", "a");
4729           emitcode ("subb", "a,acc");
4730           while (size--)
4731             {
4732               aopPut (result, "a", offset++);
4733             }
4734         }
4735       else
4736         {
4737           while (size--)
4738             {
4739               aopPut (result, zero, offset++);
4740             }
4741         }
4742     }
4743 }
4744
4745 /*-----------------------------------------------------------------*/
4746 /* genMinusBits - generates code for subtraction  of two bits      */
4747 /*-----------------------------------------------------------------*/
4748 static void
4749 genMinusBits (iCode * ic)
4750 {
4751   symbol *lbl = newiTempLabel (NULL);
4752
4753   D (emitcode (";", "genMinusBits"));
4754
4755   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4756     {
4757       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4758       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4759       emitcode ("cpl", "c");
4760       emitLabel (lbl);
4761       outBitC (IC_RESULT (ic));
4762     }
4763   else
4764     {
4765       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4766       emitcode ("subb", "a,acc");
4767       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4768       emitcode ("inc", "a");
4769       emitLabel (lbl);
4770       aopPut (IC_RESULT (ic), "a", 0);
4771       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4772     }
4773 }
4774
4775 /*-----------------------------------------------------------------*/
4776 /* genMinus - generates code for subtraction                       */
4777 /*-----------------------------------------------------------------*/
4778 static void
4779 genMinus (iCode * ic)
4780 {
4781   int size, offset = 0;
4782
4783   D (emitcode (";", "genMinus"));
4784
4785   aopOp (IC_LEFT (ic), ic, FALSE);
4786   aopOp (IC_RIGHT (ic), ic, FALSE);
4787   aopOp (IC_RESULT (ic), ic, TRUE);
4788
4789   /* special cases :- */
4790   /* if both left & right are in bit space */
4791   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4792       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4793     {
4794       genMinusBits (ic);
4795       goto release;
4796     }
4797
4798   /* if I can do an decrement instead
4799      of subtract then GOOD for ME */
4800   if (genMinusDec (ic) == TRUE)
4801     goto release;
4802
4803   size = getDataSize (IC_RESULT (ic));
4804
4805   /* if literal, add a,#-lit, else normal subb */
4806   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4807     {
4808       unsigned long lit = 0L;
4809       bool useCarry = FALSE;
4810
4811       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4812       lit = -(long) lit;
4813
4814       while (size--)
4815         {
4816           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4817             {
4818               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4819               if (!offset && !size && lit== (unsigned long) -1)
4820                 {
4821                   emitcode ("dec", "a");
4822                 }
4823               else if (!useCarry)
4824                 {
4825                   /* first add without previous c */
4826                   emitcode ("add", "a,#0x%02x",
4827                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4828                   useCarry = TRUE;
4829                 }
4830               else
4831                 {
4832                   emitcode ("addc", "a,#0x%02x",
4833                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4834                 }
4835               aopPut (IC_RESULT (ic), "a", offset++);
4836             }
4837           else
4838             {
4839               /* no need to add zeroes */
4840               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4841                 {
4842                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4843                           offset);
4844                 }
4845               offset++;
4846             }
4847         }
4848     }
4849   else
4850     {
4851       operand *leftOp, *rightOp;
4852
4853       leftOp = IC_LEFT(ic);
4854       rightOp = IC_RIGHT(ic);
4855
4856       while (size--)
4857         {
4858           if (aopGetUsesAcc(rightOp, offset)) {
4859             if (aopGetUsesAcc(leftOp, offset)) {
4860               bool pushedB;
4861
4862               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4863               pushedB = pushB ();
4864               emitcode ("mov", "b,a");
4865               if (offset == 0)
4866                 CLRC;
4867               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4868               emitcode ("subb", "a,b");
4869               popB (pushedB);
4870             } else {
4871               /* reverse subtraction with 2's complement */
4872               if (offset == 0)
4873                 emitcode( "setb", "c");
4874               else
4875                 emitcode( "cpl", "c");
4876               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4877               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4878               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4879               emitcode("cpl", "a");
4880               if (size) /* skip if last byte */
4881                 emitcode( "cpl", "c");
4882             }
4883           } else {
4884             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4885             if (offset == 0)
4886               CLRC;
4887             emitcode ("subb", "a,%s",
4888                       aopGet(rightOp, offset, FALSE, TRUE));
4889           }
4890
4891           aopPut (IC_RESULT (ic), "a", offset++);
4892         }
4893     }
4894
4895   adjustArithmeticResult (ic);
4896
4897 release:
4898   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4899   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4900   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4901 }
4902
4903
4904 /*-----------------------------------------------------------------*/
4905 /* genMultbits :- multiplication of bits                           */
4906 /*-----------------------------------------------------------------*/
4907 static void
4908 genMultbits (operand * left,
4909              operand * right,
4910              operand * result)
4911 {
4912   D (emitcode (";", "genMultbits"));
4913
4914   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4915   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4916   outBitC (result);
4917 }
4918
4919 /*-----------------------------------------------------------------*/
4920 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4921 /*-----------------------------------------------------------------*/
4922 static void
4923 genMultOneByte (operand * left,
4924                 operand * right,
4925                 operand * result)
4926 {
4927   symbol *lbl;
4928   int size = AOP_SIZE (result);
4929   bool runtimeSign, compiletimeSign;
4930   bool lUnsigned, rUnsigned, pushedB;
4931
4932   D (emitcode (";", "genMultOneByte"));
4933
4934   if (size < 1 || size > 2)
4935     {
4936       /* this should never happen */
4937       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4938                AOP_SIZE(result), __FILE__, lineno);
4939       exit (1);
4940     }
4941
4942   /* (if two literals: the value is computed before) */
4943   /* if one literal, literal on the right */
4944   if (AOP_TYPE (left) == AOP_LIT)
4945     {
4946       operand *t = right;
4947       right = left;
4948       left = t;
4949       /* emitcode (";", "swapped left and right"); */
4950     }
4951   /* if no literal, unsigned on the right: shorter code */
4952   if (   AOP_TYPE (right) != AOP_LIT
4953       && SPEC_USIGN (getSpec (operandType (left))))
4954     {
4955       operand *t = right;
4956       right = left;
4957       left = t;
4958     }
4959
4960   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4961   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4962
4963   pushedB = pushB ();
4964
4965   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
4966                    no need to take care about the signedness! */
4967       || (lUnsigned && rUnsigned))
4968     {
4969       /* just an unsigned 8 * 8 = 8 multiply
4970          or 8u * 8u = 16u */
4971       /* emitcode (";","unsigned"); */
4972       /* TODO: check for accumulator clash between left & right aops? */
4973
4974       if (AOP_TYPE (right) == AOP_LIT)
4975         {
4976           /* moving to accumulator first helps peepholes */
4977           MOVA (aopGet (left, 0, FALSE, FALSE));
4978           MOVB (aopGet (right, 0, FALSE, FALSE));
4979         }
4980       else
4981         {
4982           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
4983           MOVA (aopGet (left, 0, FALSE, FALSE));
4984         }
4985
4986       emitcode ("mul", "ab");
4987       aopPut (result, "a", 0);
4988       if (size == 2)
4989         aopPut (result, "b", 1);
4990
4991       popB (pushedB);
4992       return;
4993     }
4994
4995   /* we have to do a signed multiply */
4996   /* emitcode (";", "signed"); */
4997
4998   /* now sign adjust for both left & right */
4999
5000   /* let's see what's needed: */
5001   /* apply negative sign during runtime */
5002   runtimeSign = FALSE;
5003   /* negative sign from literals */
5004   compiletimeSign = FALSE;
5005
5006   if (!lUnsigned)
5007     {
5008       if (AOP_TYPE(left) == AOP_LIT)
5009         {
5010           /* signed literal */
5011           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5012           if (val < 0)
5013             compiletimeSign = TRUE;
5014         }
5015       else
5016         /* signed but not literal */
5017         runtimeSign = TRUE;
5018     }
5019
5020   if (!rUnsigned)
5021     {
5022       if (AOP_TYPE(right) == AOP_LIT)
5023         {
5024           /* signed literal */
5025           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5026           if (val < 0)
5027             compiletimeSign ^= TRUE;
5028         }
5029       else
5030         /* signed but not literal */
5031         runtimeSign = TRUE;
5032     }
5033
5034   /* initialize F0, which stores the runtime sign */
5035   if (runtimeSign)
5036     {
5037       if (compiletimeSign)
5038         emitcode ("setb", "F0"); /* set sign flag */
5039       else
5040         emitcode ("clr", "F0"); /* reset sign flag */
5041     }
5042
5043   /* save the signs of the operands */
5044   if (AOP_TYPE(right) == AOP_LIT)
5045     {
5046       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5047
5048       if (!rUnsigned && val < 0)
5049         emitcode ("mov", "b,#0x%02x", -val);
5050       else
5051         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5052     }
5053   else /* ! literal */
5054     {
5055       if (rUnsigned)  /* emitcode (";", "signed"); */
5056         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5057       else
5058         {
5059           MOVA (aopGet (right, 0, FALSE, FALSE));
5060           lbl = newiTempLabel (NULL);
5061           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5062           emitcode ("cpl", "F0"); /* complement sign flag */
5063           emitcode ("cpl", "a");  /* 2's complement */
5064           emitcode ("inc", "a");
5065           emitLabel (lbl);
5066           emitcode ("mov", "b,a");
5067         }
5068     }
5069
5070   if (AOP_TYPE(left) == AOP_LIT)
5071     {
5072       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5073
5074       if (!lUnsigned && val < 0)
5075         emitcode ("mov", "a,#0x%02x", -val);
5076       else
5077         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5078     }
5079   else /* ! literal */
5080     {
5081       MOVA (aopGet (left, 0, FALSE, FALSE));
5082
5083       if (!lUnsigned)
5084         {
5085           lbl = newiTempLabel (NULL);
5086           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5087           emitcode ("cpl", "F0"); /* complement sign flag */
5088           emitcode ("cpl", "a"); /* 2's complement */
5089           emitcode ("inc", "a");
5090           emitLabel (lbl);
5091         }
5092     }
5093
5094   /* now the multiplication */
5095   emitcode ("mul", "ab");
5096   if (runtimeSign || compiletimeSign)
5097     {
5098       lbl = newiTempLabel (NULL);
5099       if (runtimeSign)
5100         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5101       emitcode ("cpl", "a"); /* lsb 2's complement */
5102       if (size != 2)
5103         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5104       else
5105         {
5106           emitcode ("add", "a,#1"); /* this sets carry flag */
5107           emitcode ("xch", "a,b");
5108           emitcode ("cpl", "a"); /* msb 2's complement */
5109           emitcode ("addc", "a,#0");
5110           emitcode ("xch", "a,b");
5111         }
5112       emitLabel (lbl);
5113     }
5114   aopPut (result, "a", 0);
5115   if (size == 2)
5116     aopPut (result, "b", 1);
5117
5118   popB (pushedB);
5119 }
5120
5121 /*-----------------------------------------------------------------*/
5122 /* genMult - generates code for multiplication                     */
5123 /*-----------------------------------------------------------------*/
5124 static void
5125 genMult (iCode * ic)
5126 {
5127   operand *left = IC_LEFT (ic);
5128   operand *right = IC_RIGHT (ic);
5129   operand *result = IC_RESULT (ic);
5130
5131   D (emitcode (";", "genMult"));
5132
5133   /* assign the asmops */
5134   aopOp (left, ic, FALSE);
5135   aopOp (right, ic, FALSE);
5136   aopOp (result, ic, TRUE);
5137
5138   /* special cases first */
5139   /* both are bits */
5140   if (AOP_TYPE (left) == AOP_CRY &&
5141       AOP_TYPE (right) == AOP_CRY)
5142     {
5143       genMultbits (left, right, result);
5144       goto release;
5145     }
5146
5147   /* if both are of size == 1 */
5148 #if 0 // one of them can be a sloc shared with the result
5149     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5150 #else
5151   if (getSize(operandType(left)) == 1 &&
5152       getSize(operandType(right)) == 1)
5153 #endif
5154     {
5155       genMultOneByte (left, right, result);
5156       goto release;
5157     }
5158
5159   /* should have been converted to function call */
5160     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5161              getSize(OP_SYMBOL(right)->type));
5162   assert (0);
5163
5164 release:
5165   freeAsmop (result, NULL, ic, TRUE);
5166   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5167   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5168 }
5169
5170 /*-----------------------------------------------------------------*/
5171 /* genDivbits :- division of bits                                  */
5172 /*-----------------------------------------------------------------*/
5173 static void
5174 genDivbits (operand * left,
5175             operand * right,
5176             operand * result)
5177 {
5178   char *l;
5179   bool pushedB;
5180
5181   D(emitcode (";     genDivbits",""));
5182
5183   pushedB = pushB ();
5184
5185   /* the result must be bit */
5186   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5187   l = aopGet (left, 0, FALSE, FALSE);
5188
5189   MOVA (l);
5190
5191   emitcode ("div", "ab");
5192   emitcode ("rrc", "a");
5193
5194   popB (pushedB);
5195
5196   aopPut (result, "c", 0);
5197 }
5198
5199 /*-----------------------------------------------------------------*/
5200 /* genDivOneByte : 8 bit division                                  */
5201 /*-----------------------------------------------------------------*/
5202 static void
5203 genDivOneByte (operand * left,
5204                operand * right,
5205                operand * result)
5206 {
5207   bool lUnsigned, rUnsigned, pushedB;
5208   bool runtimeSign, compiletimeSign;
5209   bool accuse = FALSE;
5210   bool pushedA = FALSE;
5211   symbol *lbl;
5212   int size, offset;
5213
5214   D(emitcode (";     genDivOneByte",""));
5215
5216   /* Why is it necessary that genDivOneByte() can return an int result?
5217      Have a look at:
5218
5219         volatile unsigned char uc;
5220         volatile signed char sc1, sc2;
5221         volatile int i;
5222
5223         uc  = 255;
5224         sc1 = -1;
5225         i = uc / sc1;
5226
5227      Or:
5228
5229         sc1 = -128;
5230         sc2 = -1;
5231         i = sc1 / sc2;
5232
5233      In all cases a one byte result would overflow, the following cast to int
5234      would return the wrong result.
5235
5236      Two possible solution:
5237         a) cast operands to int, if ((unsigned) / (signed)) or
5238            ((signed) / (signed))
5239         b) return an 16 bit signed int; this is what we're doing here!
5240   */
5241
5242   size = AOP_SIZE (result) - 1;
5243   offset = 1;
5244   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5245   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5246
5247   pushedB = pushB ();
5248
5249   /* signed or unsigned */
5250   if (lUnsigned && rUnsigned)
5251     {
5252       /* unsigned is easy */
5253       MOVB (aopGet (right, 0, FALSE, FALSE));
5254       MOVA (aopGet (left, 0, FALSE, FALSE));
5255       emitcode ("div", "ab");
5256       aopPut (result, "a", 0);
5257       while (size--)
5258         aopPut (result, zero, offset++);
5259
5260       popB (pushedB);
5261       return;
5262     }
5263
5264   /* signed is a little bit more difficult */
5265
5266   /* now sign adjust for both left & right */
5267
5268   /* let's see what's needed: */
5269   /* apply negative sign during runtime */
5270   runtimeSign = FALSE;
5271   /* negative sign from literals */
5272   compiletimeSign = FALSE;
5273
5274   if (!lUnsigned)
5275     {
5276       if (AOP_TYPE(left) == AOP_LIT)
5277         {
5278           /* signed literal */
5279           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5280           if (val < 0)
5281             compiletimeSign = TRUE;
5282         }
5283       else
5284         /* signed but not literal */
5285         runtimeSign = TRUE;
5286     }
5287
5288   if (!rUnsigned)
5289     {
5290       if (AOP_TYPE(right) == AOP_LIT)
5291         {
5292           /* signed literal */
5293           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5294           if (val < 0)
5295             compiletimeSign ^= TRUE;
5296         }
5297       else
5298         /* signed but not literal */
5299         runtimeSign = TRUE;
5300     }
5301
5302   /* initialize F0, which stores the runtime sign */
5303   if (runtimeSign)
5304     {
5305       if (compiletimeSign)
5306         emitcode ("setb", "F0"); /* set sign flag */
5307       else
5308         emitcode ("clr", "F0"); /* reset sign flag */
5309     }
5310
5311   /* save the signs of the operands */
5312   if (AOP_TYPE(right) == AOP_LIT)
5313     {
5314       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5315
5316       if (!rUnsigned && val < 0)
5317         emitcode ("mov", "b,#0x%02x", -val);
5318       else
5319         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5320     }
5321   else /* ! literal */
5322     {
5323       if (rUnsigned)
5324         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5325       else
5326         {
5327           MOVA (aopGet (right, 0, FALSE, FALSE));
5328           lbl = newiTempLabel (NULL);
5329           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5330           emitcode ("cpl", "F0"); /* complement sign flag */
5331           emitcode ("cpl", "a");  /* 2's complement */
5332           emitcode ("inc", "a");
5333           emitLabel (lbl);
5334           emitcode ("mov", "b,a");
5335         }
5336     }
5337
5338   if (AOP_TYPE(left) == AOP_LIT)
5339     {
5340       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5341
5342       if (!lUnsigned && val < 0)
5343         emitcode ("mov", "a,#0x%02x", -val);
5344       else
5345         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5346     }
5347   else /* ! literal */
5348     {
5349       MOVA (aopGet (left, 0, FALSE, FALSE));
5350
5351       if (!lUnsigned)
5352         {
5353           lbl = newiTempLabel (NULL);
5354           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5355           emitcode ("cpl", "F0"); /* complement sign flag */
5356           emitcode ("cpl", "a");  /* 2's complement */
5357           emitcode ("inc", "a");
5358           emitLabel (lbl);
5359         }
5360     }
5361
5362   /* now the division */
5363   emitcode ("div", "ab");
5364
5365   if (runtimeSign || compiletimeSign)
5366     {
5367       lbl = newiTempLabel (NULL);
5368       if (runtimeSign)
5369         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5370       emitcode ("cpl", "a"); /* lsb 2's complement */
5371       emitcode ("inc", "a");
5372       emitLabel (lbl);
5373
5374       accuse = aopPut (result, "a", 0);
5375       if (size > 0)
5376         {
5377           /* msb is 0x00 or 0xff depending on the sign */
5378           if (runtimeSign)
5379             {
5380               if (accuse)
5381                 {
5382                   emitcode ("push", "acc");
5383                   pushedA = TRUE;
5384                 }
5385               emitcode ("mov", "c,F0");
5386               emitcode ("subb", "a,acc");
5387               while (size--)
5388                 aopPut (result, "a", offset++);
5389             }
5390           else /* compiletimeSign */
5391             {
5392               if (aopPutUsesAcc (result, "#0xFF", offset))
5393                 {
5394                   emitcode ("push", "acc");
5395                   pushedA = TRUE;
5396                 }
5397               while (size--)
5398                 aopPut (result, "#0xff", offset++);
5399             }
5400         }
5401     }
5402   else
5403     {
5404       aopPut (result, "a", 0);
5405       while (size--)
5406         aopPut (result, zero, offset++);
5407     }
5408
5409   if (pushedA)
5410     emitcode ("pop", "acc");
5411   popB (pushedB);
5412 }
5413
5414 /*-----------------------------------------------------------------*/
5415 /* genDiv - generates code for division                            */
5416 /*-----------------------------------------------------------------*/
5417 static void
5418 genDiv (iCode * ic)
5419 {
5420   operand *left = IC_LEFT (ic);
5421   operand *right = IC_RIGHT (ic);
5422   operand *result = IC_RESULT (ic);
5423
5424   D (emitcode (";", "genDiv"));
5425
5426   /* assign the amsops */
5427   aopOp (left, ic, FALSE);
5428   aopOp (right, ic, FALSE);
5429   aopOp (result, ic, TRUE);
5430
5431   /* special cases first */
5432   /* both are bits */
5433   if (AOP_TYPE (left) == AOP_CRY &&
5434       AOP_TYPE (right) == AOP_CRY)
5435     {
5436       genDivbits (left, right, result);
5437       goto release;
5438     }
5439
5440   /* if both are of size == 1 */
5441   if (AOP_SIZE (left) == 1 &&
5442       AOP_SIZE (right) == 1)
5443     {
5444       genDivOneByte (left, right, result);
5445       goto release;
5446     }
5447
5448   /* should have been converted to function call */
5449   assert (0);
5450 release:
5451   freeAsmop (result, NULL, ic, TRUE);
5452   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5453   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5454 }
5455
5456 /*-----------------------------------------------------------------*/
5457 /* genModbits :- modulus of bits                                   */
5458 /*-----------------------------------------------------------------*/
5459 static void
5460 genModbits (operand * left,
5461             operand * right,
5462             operand * result)
5463 {
5464   char *l;
5465   bool pushedB;
5466
5467   D (emitcode (";", "genModbits"));
5468
5469   pushedB = pushB ();
5470
5471   /* the result must be bit */
5472   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5473   l = aopGet (left, 0, FALSE, FALSE);
5474
5475   MOVA (l);
5476
5477   emitcode ("div", "ab");
5478   emitcode ("mov", "a,b");
5479   emitcode ("rrc", "a");
5480
5481   popB (pushedB);
5482
5483   aopPut (result, "c", 0);
5484 }
5485
5486 /*-----------------------------------------------------------------*/
5487 /* genModOneByte : 8 bit modulus                                   */
5488 /*-----------------------------------------------------------------*/
5489 static void
5490 genModOneByte (operand * left,
5491                operand * right,
5492                operand * result)
5493 {
5494   bool lUnsigned, rUnsigned, pushedB;
5495   bool runtimeSign, compiletimeSign;
5496   symbol *lbl;
5497   int size, offset;
5498
5499   D (emitcode (";", "genModOneByte"));
5500
5501   size = AOP_SIZE (result) - 1;
5502   offset = 1;
5503   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5504   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5505
5506   /* if right is a literal, check it for 2^n */
5507   if (AOP_TYPE(right) == AOP_LIT)
5508     {
5509       unsigned char val = abs((int) operandLitValue(right));
5510       symbol *lbl2 = NULL;
5511
5512       switch (val)
5513         {
5514           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5515           case 2:
5516           case 4:
5517           case 8:
5518           case 16:
5519           case 32:
5520           case 64:
5521           case 128:
5522             if (lUnsigned)
5523               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5524                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5525               /* because iCode should have been changed to genAnd  */
5526               /* see file "SDCCopt.c", function "convertToFcall()" */
5527
5528             MOVA (aopGet (left, 0, FALSE, FALSE));
5529             emitcode ("mov", "c,acc.7");
5530             emitcode ("anl", "a,#0x%02x", val - 1);
5531             lbl = newiTempLabel (NULL);
5532             emitcode ("jz", "%05d$", (lbl->key + 100));
5533             emitcode ("jnc", "%05d$", (lbl->key + 100));
5534             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5535             if (size)
5536               {
5537                 int size2 = size;
5538                 int offs2 = offset;
5539
5540                 aopPut (result, "a", 0);
5541                 while (size2--)
5542                   aopPut (result, "#0xff", offs2++);
5543                 lbl2 = newiTempLabel (NULL);
5544                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5545               }
5546             emitLabel (lbl);
5547             aopPut (result, "a", 0);
5548             while (size--)
5549               aopPut (result, zero, offset++);
5550             if (lbl2)
5551               {
5552                 emitLabel (lbl2);
5553               }
5554             return;
5555
5556           default:
5557             break;
5558         }
5559     }
5560
5561   pushedB = pushB ();
5562
5563   /* signed or unsigned */
5564   if (lUnsigned && rUnsigned)
5565     {
5566       /* unsigned is easy */
5567       MOVB (aopGet (right, 0, FALSE, FALSE));
5568       MOVA (aopGet (left, 0, FALSE, FALSE));
5569       emitcode ("div", "ab");
5570       aopPut (result, "b", 0);
5571       while (size--)
5572         aopPut (result, zero, offset++);
5573
5574       popB (pushedB);
5575       return;
5576     }
5577
5578   /* signed is a little bit more difficult */
5579
5580   /* now sign adjust for both left & right */
5581
5582   /* modulus: sign of the right operand has no influence on the result! */
5583   if (AOP_TYPE(right) == AOP_LIT)
5584     {
5585       signed char val = (char) operandLitValue(right);
5586
5587       if (!rUnsigned && val < 0)
5588         emitcode ("mov", "b,#0x%02x", -val);
5589       else
5590         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5591     }
5592   else /* not literal */
5593     {
5594       if (rUnsigned)
5595         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5596       else
5597         {
5598           MOVA (aopGet (right, 0, FALSE, FALSE));
5599           lbl = newiTempLabel (NULL);
5600           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5601           emitcode ("cpl", "a"); /* 2's complement */
5602           emitcode ("inc", "a");
5603           emitLabel (lbl);
5604           emitcode ("mov", "b,a");
5605         }
5606     }
5607
5608   /* let's see what's needed: */
5609   /* apply negative sign during runtime */
5610   runtimeSign = FALSE;
5611   /* negative sign from literals */
5612   compiletimeSign = FALSE;
5613
5614   /* sign adjust left side */
5615   if (AOP_TYPE(left) == AOP_LIT)
5616     {
5617       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5618
5619       if (!lUnsigned && val < 0)
5620         {
5621           compiletimeSign = TRUE; /* set sign flag */
5622           emitcode ("mov", "a,#0x%02x", -val);
5623         }
5624       else
5625         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5626     }
5627   else /* ! literal */
5628     {
5629       MOVA (aopGet (left, 0, FALSE, FALSE));
5630
5631       if (!lUnsigned)
5632         {
5633           runtimeSign = TRUE;
5634           emitcode ("clr", "F0"); /* clear sign flag */
5635
5636           lbl = newiTempLabel (NULL);
5637           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5638           emitcode ("setb", "F0"); /* set sign flag */
5639           emitcode ("cpl", "a");   /* 2's complement */
5640           emitcode ("inc", "a");
5641           emitLabel (lbl);
5642         }
5643     }
5644
5645   /* now the modulus */
5646   emitcode ("div", "ab");
5647
5648   if (runtimeSign || compiletimeSign)
5649     {
5650       emitcode ("mov", "a,b");
5651       lbl = newiTempLabel (NULL);
5652       if (runtimeSign)
5653         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5654       emitcode ("cpl", "a"); /* 2's complement */
5655       emitcode ("inc", "a");
5656       emitLabel (lbl);
5657
5658       aopPut (result, "a", 0);
5659       if (size > 0)
5660         {
5661           /* msb is 0x00 or 0xff depending on the sign */
5662           if (runtimeSign)
5663             {
5664               emitcode ("mov", "c,F0");
5665               emitcode ("subb", "a,acc");
5666               while (size--)
5667                 aopPut (result, "a", offset++);
5668             }
5669           else /* compiletimeSign */
5670             while (size--)
5671               aopPut (result, "#0xff", offset++);
5672         }
5673     }
5674   else
5675     {
5676       aopPut (result, "b", 0);
5677       while (size--)
5678         aopPut (result, zero, offset++);
5679     }
5680
5681   popB (pushedB);
5682 }
5683
5684 /*-----------------------------------------------------------------*/
5685 /* genMod - generates code for division                            */
5686 /*-----------------------------------------------------------------*/
5687 static void
5688 genMod (iCode * ic)
5689 {
5690   operand *left = IC_LEFT (ic);
5691   operand *right = IC_RIGHT (ic);
5692   operand *result = IC_RESULT (ic);
5693
5694   D (emitcode (";", "genMod"));
5695
5696   /* assign the asmops */
5697   aopOp (left, ic, FALSE);
5698   aopOp (right, ic, FALSE);
5699   aopOp (result, ic, TRUE);
5700
5701   /* special cases first */
5702   /* both are bits */
5703   if (AOP_TYPE (left) == AOP_CRY &&
5704       AOP_TYPE (right) == AOP_CRY)
5705     {
5706       genModbits (left, right, result);
5707       goto release;
5708     }
5709
5710   /* if both are of size == 1 */
5711   if (AOP_SIZE (left) == 1 &&
5712       AOP_SIZE (right) == 1)
5713     {
5714       genModOneByte (left, right, result);
5715       goto release;
5716     }
5717
5718   /* should have been converted to function call */
5719   assert (0);
5720
5721 release:
5722   freeAsmop (result, NULL, ic, TRUE);
5723   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5724   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5725 }
5726
5727 /*-----------------------------------------------------------------*/
5728 /* genIfxJump :- will create a jump depending on the ifx           */
5729 /*-----------------------------------------------------------------*/
5730 static void
5731 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5732 {
5733   symbol *jlbl;
5734   symbol *tlbl = newiTempLabel (NULL);
5735   char *inst;
5736
5737   D (emitcode (";", "genIfxJump"));
5738
5739   /* if true label then we jump if condition
5740      supplied is true */
5741   if (IC_TRUE (ic))
5742     {
5743       jlbl = IC_TRUE (ic);
5744       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5745                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5746     }
5747   else
5748     {
5749       /* false label is present */
5750       jlbl = IC_FALSE (ic);
5751       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5752                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5753     }
5754   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5755     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5756   else
5757     emitcode (inst, "%05d$", tlbl->key + 100);
5758   freeForBranchAsmop (result);
5759   freeForBranchAsmop (right);
5760   freeForBranchAsmop (left);
5761   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5762   emitLabel (tlbl);
5763
5764   /* mark the icode as generated */
5765   ic->generated = 1;
5766 }
5767
5768 /*-----------------------------------------------------------------*/
5769 /* genCmp :- greater or less than comparison                       */
5770 /*-----------------------------------------------------------------*/
5771 static void
5772 genCmp (operand * left, operand * right,
5773         operand * result, iCode * ifx, int sign, iCode *ic)
5774 {
5775   int size, offset = 0;
5776   unsigned long lit = 0L;
5777   bool rightInB;
5778
5779   D (emitcode (";", "genCmp"));
5780
5781   /* if left & right are bit variables */
5782   if (AOP_TYPE (left) == AOP_CRY &&
5783       AOP_TYPE (right) == AOP_CRY)
5784     {
5785       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5786       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5787     }
5788   else
5789     {
5790       /* subtract right from left if at the
5791          end the carry flag is set then we know that
5792          left is greater than right */
5793       size = max (AOP_SIZE (left), AOP_SIZE (right));
5794
5795       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5796       if ((size == 1) && !sign &&
5797           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5798         {
5799           symbol *lbl = newiTempLabel (NULL);
5800           emitcode ("cjne", "%s,%s,%05d$",
5801                     aopGet (left, offset, FALSE, FALSE),
5802                     aopGet (right, offset, FALSE, FALSE),
5803                     lbl->key + 100);
5804           emitLabel (lbl);
5805         }
5806       else
5807         {
5808           if (AOP_TYPE (right) == AOP_LIT)
5809             {
5810               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5811               /* optimize if(x < 0) or if(x >= 0) */
5812               if (lit == 0L)
5813                 {
5814                   if (!sign)
5815                     {
5816                       CLRC;
5817                     }
5818                   else
5819                     {
5820                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5821                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5822                         {
5823                           genIfxJump (ifx, "acc.7", left, right, result);
5824                           freeAsmop (right, NULL, ic, TRUE);
5825                           freeAsmop (left, NULL, ic, TRUE);
5826
5827                           return;
5828                         }
5829                       else
5830                         {
5831                           emitcode ("rlc", "a");
5832                         }
5833                     }
5834                   goto release;
5835                 }
5836               else
5837                 {//nonzero literal
5838                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5839                   while (size && (bytelit == 0))
5840                     {
5841                       offset++;
5842                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5843                       size--;
5844                     }
5845                   CLRC;
5846                   while (size--)
5847                     {
5848                       MOVA (aopGet (left, offset, FALSE, FALSE));
5849                       if (sign && size == 0)
5850                         {
5851                           emitcode ("xrl", "a,#0x80");
5852                           emitcode ("subb", "a,#0x%02x",
5853                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5854                         }
5855                       else
5856                         {
5857                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5858                         }
5859                       offset++;
5860                     }
5861                   goto release;
5862                 }
5863             }
5864           CLRC;
5865           while (size--)
5866             {
5867               bool pushedB = FALSE;
5868               rightInB = aopGetUsesAcc(right, offset);
5869               if (rightInB)
5870                 {
5871                   pushedB = pushB ();
5872                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5873                 }
5874               MOVA (aopGet (left, offset, FALSE, FALSE));
5875               if (sign && size == 0)
5876                 {
5877                   emitcode ("xrl", "a,#0x80");
5878                   if (!rightInB)
5879                     {
5880                       pushedB = pushB ();
5881                       rightInB++;
5882                       MOVB (aopGet (right, offset, FALSE, FALSE));
5883                     }
5884                   emitcode ("xrl", "b,#0x80");
5885                   emitcode ("subb", "a,b");
5886                 }
5887               else
5888                 {
5889                   if (rightInB)
5890                     emitcode ("subb", "a,b");
5891                   else
5892                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5893                 }
5894               if (rightInB)
5895                 popB (pushedB);
5896               offset++;
5897             }
5898         }
5899     }
5900
5901 release:
5902   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5903   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5904   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5905     {
5906       outBitC (result);
5907     }
5908   else
5909     {
5910       /* if the result is used in the next
5911          ifx conditional branch then generate
5912          code a little differently */
5913       if (ifx)
5914         {
5915           genIfxJump (ifx, "c", NULL, NULL, result);
5916         }
5917       else
5918         {
5919           outBitC (result);
5920         }
5921       /* leave the result in acc */
5922     }
5923 }
5924
5925 /*-----------------------------------------------------------------*/
5926 /* genCmpGt :- greater than comparison                             */
5927 /*-----------------------------------------------------------------*/
5928 static void
5929 genCmpGt (iCode * ic, iCode * ifx)
5930 {
5931   operand *left, *right, *result;
5932   sym_link *letype, *retype;
5933   int sign;
5934
5935   D (emitcode (";", "genCmpGt"));
5936
5937   left = IC_LEFT (ic);
5938   right = IC_RIGHT (ic);
5939   result = IC_RESULT (ic);
5940
5941   letype = getSpec (operandType (left));
5942   retype = getSpec (operandType (right));
5943   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5944            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5945   /* assign the amsops */
5946   aopOp (result, ic, TRUE);
5947   aopOp (left, ic, FALSE);
5948   aopOp (right, ic, FALSE);
5949
5950   genCmp (right, left, result, ifx, sign, ic);
5951
5952   freeAsmop (result, NULL, ic, TRUE);
5953 }
5954
5955 /*-----------------------------------------------------------------*/
5956 /* genCmpLt - less than comparisons                                */
5957 /*-----------------------------------------------------------------*/
5958 static void
5959 genCmpLt (iCode * ic, iCode * ifx)
5960 {
5961   operand *left, *right, *result;
5962   sym_link *letype, *retype;
5963   int sign;
5964
5965   D (emitcode (";", "genCmpLt"));
5966
5967   left = IC_LEFT (ic);
5968   right = IC_RIGHT (ic);
5969   result = IC_RESULT (ic);
5970
5971   letype = getSpec (operandType (left));
5972   retype = getSpec (operandType (right));
5973   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5974            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5975   /* assign the amsops */
5976   aopOp (result, ic, TRUE);
5977   aopOp (left, ic, FALSE);
5978   aopOp (right, ic, FALSE);
5979
5980   genCmp (left, right, result, ifx, sign, ic);
5981
5982   freeAsmop (result, NULL, ic, TRUE);
5983 }
5984
5985 /*-----------------------------------------------------------------*/
5986 /* gencjneshort - compare and jump if not equal                    */
5987 /*-----------------------------------------------------------------*/
5988 static void
5989 gencjneshort (operand * left, operand * right, symbol * lbl)
5990 {
5991   int size = max (AOP_SIZE (left), AOP_SIZE (right));
5992   int offset = 0;
5993   unsigned long lit = 0L;
5994
5995   D (emitcode (";", "gencjneshort"));
5996
5997   /* if the left side is a literal or
5998      if the right is in a pointer register and left
5999      is not */
6000   if ((AOP_TYPE (left) == AOP_LIT) ||
6001       (AOP_TYPE (left) == AOP_IMMD) ||
6002       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6003     {
6004       operand *t = right;
6005       right = left;
6006       left = t;
6007     }
6008
6009   if (AOP_TYPE (right) == AOP_LIT)
6010     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6011
6012   /* if the right side is a literal then anything goes */
6013   if (AOP_TYPE (right) == AOP_LIT &&
6014       AOP_TYPE (left) != AOP_DIR  &&
6015       AOP_TYPE (left) != AOP_IMMD)
6016     {
6017       while (size--)
6018         {
6019           emitcode ("cjne", "%s,%s,%05d$",
6020                     aopGet (left, offset, FALSE, FALSE),
6021                     aopGet (right, offset, FALSE, FALSE),
6022                     lbl->key + 100);
6023           offset++;
6024         }
6025     }
6026
6027   /* if the right side is in a register or in direct space or
6028      if the left is a pointer register & right is not */
6029   else if (AOP_TYPE (right) == AOP_REG ||
6030            AOP_TYPE (right) == AOP_DIR ||
6031            AOP_TYPE (right) == AOP_LIT ||
6032            AOP_TYPE (right) == AOP_IMMD ||
6033            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6034            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6035     {
6036       while (size--)
6037         {
6038           MOVA (aopGet (left, offset, FALSE, FALSE));
6039           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6040               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6041             emitcode ("jnz", "%05d$", lbl->key + 100);
6042           else
6043             emitcode ("cjne", "a,%s,%05d$",
6044                       aopGet (right, offset, FALSE, TRUE),
6045                       lbl->key + 100);
6046           offset++;
6047         }
6048     }
6049   else
6050     {
6051       /* right is a pointer reg need both a & b */
6052       while (size--)
6053         {
6054           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6055           wassertl(!BINUSE, "B was in use");
6056           MOVB (aopGet (left, offset, FALSE, FALSE));
6057           MOVA (aopGet (right, offset, FALSE, FALSE));
6058           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6059           offset++;
6060         }
6061     }
6062 }
6063
6064 /*-----------------------------------------------------------------*/
6065 /* gencjne - compare and jump if not equal                         */
6066 /*-----------------------------------------------------------------*/
6067 static void
6068 gencjne (operand * left, operand * right, symbol * lbl)
6069 {
6070   symbol *tlbl = newiTempLabel (NULL);
6071
6072   D (emitcode (";", "gencjne"));
6073
6074   gencjneshort (left, right, lbl);
6075
6076   emitcode ("mov", "a,%s", one);
6077   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6078   emitLabel (lbl);
6079   emitcode ("clr", "a");
6080   emitLabel (tlbl);
6081 }
6082
6083 /*-----------------------------------------------------------------*/
6084 /* genCmpEq - generates code for equal to                          */
6085 /*-----------------------------------------------------------------*/
6086 static void
6087 genCmpEq (iCode * ic, iCode * ifx)
6088 {
6089   bool swappedLR = FALSE;
6090   operand *left, *right, *result;
6091
6092   D (emitcode (";", "genCmpEq"));
6093
6094   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6095   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6096   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6097
6098   /* if literal, literal on the right or
6099      if the right is in a pointer register and left
6100      is not */
6101   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6102       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6103     {
6104       operand *t = IC_RIGHT (ic);
6105       IC_RIGHT (ic) = IC_LEFT (ic);
6106       IC_LEFT (ic) = t;
6107       swappedLR = TRUE;
6108     }
6109
6110   if (ifx && !AOP_SIZE (result))
6111     {
6112       symbol *tlbl;
6113       /* if they are both bit variables */
6114       if (AOP_TYPE (left) == AOP_CRY &&
6115           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6116         {
6117           if (AOP_TYPE (right) == AOP_LIT)
6118             {
6119               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6120               if (lit == 0L)
6121                 {
6122                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6123                   emitcode ("cpl", "c");
6124                 }
6125               else if (lit == 1L)
6126                 {
6127                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6128                 }
6129               else
6130                 {
6131                   emitcode ("clr", "c");
6132                 }
6133               /* AOP_TYPE(right) == AOP_CRY */
6134             }
6135           else
6136             {
6137               symbol *lbl = newiTempLabel (NULL);
6138               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6139               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6140               emitcode ("cpl", "c");
6141               emitLabel (lbl);
6142             }
6143           /* if true label then we jump if condition
6144              supplied is true */
6145           tlbl = newiTempLabel (NULL);
6146           if (IC_TRUE (ifx))
6147             {
6148               emitcode ("jnc", "%05d$", tlbl->key + 100);
6149               freeForBranchAsmop (result);
6150               freeForBranchAsmop (right);
6151               freeForBranchAsmop (left);
6152               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6153             }
6154           else
6155             {
6156               emitcode ("jc", "%05d$", tlbl->key + 100);
6157               freeForBranchAsmop (result);
6158               freeForBranchAsmop (right);
6159               freeForBranchAsmop (left);
6160               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6161             }
6162           emitLabel (tlbl);
6163         }
6164       else
6165         {
6166           tlbl = newiTempLabel (NULL);
6167           gencjneshort (left, right, tlbl);
6168           if (IC_TRUE (ifx))
6169             {
6170               freeForBranchAsmop (result);
6171               freeForBranchAsmop (right);
6172               freeForBranchAsmop (left);
6173               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6174               emitLabel (tlbl);
6175             }
6176           else
6177             {
6178               symbol *lbl = newiTempLabel (NULL);
6179               emitcode ("sjmp", "%05d$", lbl->key + 100);
6180               emitLabel (tlbl);
6181               freeForBranchAsmop (result);
6182               freeForBranchAsmop (right);
6183               freeForBranchAsmop (left);
6184               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6185               emitLabel (lbl);
6186             }
6187         }
6188       /* mark the icode as generated */
6189       ifx->generated = 1;
6190       goto release;
6191     }
6192
6193   /* if they are both bit variables */
6194   if (AOP_TYPE (left) == AOP_CRY &&
6195       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6196     {
6197       if (AOP_TYPE (right) == AOP_LIT)
6198         {
6199           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6200           if (lit == 0L)
6201             {
6202               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6203               emitcode ("cpl", "c");
6204             }
6205           else if (lit == 1L)
6206             {
6207               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6208             }
6209           else
6210             {
6211               emitcode ("clr", "c");
6212             }
6213           /* AOP_TYPE(right) == AOP_CRY */
6214         }
6215       else
6216         {
6217           symbol *lbl = newiTempLabel (NULL);
6218           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6219           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6220           emitcode ("cpl", "c");
6221           emitLabel (lbl);
6222         }
6223       /* c = 1 if egal */
6224       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6225         {
6226           outBitC (result);
6227           goto release;
6228         }
6229       if (ifx)
6230         {
6231           genIfxJump (ifx, "c", left, right, result);
6232           goto release;
6233         }
6234       /* if the result is used in an arithmetic operation
6235          then put the result in place */
6236       outBitC (result);
6237     }
6238   else
6239     {
6240       gencjne (left, right, newiTempLabel (NULL));
6241       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6242         {
6243           aopPut (result, "a", 0);
6244           goto release;
6245         }
6246       if (ifx)
6247         {
6248           genIfxJump (ifx, "a", left, right, result);
6249           goto release;
6250         }
6251       /* if the result is used in an arithmetic operation
6252          then put the result in place */
6253       if (AOP_TYPE (result) != AOP_CRY)
6254         outAcc (result);
6255       /* leave the result in acc */
6256     }
6257
6258 release:
6259   freeAsmop (result, NULL, ic, TRUE);
6260   if (!swappedLR)
6261     {
6262       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6263       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6264     }
6265   else
6266     {
6267       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6268       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6269     }
6270 }
6271
6272 /*-----------------------------------------------------------------*/
6273 /* ifxForOp - returns the icode containing the ifx for operand     */
6274 /*-----------------------------------------------------------------*/
6275 static iCode *
6276 ifxForOp (operand * op, iCode * ic)
6277 {
6278   /* if true symbol then needs to be assigned */
6279   if (IS_TRUE_SYMOP (op))
6280     return NULL;
6281
6282   /* if this has register type condition and
6283      the next instruction is ifx with the same operand
6284      and live to of the operand is upto the ifx only then */
6285   if (ic->next &&
6286       ic->next->op == IFX &&
6287       IC_COND (ic->next)->key == op->key &&
6288       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6289     return ic->next;
6290
6291   return NULL;
6292 }
6293
6294 /*-----------------------------------------------------------------*/
6295 /* hasInc - operand is incremented before any other use            */
6296 /*-----------------------------------------------------------------*/
6297 static iCode *
6298 hasInc (operand *op, iCode *ic, int osize)
6299 {
6300   sym_link *type = operandType(op);
6301   sym_link *retype = getSpec (type);
6302   iCode *lic = ic->next;
6303   int isize ;
6304
6305   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6306   if (!IS_SYMOP(op)) return NULL;
6307
6308   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6309   if (IS_AGGREGATE(type->next)) return NULL;
6310   if (osize != (isize = getSize(type->next))) return NULL;
6311
6312   while (lic) {
6313     /* if operand of the form op = op + <sizeof *op> */
6314     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6315         isOperandEqual(IC_RESULT(lic),op) &&
6316         isOperandLiteral(IC_RIGHT(lic)) &&
6317         operandLitValue(IC_RIGHT(lic)) == isize) {
6318       return lic;
6319     }
6320     /* if the operand used or deffed */
6321     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6322       return NULL;
6323     }
6324     /* if GOTO or IFX */
6325     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6326     lic = lic->next;
6327   }
6328   return NULL;
6329 }
6330
6331 /*-----------------------------------------------------------------*/
6332 /* genAndOp - for && operation                                     */
6333 /*-----------------------------------------------------------------*/
6334 static void
6335 genAndOp (iCode * ic)
6336 {
6337   operand *left, *right, *result;
6338   symbol *tlbl;
6339
6340   D (emitcode (";", "genAndOp"));
6341
6342   /* note here that && operations that are in an
6343      if statement are taken away by backPatchLabels
6344      only those used in arthmetic operations remain */
6345   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6346   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6347   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6348
6349   /* if both are bit variables */
6350   if (AOP_TYPE (left) == AOP_CRY &&
6351       AOP_TYPE (right) == AOP_CRY)
6352     {
6353       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6354       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6355       outBitC (result);
6356     }
6357   else
6358     {
6359       tlbl = newiTempLabel (NULL);
6360       toBoolean (left);
6361       emitcode ("jz", "%05d$", tlbl->key + 100);
6362       toBoolean (right);
6363       emitLabel (tlbl);
6364       outBitAcc (result);
6365     }
6366
6367   freeAsmop (result, NULL, ic, TRUE);
6368   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6369   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6370 }
6371
6372
6373 /*-----------------------------------------------------------------*/
6374 /* genOrOp - for || operation                                      */
6375 /*-----------------------------------------------------------------*/
6376 static void
6377 genOrOp (iCode * ic)
6378 {
6379   operand *left, *right, *result;
6380   symbol *tlbl;
6381
6382   D (emitcode (";", "genOrOp"));
6383
6384   /* note here that || operations that are in an
6385      if statement are taken away by backPatchLabels
6386      only those used in arthmetic operations remain */
6387   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6388   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6389   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6390
6391   /* if both are bit variables */
6392   if (AOP_TYPE (left) == AOP_CRY &&
6393       AOP_TYPE (right) == AOP_CRY)
6394     {
6395       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6396       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6397       outBitC (result);
6398     }
6399   else
6400     {
6401       tlbl = newiTempLabel (NULL);
6402       toBoolean (left);
6403       emitcode ("jnz", "%05d$", tlbl->key + 100);
6404       toBoolean (right);
6405       emitLabel (tlbl);
6406       outBitAcc (result);
6407     }
6408
6409   freeAsmop (result, NULL, ic, TRUE);
6410   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6411   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6412 }
6413
6414 /*-----------------------------------------------------------------*/
6415 /* isLiteralBit - test if lit == 2^n                               */
6416 /*-----------------------------------------------------------------*/
6417 static int
6418 isLiteralBit (unsigned long lit)
6419 {
6420   unsigned long pw[32] =
6421   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6422    0x100L, 0x200L, 0x400L, 0x800L,
6423    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6424    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6425    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6426    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6427    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6428   int idx;
6429
6430   for (idx = 0; idx < 32; idx++)
6431     if (lit == pw[idx])
6432       return idx + 1;
6433   return 0;
6434 }
6435
6436 /*-----------------------------------------------------------------*/
6437 /* continueIfTrue -                                                */
6438 /*-----------------------------------------------------------------*/
6439 static void
6440 continueIfTrue (iCode * ic)
6441 {
6442   if (IC_TRUE (ic))
6443     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6444   ic->generated = 1;
6445 }
6446
6447 /*-----------------------------------------------------------------*/
6448 /* jmpIfTrue -                                                     */
6449 /*-----------------------------------------------------------------*/
6450 static void
6451 jumpIfTrue (iCode * ic)
6452 {
6453   if (!IC_TRUE (ic))
6454     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6455   ic->generated = 1;
6456 }
6457
6458 /*-----------------------------------------------------------------*/
6459 /* jmpTrueOrFalse -                                                */
6460 /*-----------------------------------------------------------------*/
6461 static void
6462 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6463 {
6464   // ugly but optimized by peephole
6465   if (IC_TRUE (ic))
6466     {
6467       symbol *nlbl = newiTempLabel (NULL);
6468       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6469       emitLabel (tlbl);
6470       freeForBranchAsmop (result);
6471       freeForBranchAsmop (right);
6472       freeForBranchAsmop (left);
6473       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6474       emitLabel (nlbl);
6475     }
6476   else
6477     {
6478       freeForBranchAsmop (result);
6479       freeForBranchAsmop (right);
6480       freeForBranchAsmop (left);
6481       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6482       emitLabel (tlbl);
6483     }
6484   ic->generated = 1;
6485 }
6486
6487 /*-----------------------------------------------------------------*/
6488 /* genAnd  - code for and                                          */
6489 /*-----------------------------------------------------------------*/
6490 static void
6491 genAnd (iCode * ic, iCode * ifx)
6492 {
6493   operand *left, *right, *result;
6494   int size, offset = 0;
6495   unsigned long lit = 0L;
6496   int bytelit = 0;
6497   char buffer[10];
6498
6499   D (emitcode (";", "genAnd"));
6500
6501   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6502   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6503   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6504
6505 #ifdef DEBUG_TYPE
6506   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6507             AOP_TYPE (result),
6508             AOP_TYPE (left), AOP_TYPE (right));
6509   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6510             AOP_SIZE (result),
6511             AOP_SIZE (left), AOP_SIZE (right));
6512 #endif
6513
6514   /* if left is a literal & right is not then exchange them */
6515   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6516       AOP_NEEDSACC (left))
6517     {
6518       operand *tmp = right;
6519       right = left;
6520       left = tmp;
6521     }
6522
6523   /* if result = right then exchange left and right */
6524   if (sameRegs (AOP (result), AOP (right)))
6525     {
6526       operand *tmp = right;
6527       right = left;
6528       left = tmp;
6529     }
6530
6531   /* if right is bit then exchange them */
6532   if (AOP_TYPE (right) == AOP_CRY &&
6533       AOP_TYPE (left) != AOP_CRY)
6534     {
6535       operand *tmp = right;
6536       right = left;
6537       left = tmp;
6538     }
6539   if (AOP_TYPE (right) == AOP_LIT)
6540     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6541
6542   size = AOP_SIZE (result);
6543
6544   // if(bit & yy)
6545   // result = bit & yy;
6546   if (AOP_TYPE (left) == AOP_CRY)
6547     {
6548       // c = bit & literal;
6549       if (AOP_TYPE (right) == AOP_LIT)
6550         {
6551           if (lit & 1)
6552             {
6553               if (size && sameRegs (AOP (result), AOP (left)))
6554                 // no change
6555                 goto release;
6556               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6557             }
6558           else
6559             {
6560               // bit(result) = 0;
6561               if (size && (AOP_TYPE (result) == AOP_CRY))
6562                 {
6563                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6564                   goto release;
6565                 }
6566               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6567                 {
6568                   jumpIfTrue (ifx);
6569                   goto release;
6570                 }
6571               emitcode ("clr", "c");
6572             }
6573         }
6574       else
6575         {
6576           if (AOP_TYPE (right) == AOP_CRY)
6577             {
6578               // c = bit & bit;
6579               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6580               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6581             }
6582           else
6583             {
6584               // c = bit & val;
6585               MOVA (aopGet (right, 0, FALSE, FALSE));
6586               // c = lsb
6587               emitcode ("rrc", "a");
6588               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6589             }
6590         }
6591       // bit = c
6592       // val = c
6593       if (size)
6594         outBitC (result);
6595       // if(bit & ...)
6596       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6597         genIfxJump (ifx, "c", left, right, result);
6598       goto release;
6599     }
6600
6601   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6602   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6603   if ((AOP_TYPE (right) == AOP_LIT) &&
6604       (AOP_TYPE (result) == AOP_CRY) &&
6605       (AOP_TYPE (left) != AOP_CRY))
6606     {
6607       int posbit = isLiteralBit (lit);
6608       /* left &  2^n */
6609       if (posbit)
6610         {
6611           posbit--;
6612           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6613           // bit = left & 2^n
6614           if (size)
6615             {
6616               switch (posbit & 0x07)
6617                 {
6618                   case 0: emitcode ("rrc", "a");
6619                           break;
6620                   case 7: emitcode ("rlc", "a");
6621                           break;
6622                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6623                           break;
6624                 }
6625             }
6626           // if(left &  2^n)
6627           else
6628             {
6629               if (ifx)
6630                 {
6631                   SNPRINTF (buffer, sizeof(buffer),
6632                             "acc.%d", posbit & 0x07);
6633                   genIfxJump (ifx, buffer, left, right, result);
6634                 }
6635               else
6636                 {// what is this case? just found it in ds390/gen.c
6637                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6638                 }
6639               goto release;
6640             }
6641         }
6642       else
6643         {
6644           symbol *tlbl = newiTempLabel (NULL);
6645           int sizel = AOP_SIZE (left);
6646           if (size)
6647             emitcode ("setb", "c");
6648           while (sizel--)
6649             {
6650               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6651                 {
6652                   MOVA (aopGet (left, offset, FALSE, FALSE));
6653                   // byte ==  2^n ?
6654                   if ((posbit = isLiteralBit (bytelit)) != 0)
6655                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6656                   else
6657                     {
6658                       if (bytelit != 0x0FFL)
6659                         emitcode ("anl", "a,%s",
6660                                   aopGet (right, offset, FALSE, TRUE));
6661                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6662                     }
6663                 }
6664               offset++;
6665             }
6666           // bit = left & literal
6667           if (size)
6668             {
6669               emitcode ("clr", "c");
6670               emitLabel (tlbl);
6671             }
6672           // if(left & literal)
6673           else
6674             {
6675               if (ifx)
6676                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6677               else
6678                 emitLabel (tlbl);
6679               goto release;
6680             }
6681         }
6682       outBitC (result);
6683       goto release;
6684     }
6685
6686   /* if left is same as result */
6687   if (sameRegs (AOP (result), AOP (left)))
6688     {
6689       for (; size--; offset++)
6690         {
6691           if (AOP_TYPE (right) == AOP_LIT)
6692             {
6693               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6694               if (bytelit == 0x0FF)
6695                 {
6696                   /* dummy read of volatile operand */
6697                   if (isOperandVolatile (left, FALSE))
6698                     MOVA (aopGet (left, offset, FALSE, FALSE));
6699                   else
6700                     continue;
6701                 }
6702               else if (bytelit == 0)
6703                 {
6704                   aopPut (result, zero, offset);
6705                 }
6706               else if (IS_AOP_PREG (result))
6707                 {
6708                   MOVA (aopGet (left, offset, FALSE, TRUE));
6709                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6710                   aopPut (result, "a", offset);
6711                 }
6712               else
6713                 emitcode ("anl", "%s,%s",
6714                           aopGet (left, offset, FALSE, TRUE),
6715                           aopGet (right, offset, FALSE, FALSE));
6716             }
6717           else
6718             {
6719               if (AOP_TYPE (left) == AOP_ACC)
6720                 {
6721                   if (offset)
6722                     emitcode("mov", "a,b");
6723                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6724                 }
6725               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6726                 {
6727                   MOVB (aopGet (left, offset, FALSE, FALSE));
6728                   MOVA (aopGet (right, offset, FALSE, FALSE));
6729                   emitcode ("anl", "a,b");
6730                   aopPut (result, "a", offset);
6731                 }
6732               else if (aopGetUsesAcc (left, offset))
6733                 {
6734                   MOVA (aopGet (left, offset, FALSE, FALSE));
6735                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6736                   aopPut (result, "a", offset);
6737                 }
6738               else
6739                 {
6740                   MOVA (aopGet (right, offset, FALSE, FALSE));
6741                   if (IS_AOP_PREG (result))
6742                     {
6743                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6744                       aopPut (result, "a", offset);
6745                     }
6746                   else
6747                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6748                 }
6749             }
6750         }
6751     }
6752   else
6753     {
6754       // left & result in different registers
6755       if (AOP_TYPE (result) == AOP_CRY)
6756         {
6757           // result = bit
6758           // if(size), result in bit
6759           // if(!size && ifx), conditional oper: if(left & right)
6760           symbol *tlbl = newiTempLabel (NULL);
6761           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6762           if (size)
6763             emitcode ("setb", "c");
6764           while (sizer--)
6765             {
6766               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6767                   && AOP_TYPE(left)==AOP_ACC)
6768                 {
6769                   if (offset)
6770                     emitcode("mov", "a,b");
6771                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6772                 }
6773               else if (AOP_TYPE(left)==AOP_ACC)
6774                 {
6775                   if (!offset)
6776                     {
6777                       bool pushedB = pushB ();
6778                       emitcode("mov", "b,a");
6779                       MOVA (aopGet (right, offset, FALSE, FALSE));
6780                       emitcode("anl", "a,b");
6781                       popB (pushedB);
6782                     }
6783                   else
6784                     {
6785                       MOVA (aopGet (right, offset, FALSE, FALSE));
6786                       emitcode("anl", "a,b");
6787                     }
6788                 }
6789               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6790                 {
6791                   MOVB (aopGet (left, offset, FALSE, FALSE));
6792                   MOVA (aopGet (right, offset, FALSE, FALSE));
6793                   emitcode ("anl", "a,b");
6794                 }
6795               else if (aopGetUsesAcc (left, offset))
6796                 {
6797                   MOVA (aopGet (left, offset, FALSE, FALSE));
6798                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6799                     }
6800               else
6801                 {
6802                   MOVA (aopGet (right, offset, FALSE, FALSE));
6803                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6804                 }
6805
6806               emitcode ("jnz", "%05d$", tlbl->key + 100);
6807               offset++;
6808             }
6809           if (size)
6810             {
6811               CLRC;
6812               emitLabel (tlbl);
6813               outBitC (result);
6814             }
6815           else if (ifx)
6816             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6817           else
6818             emitLabel (tlbl);
6819         }
6820       else
6821         {
6822           for (; (size--); offset++)
6823             {
6824               // normal case
6825               // result = left & right
6826               if (AOP_TYPE (right) == AOP_LIT)
6827                 {
6828                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6829                   if (bytelit == 0x0FF)
6830                     {
6831                       aopPut (result,
6832                               aopGet (left, offset, FALSE, FALSE),
6833                               offset);
6834                       continue;
6835                     }
6836                   else if (bytelit == 0)
6837                     {
6838                       /* dummy read of volatile operand */
6839                       if (isOperandVolatile (left, FALSE))
6840                         MOVA (aopGet (left, offset, FALSE, FALSE));
6841                       aopPut (result, zero, offset);
6842                       continue;
6843                     }
6844                   else if (AOP_TYPE (left) == AOP_ACC)
6845                     {
6846                       if (!offset)
6847                         {
6848                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6849                           aopPut (result, "a", offset);
6850                           continue;
6851                         }
6852                       else
6853                         {
6854                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6855                           aopPut (result, "b", offset);
6856                           continue;
6857                         }
6858                     }
6859                 }
6860               // faster than result <- left, anl result,right
6861               // and better if result is SFR
6862               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6863                   && AOP_TYPE(left)==AOP_ACC)
6864                 {
6865                   if (offset)
6866                     emitcode("mov", "a,b");
6867                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6868                 }
6869               else if (AOP_TYPE(left)==AOP_ACC)
6870                 {
6871                   if (!offset)
6872                     {
6873                       bool pushedB = pushB ();
6874                       emitcode("mov", "b,a");
6875                       MOVA (aopGet (right, offset, FALSE, FALSE));
6876                       emitcode("anl", "a,b");
6877                       popB (pushedB);
6878                     }
6879                   else
6880                     {
6881                       MOVA (aopGet (right, offset, FALSE, FALSE));
6882                       emitcode("anl", "a,b");
6883                     }
6884                 }
6885               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6886                 {
6887                   MOVB (aopGet (left, offset, FALSE, FALSE));
6888                   MOVA (aopGet (right, offset, FALSE, FALSE));
6889                   emitcode ("anl", "a,b");
6890                 }
6891               else if (aopGetUsesAcc (left, offset))
6892                 {
6893                   MOVA (aopGet (left, offset, FALSE, FALSE));
6894                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6895                 }
6896               else
6897                 {
6898                   MOVA (aopGet (right, offset, FALSE, FALSE));
6899                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6900                 }
6901               aopPut (result, "a", offset);
6902             }
6903         }
6904     }
6905
6906 release:
6907   freeAsmop (result, NULL, ic, TRUE);
6908   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6909   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6910 }
6911
6912 /*-----------------------------------------------------------------*/
6913 /* genOr  - code for or                                            */
6914 /*-----------------------------------------------------------------*/
6915 static void
6916 genOr (iCode * ic, iCode * ifx)
6917 {
6918   operand *left, *right, *result;
6919   int size, offset = 0;
6920   unsigned long lit = 0L;
6921   int bytelit = 0;
6922
6923   D (emitcode (";", "genOr"));
6924
6925   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6926   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6927   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6928
6929 #ifdef DEBUG_TYPE
6930   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6931             AOP_TYPE (result),
6932             AOP_TYPE (left), AOP_TYPE (right));
6933   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6934             AOP_SIZE (result),
6935             AOP_SIZE (left), AOP_SIZE (right));
6936 #endif
6937
6938   /* if left is a literal & right is not then exchange them */
6939   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6940       AOP_NEEDSACC (left))
6941     {
6942       operand *tmp = right;
6943       right = left;
6944       left = tmp;
6945     }
6946
6947   /* if result = right then exchange them */
6948   if (sameRegs (AOP (result), AOP (right)))
6949     {
6950       operand *tmp = right;
6951       right = left;
6952       left = tmp;
6953     }
6954
6955   /* if right is bit then exchange them */
6956   if (AOP_TYPE (right) == AOP_CRY &&
6957       AOP_TYPE (left) != AOP_CRY)
6958     {
6959       operand *tmp = right;
6960       right = left;
6961       left = tmp;
6962     }
6963   if (AOP_TYPE (right) == AOP_LIT)
6964     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6965
6966   size = AOP_SIZE (result);
6967
6968   // if(bit | yy)
6969   // xx = bit | yy;
6970   if (AOP_TYPE (left) == AOP_CRY)
6971     {
6972       if (AOP_TYPE (right) == AOP_LIT)
6973         {
6974           // c = bit | literal;
6975           if (lit)
6976             {
6977               // lit != 0 => result = 1
6978               if (AOP_TYPE (result) == AOP_CRY)
6979                 {
6980                   if (size)
6981                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
6982                   else if (ifx)
6983                     continueIfTrue (ifx);
6984                   goto release;
6985                 }
6986               emitcode ("setb", "c");
6987             }
6988           else
6989             {
6990               // lit == 0 => result = left
6991               if (size && sameRegs (AOP (result), AOP (left)))
6992                 goto release;
6993               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6994             }
6995         }
6996       else
6997         {
6998           if (AOP_TYPE (right) == AOP_CRY)
6999             {
7000               // c = bit | bit;
7001               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7002               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7003             }
7004           else
7005             {
7006               // c = bit | val;
7007               symbol *tlbl = newiTempLabel (NULL);
7008               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7009                 emitcode ("setb", "c");
7010               emitcode ("jb", "%s,%05d$",
7011                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7012               toBoolean (right);
7013               emitcode ("jnz", "%05d$", tlbl->key + 100);
7014               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7015                 {
7016                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7017                   goto release;
7018                 }
7019               else
7020                 {
7021                   CLRC;
7022                   emitLabel (tlbl);
7023                 }
7024             }
7025         }
7026       // bit = c
7027       // val = c
7028       if (size)
7029         outBitC (result);
7030       // if(bit | ...)
7031       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7032         genIfxJump (ifx, "c", left, right, result);
7033       goto release;
7034     }
7035
7036   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7037   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7038   if ((AOP_TYPE (right) == AOP_LIT) &&
7039       (AOP_TYPE (result) == AOP_CRY) &&
7040       (AOP_TYPE (left) != AOP_CRY))
7041     {
7042       if (lit)
7043         {
7044           // result = 1
7045           if (size)
7046             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7047           else
7048             continueIfTrue (ifx);
7049           goto release;
7050         }
7051       else
7052         {
7053           // lit = 0, result = boolean(left)
7054           if (size)
7055             emitcode ("setb", "c");
7056           toBoolean (right);
7057           if (size)
7058             {
7059               symbol *tlbl = newiTempLabel (NULL);
7060               emitcode ("jnz", "%05d$", tlbl->key + 100);
7061               CLRC;
7062               emitLabel (tlbl);
7063             }
7064           else
7065             {
7066               genIfxJump (ifx, "a", left, right, result);
7067               goto release;
7068             }
7069         }
7070       outBitC (result);
7071       goto release;
7072     }
7073
7074   /* if left is same as result */
7075   if (sameRegs (AOP (result), AOP (left)))
7076     {
7077       for (; size--; offset++)
7078         {
7079           if (AOP_TYPE (right) == AOP_LIT)
7080             {
7081               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7082               if (bytelit == 0)
7083                 {
7084                   /* dummy read of volatile operand */
7085                   if (isOperandVolatile (left, FALSE))
7086                     MOVA (aopGet (left, offset, FALSE, FALSE));
7087                   else
7088                     continue;
7089                 }
7090               else if (bytelit == 0x0FF)
7091                 {
7092                   aopPut (result, "#0xFF", offset);
7093                 }
7094               else if (IS_AOP_PREG (left))
7095                 {
7096                   MOVA (aopGet (left, offset, FALSE, TRUE));
7097                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7098                   aopPut (result, "a", offset);
7099                 }
7100               else
7101                 {
7102                   emitcode ("orl", "%s,%s",
7103                             aopGet (left, offset, FALSE, TRUE),
7104                             aopGet (right, offset, FALSE, FALSE));
7105                 }
7106             }
7107           else
7108             {
7109               if (AOP_TYPE (left) == AOP_ACC)
7110                 {
7111                   if (offset)
7112                     emitcode("mov", "a,b");
7113                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7114                 }
7115               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7116                 {
7117                   MOVB (aopGet (left, offset, FALSE, FALSE));
7118                   MOVA (aopGet (right, offset, FALSE, FALSE));
7119                   emitcode ("orl", "a,b");
7120                   aopPut (result, "a", offset);
7121                 }
7122               else if (aopGetUsesAcc (left, offset))
7123                 {
7124                   MOVA (aopGet (left, offset, FALSE, FALSE));
7125                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7126                   aopPut (result, "a", offset);
7127                 }
7128               else
7129                 {
7130                   MOVA (aopGet (right, offset, FALSE, FALSE));
7131                   if (IS_AOP_PREG (left))
7132                     {
7133                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7134                       aopPut (result, "a", offset);
7135                     }
7136                   else
7137                     {
7138                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7139                     }
7140                 }
7141             }
7142         }
7143     }
7144   else
7145     {
7146       // left & result in different registers
7147       if (AOP_TYPE (result) == AOP_CRY)
7148         {
7149           // result = bit
7150           // if(size), result in bit
7151           // if(!size && ifx), conditional oper: if(left | right)
7152           symbol *tlbl = newiTempLabel (NULL);
7153           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7154           if (size)
7155             emitcode ("setb", "c");
7156           while (sizer--)
7157             {
7158               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7159                   && AOP_TYPE(left)==AOP_ACC)
7160                 {
7161                   if (offset)
7162                     emitcode("mov", "a,b");
7163                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7164                 }
7165               else if (AOP_TYPE(left)==AOP_ACC)
7166                 {
7167                   if (!offset)
7168                     {
7169                       bool pushedB = pushB ();
7170                       emitcode("mov", "b,a");
7171                       MOVA (aopGet (right, offset, FALSE, FALSE));
7172                       emitcode("orl", "a,b");
7173                       popB (pushedB);
7174                     }
7175                   else
7176                     {
7177                       MOVA (aopGet (right, offset, FALSE, FALSE));
7178                       emitcode("orl", "a,b");
7179                     }
7180                 }
7181               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7182                 {
7183                   MOVB (aopGet (left, offset, FALSE, FALSE));
7184                   MOVA (aopGet (right, offset, FALSE, FALSE));
7185                   emitcode ("orl", "a,b");
7186                 }
7187               else if (aopGetUsesAcc (left, offset))
7188                 {
7189                   MOVA (aopGet (left, offset, FALSE, FALSE));
7190                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7191                 }
7192               else
7193                 {
7194                   MOVA (aopGet (right, offset, FALSE, FALSE));
7195                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7196               }
7197
7198               emitcode ("jnz", "%05d$", tlbl->key + 100);
7199               offset++;
7200             }
7201           if (size)
7202             {
7203               CLRC;
7204               emitLabel (tlbl);
7205               outBitC (result);
7206             }
7207           else if (ifx)
7208             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7209           else
7210             emitLabel (tlbl);
7211         }
7212       else
7213         {
7214           for (; (size--); offset++)
7215             {
7216               // normal case
7217               // result = left | right
7218               if (AOP_TYPE (right) == AOP_LIT)
7219                 {
7220                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7221                   if (bytelit == 0)
7222                     {
7223                       aopPut (result,
7224                               aopGet (left, offset, FALSE, FALSE),
7225                               offset);
7226                       continue;
7227                     }
7228                   else if (bytelit == 0x0FF)
7229                     {
7230                       /* dummy read of volatile operand */
7231                       if (isOperandVolatile (left, FALSE))
7232                         MOVA (aopGet (left, offset, FALSE, FALSE));
7233                       aopPut (result, "#0xFF", offset);
7234                       continue;
7235                     }
7236                 }
7237               // faster than result <- left, orl result,right
7238               // and better if result is SFR
7239               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7240                   && AOP_TYPE(left)==AOP_ACC)
7241                 {
7242                   if (offset)
7243                     emitcode("mov", "a,b");
7244                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7245                 }
7246               else if (AOP_TYPE(left)==AOP_ACC)
7247                 {
7248                   if (!offset)
7249                     {
7250                       bool pushedB = pushB ();
7251                       emitcode("mov", "b,a");
7252                       MOVA (aopGet (right, offset, FALSE, FALSE));
7253                       emitcode("orl", "a,b");
7254                       popB (pushedB);
7255                     }
7256                   else
7257                     {
7258                       MOVA (aopGet (right, offset, FALSE, FALSE));
7259                       emitcode("orl", "a,b");
7260                     }
7261                 }
7262               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7263                 {
7264                   MOVB (aopGet (left, offset, FALSE, FALSE));
7265                   MOVA (aopGet (right, offset, FALSE, FALSE));
7266                   emitcode ("orl", "a,b");
7267                 }
7268               else if (aopGetUsesAcc (left, offset))
7269                 {
7270                   MOVA (aopGet (left, offset, FALSE, FALSE));
7271                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7272                 }
7273               else
7274                 {
7275                   MOVA (aopGet (right, offset, FALSE, FALSE));
7276                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7277                 }
7278               aopPut (result, "a", offset);
7279             }
7280         }
7281     }
7282
7283 release:
7284   freeAsmop (result, NULL, ic, TRUE);
7285   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7286   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7287 }
7288
7289 /*-----------------------------------------------------------------*/
7290 /* genXor - code for xclusive or                                   */
7291 /*-----------------------------------------------------------------*/
7292 static void
7293 genXor (iCode * ic, iCode * ifx)
7294 {
7295   operand *left, *right, *result;
7296   int size, offset = 0;
7297   unsigned long lit = 0L;
7298   int bytelit = 0;
7299
7300   D (emitcode (";", "genXor"));
7301
7302   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7303   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7304   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7305
7306 #ifdef DEBUG_TYPE
7307   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7308             AOP_TYPE (result),
7309             AOP_TYPE (left), AOP_TYPE (right));
7310   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7311             AOP_SIZE (result),
7312             AOP_SIZE (left), AOP_SIZE (right));
7313 #endif
7314
7315   /* if left is a literal & right is not ||
7316      if left needs acc & right does not */
7317   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7318       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7319     {
7320       operand *tmp = right;
7321       right = left;
7322       left = tmp;
7323     }
7324
7325   /* if result = right then exchange them */
7326   if (sameRegs (AOP (result), AOP (right)))
7327     {
7328       operand *tmp = right;
7329       right = left;
7330       left = tmp;
7331     }
7332
7333   /* if right is bit then exchange them */
7334   if (AOP_TYPE (right) == AOP_CRY &&
7335       AOP_TYPE (left) != AOP_CRY)
7336     {
7337       operand *tmp = right;
7338       right = left;
7339       left = tmp;
7340     }
7341   if (AOP_TYPE (right) == AOP_LIT)
7342     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7343
7344   size = AOP_SIZE (result);
7345
7346   // if(bit ^ yy)
7347   // xx = bit ^ yy;
7348   if (AOP_TYPE (left) == AOP_CRY)
7349     {
7350       if (AOP_TYPE (right) == AOP_LIT)
7351         {
7352           // c = bit & literal;
7353           if (lit >> 1)
7354             {
7355               // lit>>1  != 0 => result = 1
7356               if (AOP_TYPE (result) == AOP_CRY)
7357                 {
7358                   if (size)
7359                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7360                   else if (ifx)
7361                     continueIfTrue (ifx);
7362                   goto release;
7363                 }
7364               emitcode ("setb", "c");
7365             }
7366           else
7367             {
7368               // lit == (0 or 1)
7369               if (lit == 0)
7370                 {
7371                   // lit == 0, result = left
7372                   if (size && sameRegs (AOP (result), AOP (left)))
7373                     goto release;
7374                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7375                 }
7376               else
7377                 {
7378                   // lit == 1, result = not(left)
7379                   if (size && sameRegs (AOP (result), AOP (left)))
7380                     {
7381                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7382                       goto release;
7383                     }
7384                   else
7385                     {
7386                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7387                       emitcode ("cpl", "c");
7388                     }
7389                 }
7390             }
7391         }
7392       else
7393         {
7394           // right != literal
7395           symbol *tlbl = newiTempLabel (NULL);
7396           if (AOP_TYPE (right) == AOP_CRY)
7397             {
7398               // c = bit ^ bit;
7399               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7400             }
7401           else
7402             {
7403               int sizer = AOP_SIZE (right);
7404               // c = bit ^ val
7405               // if val>>1 != 0, result = 1
7406               emitcode ("setb", "c");
7407               while (sizer)
7408                 {
7409                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7410                   if (sizer == 1)
7411                     // test the msb of the lsb
7412                     emitcode ("anl", "a,#0xfe");
7413                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7414                   sizer--;
7415                 }
7416               // val = (0,1)
7417               emitcode ("rrc", "a");
7418             }
7419           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7420           emitcode ("cpl", "c");
7421           emitLabel (tlbl);
7422         }
7423       // bit = c
7424       // val = c
7425       if (size)
7426         outBitC (result);
7427       // if(bit | ...)
7428       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7429         genIfxJump (ifx, "c", left, right, result);
7430       goto release;
7431     }
7432
7433   /* if left is same as result */
7434   if (sameRegs (AOP (result), AOP (left)))
7435     {
7436       for (; size--; offset++)
7437         {
7438           if (AOP_TYPE (right) == AOP_LIT)
7439             {
7440               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7441               if (bytelit == 0)
7442                 {
7443                   /* dummy read of volatile operand */
7444                   if (isOperandVolatile (left, FALSE))
7445                     MOVA (aopGet (left, offset, FALSE, FALSE));
7446                   else
7447                     continue;
7448                 }
7449               else if (IS_AOP_PREG (left))
7450                 {
7451                   MOVA (aopGet (left, offset, FALSE, TRUE));
7452                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7453                   aopPut (result, "a", offset);
7454                 }
7455               else
7456                 {
7457                   emitcode ("xrl", "%s,%s",
7458                             aopGet (left, offset, FALSE, TRUE),
7459                             aopGet (right, offset, FALSE, FALSE));
7460                 }
7461             }
7462           else
7463             {
7464               if (AOP_TYPE (left) == AOP_ACC)
7465                 {
7466                   if (offset)
7467                     emitcode("mov", "a,b");
7468                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7469                 }
7470               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7471                 {
7472                   MOVB (aopGet (left, offset, FALSE, FALSE));
7473                   MOVA (aopGet (right, offset, FALSE, FALSE));
7474                   emitcode ("xrl", "a,b");
7475                   aopPut (result, "a", offset);
7476                 }
7477               else if (aopGetUsesAcc (left, offset))
7478                 {
7479                   MOVA (aopGet (left, offset, FALSE, FALSE));
7480                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7481                   aopPut (result, "a", offset);
7482                 }
7483               else
7484                 {
7485                   MOVA (aopGet (right, offset, FALSE, FALSE));
7486                   if (IS_AOP_PREG (left))
7487                     {
7488                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7489                       aopPut (result, "a", offset);
7490                     }
7491                   else
7492                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7493                 }
7494             }
7495         }
7496     }
7497   else
7498     {
7499       // left & result in different registers
7500       if (AOP_TYPE (result) == AOP_CRY)
7501         {
7502           // result = bit
7503           // if(size), result in bit
7504           // if(!size && ifx), conditional oper: if(left ^ right)
7505           symbol *tlbl = newiTempLabel (NULL);
7506           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7507
7508           if (size)
7509             emitcode ("setb", "c");
7510           while (sizer--)
7511             {
7512               if ((AOP_TYPE (right) == AOP_LIT) &&
7513                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7514                 {
7515                   MOVA (aopGet (left, offset, FALSE, FALSE));
7516                 }
7517               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7518                   && AOP_TYPE(left)==AOP_ACC)
7519                 {
7520                   if (offset)
7521                     emitcode("mov", "a,b");
7522                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7523                 }
7524               else if (AOP_TYPE(left)==AOP_ACC)
7525                 {
7526                   if (!offset)
7527                     {
7528                       bool pushedB = pushB ();
7529                       emitcode("mov", "b,a");
7530                       MOVA (aopGet (right, offset, FALSE, FALSE));
7531                       emitcode("xrl", "a,b");
7532                       popB (pushedB);
7533                     }
7534                   else
7535                     {
7536                       MOVA (aopGet (right, offset, FALSE, FALSE));
7537                       emitcode("xrl", "a,b");
7538                     }
7539                 }
7540               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7541                 {
7542                   MOVB (aopGet (left, offset, FALSE, FALSE));
7543                   MOVA (aopGet (right, offset, FALSE, FALSE));
7544                   emitcode ("xrl", "a,b");
7545                 }
7546               else if (aopGetUsesAcc (left, offset))
7547                 {
7548                   MOVA (aopGet (left, offset, FALSE, FALSE));
7549                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7550                 }
7551               else
7552                 {
7553                   MOVA (aopGet (right, offset, FALSE, FALSE));
7554                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7555                 }
7556
7557               emitcode ("jnz", "%05d$", tlbl->key + 100);
7558               offset++;
7559             }
7560           if (size)
7561             {
7562               CLRC;
7563               emitLabel (tlbl);
7564               outBitC (result);
7565             }
7566           else if (ifx)
7567             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7568         }
7569       else
7570         {
7571           for (; (size--); offset++)
7572             {
7573               // normal case
7574               // result = left ^ right
7575               if (AOP_TYPE (right) == AOP_LIT)
7576                 {
7577                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7578                   if (bytelit == 0)
7579                     {
7580                       aopPut (result,
7581                               aopGet (left, offset, FALSE, FALSE),
7582                               offset);
7583                       continue;
7584                     }
7585                 }
7586               // faster than result <- left, xrl result,right
7587               // and better if result is SFR
7588               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7589                   && AOP_TYPE(left)==AOP_ACC)
7590                 {
7591                   if (offset)
7592                     emitcode("mov", "a,b");
7593                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7594                 }
7595               else if (AOP_TYPE(left)==AOP_ACC)
7596                 {
7597                   if (!offset)
7598                     {
7599                       bool pushedB = pushB ();
7600                       emitcode("mov", "b,a");
7601                       MOVA (aopGet (right, offset, FALSE, FALSE));
7602                       emitcode("xrl", "a,b");
7603                       popB (pushedB);
7604                     }
7605                   else
7606                     {
7607                       MOVA (aopGet (right, offset, FALSE, FALSE));
7608                       emitcode("xrl", "a,b");
7609                     }
7610                 }
7611               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7612                 {
7613                   MOVB (aopGet (left, offset, FALSE, FALSE));
7614                   MOVA (aopGet (right, offset, FALSE, FALSE));
7615                   emitcode ("xrl", "a,b");
7616                 }
7617               else if (aopGetUsesAcc (left, offset))
7618                 {
7619                   MOVA (aopGet (left, offset, FALSE, FALSE));
7620                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7621                 }
7622               else
7623                 {
7624                   MOVA (aopGet (right, offset, FALSE, FALSE));
7625                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7626                 }
7627               aopPut (result, "a", offset);
7628             }
7629         }
7630     }
7631
7632 release:
7633   freeAsmop (result, NULL, ic, TRUE);
7634   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7635   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7636 }
7637
7638 /*-----------------------------------------------------------------*/
7639 /* genInline - write the inline code out                           */
7640 /*-----------------------------------------------------------------*/
7641 static void
7642 genInline (iCode * ic)
7643 {
7644   char *buffer, *bp, *bp1;
7645
7646   D (emitcode (";", "genInline"));
7647
7648   _G.inLine += (!options.asmpeep);
7649
7650   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
7651
7652   /* emit each line as a code */
7653   while (*bp)
7654     {
7655       if (*bp == '\n')
7656         {
7657           *bp++ = '\0';
7658           emitcode (bp1, "");
7659           bp1 = bp;
7660         }
7661       else
7662         {
7663           /* Add \n for labels, not dirs such as c:\mydir */
7664           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7665             {
7666               bp++;
7667               *bp = '\0';
7668               bp++;
7669               emitcode (bp1, "");
7670               bp1 = bp;
7671             }
7672           else
7673             bp++;
7674         }
7675     }
7676   if (bp1 != bp)
7677     emitcode (bp1, "");
7678   /*     emitcode("",buffer); */
7679   _G.inLine -= (!options.asmpeep);
7680 }
7681
7682 /*-----------------------------------------------------------------*/
7683 /* genRRC - rotate right with carry                                */
7684 /*-----------------------------------------------------------------*/
7685 static void
7686 genRRC (iCode * ic)
7687 {
7688   operand *left, *result;
7689   int size, offset;
7690   char *l;
7691
7692   D (emitcode (";", "genRRC"));
7693
7694   /* rotate right with carry */
7695   left = IC_LEFT (ic);
7696   result = IC_RESULT (ic);
7697   aopOp (left, ic, FALSE);
7698   aopOp (result, ic, FALSE);
7699
7700   /* move it to the result */
7701   size = AOP_SIZE (result);
7702   offset = size - 1;
7703   if (size == 1) { /* special case for 1 byte */
7704       l = aopGet (left, offset, FALSE, FALSE);
7705       MOVA (l);
7706       emitcode ("rr", "a");
7707       goto release;
7708   }
7709   /* no need to clear carry, bit7 will be written later */
7710   while (size--)
7711     {
7712       l = aopGet (left, offset, FALSE, FALSE);
7713       MOVA (l);
7714       emitcode ("rrc", "a");
7715       if (AOP_SIZE (result) > 1)
7716         aopPut (result, "a", offset--);
7717     }
7718   /* now we need to put the carry into the
7719      highest order byte of the result */
7720   if (AOP_SIZE (result) > 1)
7721     {
7722       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7723       MOVA (l);
7724     }
7725   emitcode ("mov", "acc.7,c");
7726  release:
7727   aopPut (result, "a", AOP_SIZE (result) - 1);
7728   freeAsmop (result, NULL, ic, TRUE);
7729   freeAsmop (left, NULL, ic, TRUE);
7730 }
7731
7732 /*-----------------------------------------------------------------*/
7733 /* genRLC - generate code for rotate left with carry               */
7734 /*-----------------------------------------------------------------*/
7735 static void
7736 genRLC (iCode * ic)
7737 {
7738   operand *left, *result;
7739   int size, offset;
7740   char *l;
7741
7742   D (emitcode (";", "genRLC"));
7743
7744   /* rotate right with carry */
7745   left = IC_LEFT (ic);
7746   result = IC_RESULT (ic);
7747   aopOp (left, ic, FALSE);
7748   aopOp (result, ic, FALSE);
7749
7750   /* move it to the result */
7751   size = AOP_SIZE (result);
7752   offset = 0;
7753   if (size--)
7754     {
7755       l = aopGet (left, offset, FALSE, FALSE);
7756       MOVA (l);
7757       if (size == 0) { /* special case for 1 byte */
7758               emitcode("rl","a");
7759               goto release;
7760       }
7761       emitcode("rlc","a"); /* bit0 will be written later */
7762       if (AOP_SIZE (result) > 1)
7763         {
7764           aopPut (result, "a", offset++);
7765         }
7766
7767       while (size--)
7768         {
7769           l = aopGet (left, offset, FALSE, FALSE);
7770           MOVA (l);
7771           emitcode ("rlc", "a");
7772           if (AOP_SIZE (result) > 1)
7773             aopPut (result, "a", offset++);
7774         }
7775     }
7776   /* now we need to put the carry into the
7777      highest order byte of the result */
7778   if (AOP_SIZE (result) > 1)
7779     {
7780       l = aopGet (result, 0, FALSE, FALSE);
7781       MOVA (l);
7782     }
7783   emitcode ("mov", "acc.0,c");
7784  release:
7785   aopPut (result, "a", 0);
7786   freeAsmop (result, NULL, ic, TRUE);
7787   freeAsmop (left, NULL, ic, TRUE);
7788 }
7789
7790 /*-----------------------------------------------------------------*/
7791 /* genGetHbit - generates code get highest order bit               */
7792 /*-----------------------------------------------------------------*/
7793 static void
7794 genGetHbit (iCode * ic)
7795 {
7796   operand *left, *result;
7797
7798   D (emitcode (";", "genGetHbit"));
7799
7800   left = IC_LEFT (ic);
7801   result = IC_RESULT (ic);
7802   aopOp (left, ic, FALSE);
7803   aopOp (result, ic, FALSE);
7804
7805   /* get the highest order byte into a */
7806   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7807   if (AOP_TYPE (result) == AOP_CRY)
7808     {
7809       emitcode ("rlc", "a");
7810       outBitC (result);
7811     }
7812   else
7813     {
7814       emitcode ("rl", "a");
7815       emitcode ("anl", "a,#0x01");
7816       outAcc (result);
7817     }
7818
7819   freeAsmop (result, NULL, ic, TRUE);
7820   freeAsmop (left, NULL, ic, TRUE);
7821 }
7822
7823 /*-----------------------------------------------------------------*/
7824 /* genGetAbit - generates code get a single bit                    */
7825 /*-----------------------------------------------------------------*/
7826 static void
7827 genGetAbit (iCode * ic)
7828 {
7829   operand *left, *right, *result;
7830   int shCount;
7831
7832   D (emitcode (";", "genGetAbit"));
7833
7834   left = IC_LEFT (ic);
7835   right = IC_RIGHT (ic);
7836   result = IC_RESULT (ic);
7837   aopOp (left, ic, FALSE);
7838   aopOp (right, ic, FALSE);
7839   aopOp (result, ic, FALSE);
7840
7841   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7842
7843   /* get the needed byte into a */
7844   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7845   shCount %= 8;
7846   if (AOP_TYPE (result) == AOP_CRY)
7847     {
7848       if ((shCount) == 7)
7849           emitcode ("rlc", "a");
7850       else if ((shCount) == 0)
7851           emitcode ("rrc", "a");
7852       else
7853           emitcode ("mov", "c,acc[%d]", shCount);
7854       outBitC (result);
7855     }
7856   else
7857     {
7858       switch (shCount)
7859         {
7860         case 2:
7861           emitcode ("rr", "a");
7862           //fallthrough
7863         case 1:
7864           emitcode ("rr", "a");
7865           //fallthrough
7866         case 0:
7867           emitcode ("anl", "a,#0x01");
7868           break;
7869         case 3:
7870         case 5:
7871           emitcode ("mov", "c,acc[%d]", shCount);
7872           emitcode ("clr", "a");
7873           emitcode ("rlc", "a");
7874           break;
7875         case 4:
7876           emitcode ("swap", "a");
7877           emitcode ("anl", "a,#0x01");
7878           break;
7879         case 6:
7880           emitcode ("rl", "a");
7881           //fallthrough
7882         case 7:
7883           emitcode ("rl", "a");
7884           emitcode ("anl", "a,#0x01");
7885           break;
7886         }
7887       outAcc (result);
7888     }
7889
7890   freeAsmop (result, NULL, ic, TRUE);
7891   freeAsmop (right, NULL, ic, TRUE);
7892   freeAsmop (left, NULL, ic, TRUE);
7893 }
7894
7895 /*-----------------------------------------------------------------*/
7896 /* genGetByte - generates code get a single byte                   */
7897 /*-----------------------------------------------------------------*/
7898 static void
7899 genGetByte (iCode * ic)
7900 {
7901   operand *left, *right, *result;
7902   int offset;
7903
7904   D (emitcode (";", "genGetByte"));
7905
7906   left = IC_LEFT (ic);
7907   right = IC_RIGHT (ic);
7908   result = IC_RESULT (ic);
7909   aopOp (left, ic, FALSE);
7910   aopOp (right, ic, FALSE);
7911   aopOp (result, ic, FALSE);
7912
7913   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7914   aopPut (result,
7915           aopGet (left, offset, FALSE, FALSE),
7916           0);
7917
7918   freeAsmop (result, NULL, ic, TRUE);
7919   freeAsmop (right, NULL, ic, TRUE);
7920   freeAsmop (left, NULL, ic, TRUE);
7921 }
7922
7923 /*-----------------------------------------------------------------*/
7924 /* genGetWord - generates code get two bytes                       */
7925 /*-----------------------------------------------------------------*/
7926 static void
7927 genGetWord (iCode * ic)
7928 {
7929   operand *left, *right, *result;
7930   int offset;
7931
7932   D (emitcode (";", "genGetWord"));
7933
7934   left = IC_LEFT (ic);
7935   right = IC_RIGHT (ic);
7936   result = IC_RESULT (ic);
7937   aopOp (left, ic, FALSE);
7938   aopOp (right, ic, FALSE);
7939   aopOp (result, ic, FALSE);
7940
7941   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7942   aopPut (result,
7943           aopGet (left, offset, FALSE, FALSE),
7944           0);
7945   aopPut (result,
7946           aopGet (left, offset+1, FALSE, FALSE),
7947           1);
7948
7949   freeAsmop (result, NULL, ic, TRUE);
7950   freeAsmop (right, NULL, ic, TRUE);
7951   freeAsmop (left, NULL, ic, TRUE);
7952 }
7953
7954 /*-----------------------------------------------------------------*/
7955 /* genSwap - generates code to swap nibbles or bytes               */
7956 /*-----------------------------------------------------------------*/
7957 static void
7958 genSwap (iCode * ic)
7959 {
7960   operand *left, *result;
7961
7962   D(emitcode (";     genSwap",""));
7963
7964   left = IC_LEFT (ic);
7965   result = IC_RESULT (ic);
7966   aopOp (left, ic, FALSE);
7967   aopOp (result, ic, FALSE);
7968
7969   switch (AOP_SIZE (left))
7970     {
7971     case 1: /* swap nibbles in byte */
7972       MOVA (aopGet (left, 0, FALSE, FALSE));
7973       emitcode ("swap", "a");
7974       aopPut (result, "a", 0);
7975       break;
7976     case 2: /* swap bytes in word */
7977       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7978         {
7979           MOVA (aopGet (left, 0, FALSE, FALSE));
7980           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
7981           aopPut (result, "a", 1);
7982         }
7983       else if (operandsEqu (left, result))
7984         {
7985           char * reg = "a";
7986           bool pushedB = FALSE, leftInB = FALSE;
7987
7988           MOVA (aopGet (left, 0, FALSE, FALSE));
7989           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
7990             {
7991               pushedB = pushB ();
7992               emitcode ("mov", "b,a");
7993               reg = "b";
7994               leftInB = TRUE;
7995             }
7996           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
7997           aopPut (result, reg, 1);
7998
7999           if (leftInB)
8000             popB (pushedB);
8001         }
8002       else
8003         {
8004           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8005           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8006         }
8007       break;
8008     default:
8009       wassertl(FALSE, "unsupported SWAP operand size");
8010     }
8011
8012   freeAsmop (result, NULL, ic, TRUE);
8013   freeAsmop (left, NULL, ic, TRUE);
8014 }
8015
8016 /*-----------------------------------------------------------------*/
8017 /* AccRol - rotate left accumulator by known count                 */
8018 /*-----------------------------------------------------------------*/
8019 static void
8020 AccRol (int shCount)
8021 {
8022   shCount &= 0x0007;            // shCount : 0..7
8023
8024   switch (shCount)
8025     {
8026     case 0:
8027       break;
8028     case 1:
8029       emitcode ("rl", "a");
8030       break;
8031     case 2:
8032       emitcode ("rl", "a");
8033       emitcode ("rl", "a");
8034       break;
8035     case 3:
8036       emitcode ("swap", "a");
8037       emitcode ("rr", "a");
8038       break;
8039     case 4:
8040       emitcode ("swap", "a");
8041       break;
8042     case 5:
8043       emitcode ("swap", "a");
8044       emitcode ("rl", "a");
8045       break;
8046     case 6:
8047       emitcode ("rr", "a");
8048       emitcode ("rr", "a");
8049       break;
8050     case 7:
8051       emitcode ("rr", "a");
8052       break;
8053     }
8054 }
8055
8056 /*-----------------------------------------------------------------*/
8057 /* AccLsh - left shift accumulator by known count                  */
8058 /*-----------------------------------------------------------------*/
8059 static void
8060 AccLsh (int shCount)
8061 {
8062   if (shCount != 0)
8063     {
8064       if (shCount == 1)
8065         emitcode ("add", "a,acc");
8066       else if (shCount == 2)
8067         {
8068           emitcode ("add", "a,acc");
8069           emitcode ("add", "a,acc");
8070         }
8071       else
8072         {
8073           /* rotate left accumulator */
8074           AccRol (shCount);
8075           /* and kill the lower order bits */
8076           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8077         }
8078     }
8079 }
8080
8081 /*-----------------------------------------------------------------*/
8082 /* AccRsh - right shift accumulator by known count                 */
8083 /*-----------------------------------------------------------------*/
8084 static void
8085 AccRsh (int shCount)
8086 {
8087   if (shCount != 0)
8088     {
8089       if (shCount == 1)
8090         {
8091           CLRC;
8092           emitcode ("rrc", "a");
8093         }
8094       else
8095         {
8096           /* rotate right accumulator */
8097           AccRol (8 - shCount);
8098           /* and kill the higher order bits */
8099           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8100         }
8101     }
8102 }
8103
8104 /*-----------------------------------------------------------------*/
8105 /* AccSRsh - signed right shift accumulator by known count                 */
8106 /*-----------------------------------------------------------------*/
8107 static void
8108 AccSRsh (int shCount)
8109 {
8110   symbol *tlbl;
8111   if (shCount != 0)
8112     {
8113       if (shCount == 1)
8114         {
8115           emitcode ("mov", "c,acc.7");
8116           emitcode ("rrc", "a");
8117         }
8118       else if (shCount == 2)
8119         {
8120           emitcode ("mov", "c,acc.7");
8121           emitcode ("rrc", "a");
8122           emitcode ("mov", "c,acc.7");
8123           emitcode ("rrc", "a");
8124         }
8125       else
8126         {
8127           tlbl = newiTempLabel (NULL);
8128           /* rotate right accumulator */
8129           AccRol (8 - shCount);
8130           /* and kill the higher order bits */
8131           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8132           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8133           emitcode ("orl", "a,#0x%02x",
8134                     (unsigned char) ~SRMask[shCount]);
8135           emitLabel (tlbl);
8136         }
8137     }
8138 }
8139
8140 /*-----------------------------------------------------------------*/
8141 /* shiftR1Left2Result - shift right one byte from left to result   */
8142 /*-----------------------------------------------------------------*/
8143 static void
8144 shiftR1Left2Result (operand * left, int offl,
8145                     operand * result, int offr,
8146                     int shCount, int sign)
8147 {
8148   MOVA (aopGet (left, offl, FALSE, FALSE));
8149   /* shift right accumulator */
8150   if (sign)
8151     AccSRsh (shCount);
8152   else
8153     AccRsh (shCount);
8154   aopPut (result, "a", offr);
8155 }
8156
8157 /*-----------------------------------------------------------------*/
8158 /* shiftL1Left2Result - shift left one byte from left to result    */
8159 /*-----------------------------------------------------------------*/
8160 static void
8161 shiftL1Left2Result (operand * left, int offl,
8162                     operand * result, int offr, int shCount)
8163 {
8164   char *l;
8165   l = aopGet (left, offl, FALSE, FALSE);
8166   MOVA (l);
8167   /* shift left accumulator */
8168   AccLsh (shCount);
8169   aopPut (result, "a", offr);
8170 }
8171
8172 /*-----------------------------------------------------------------*/
8173 /* movLeft2Result - move byte from left to result                  */
8174 /*-----------------------------------------------------------------*/
8175 static void
8176 movLeft2Result (operand * left, int offl,
8177                 operand * result, int offr, int sign)
8178 {
8179   char *l;
8180   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8181     {
8182       l = aopGet (left, offl, FALSE, FALSE);
8183
8184       if (*l == '@' && (IS_AOP_PREG (result)))
8185         {
8186           emitcode ("mov", "a,%s", l);
8187           aopPut (result, "a", offr);
8188         }
8189       else
8190         {
8191           if (!sign)
8192             {
8193               aopPut (result, l, offr);
8194             }
8195           else
8196             {
8197               /* MSB sign in acc.7 ! */
8198               if (getDataSize (left) == offl + 1)
8199                 {
8200                   MOVA (l);
8201                   aopPut (result, "a", offr);
8202                 }
8203             }
8204         }
8205     }
8206 }
8207
8208 /*-----------------------------------------------------------------*/
8209 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8210 /*-----------------------------------------------------------------*/
8211 static void
8212 AccAXRrl1 (char *x)
8213 {
8214   emitcode ("rrc", "a");
8215   emitcode ("xch", "a,%s", x);
8216   emitcode ("rrc", "a");
8217   emitcode ("xch", "a,%s", x);
8218 }
8219
8220 /*-----------------------------------------------------------------*/
8221 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8222 /*-----------------------------------------------------------------*/
8223 static void
8224 AccAXLrl1 (char *x)
8225 {
8226   emitcode ("xch", "a,%s", x);
8227   emitcode ("rlc", "a");
8228   emitcode ("xch", "a,%s", x);
8229   emitcode ("rlc", "a");
8230 }
8231
8232 /*-----------------------------------------------------------------*/
8233 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8234 /*-----------------------------------------------------------------*/
8235 static void
8236 AccAXLsh1 (char *x)
8237 {
8238   emitcode ("xch", "a,%s", x);
8239   emitcode ("add", "a,acc");
8240   emitcode ("xch", "a,%s", x);
8241   emitcode ("rlc", "a");
8242 }
8243
8244 /*-----------------------------------------------------------------*/
8245 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8246 /*-----------------------------------------------------------------*/
8247 static void
8248 AccAXLsh (char *x, int shCount)
8249 {
8250   switch (shCount)
8251     {
8252     case 0:
8253       break;
8254     case 1:
8255       AccAXLsh1 (x);
8256       break;
8257     case 2:
8258       AccAXLsh1 (x);
8259       AccAXLsh1 (x);
8260       break;
8261     case 3:
8262     case 4:
8263     case 5:                     // AAAAABBB:CCCCCDDD
8264
8265       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8266
8267       emitcode ("anl", "a,#0x%02x",
8268                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8269
8270       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8271
8272       AccRol (shCount);         // DDDCCCCC:BBB00000
8273
8274       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8275
8276       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8277
8278       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8279
8280       emitcode ("anl", "a,#0x%02x",
8281                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8282
8283       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8284
8285       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8286
8287       break;
8288     case 6:                     // AAAAAABB:CCCCCCDD
8289       emitcode ("anl", "a,#0x%02x",
8290                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8291       emitcode ("mov", "c,acc.0");      // c = B
8292       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8293 #if 0 // REMOVE ME
8294       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8295       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8296 #else
8297       emitcode("rrc","a");
8298       emitcode("xch","a,%s", x);
8299       emitcode("rrc","a");
8300       emitcode("mov","c,acc.0"); //<< get correct bit
8301       emitcode("xch","a,%s", x);
8302
8303       emitcode("rrc","a");
8304       emitcode("xch","a,%s", x);
8305       emitcode("rrc","a");
8306       emitcode("xch","a,%s", x);
8307 #endif
8308       break;
8309     case 7:                     // a:x <<= 7
8310
8311       emitcode ("anl", "a,#0x%02x",
8312                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8313
8314       emitcode ("mov", "c,acc.0");      // c = B
8315
8316       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8317
8318       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8319
8320       break;
8321     default:
8322       break;
8323     }
8324 }
8325
8326 /*-----------------------------------------------------------------*/
8327 /* AccAXRsh - right shift a:x known count (0..7)                   */
8328 /*-----------------------------------------------------------------*/
8329 static void
8330 AccAXRsh (char *x, int shCount)
8331 {
8332   switch (shCount)
8333     {
8334     case 0:
8335       break;
8336     case 1:
8337       CLRC;
8338       AccAXRrl1 (x);            // 0->a:x
8339
8340       break;
8341     case 2:
8342       CLRC;
8343       AccAXRrl1 (x);            // 0->a:x
8344
8345       CLRC;
8346       AccAXRrl1 (x);            // 0->a:x
8347
8348       break;
8349     case 3:
8350     case 4:
8351     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8352
8353       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8354
8355       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8356
8357       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8358
8359       emitcode ("anl", "a,#0x%02x",
8360                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8361
8362       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8363
8364       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8365
8366       emitcode ("anl", "a,#0x%02x",
8367                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8368
8369       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8370
8371       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8372
8373       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8374
8375       break;
8376     case 6:                     // AABBBBBB:CCDDDDDD
8377
8378       emitcode ("mov", "c,acc.7");
8379       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8380
8381       emitcode ("mov", "c,acc.7");
8382       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8383
8384       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8385
8386       emitcode ("anl", "a,#0x%02x",
8387                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8388
8389       break;
8390     case 7:                     // ABBBBBBB:CDDDDDDD
8391
8392       emitcode ("mov", "c,acc.7");      // c = A
8393
8394       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8395
8396       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8397
8398       emitcode ("anl", "a,#0x%02x",
8399                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8400
8401       break;
8402     default:
8403       break;
8404     }
8405 }
8406
8407 /*-----------------------------------------------------------------*/
8408 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8409 /*-----------------------------------------------------------------*/
8410 static void
8411 AccAXRshS (char *x, int shCount)
8412 {
8413   symbol *tlbl;
8414   switch (shCount)
8415     {
8416     case 0:
8417       break;
8418     case 1:
8419       emitcode ("mov", "c,acc.7");
8420       AccAXRrl1 (x);            // s->a:x
8421
8422       break;
8423     case 2:
8424       emitcode ("mov", "c,acc.7");
8425       AccAXRrl1 (x);            // s->a:x
8426
8427       emitcode ("mov", "c,acc.7");
8428       AccAXRrl1 (x);            // s->a:x
8429
8430       break;
8431     case 3:
8432     case 4:
8433     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8434
8435       tlbl = newiTempLabel (NULL);
8436       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8437
8438       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8439
8440       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8441
8442       emitcode ("anl", "a,#0x%02x",
8443                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8444
8445       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8446
8447       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8448
8449       emitcode ("anl", "a,#0x%02x",
8450                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8451
8452       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8453
8454       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8455
8456       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8457
8458       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8459       emitcode ("orl", "a,#0x%02x",
8460                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8461
8462       emitLabel (tlbl);
8463       break;                    // SSSSAAAA:BBBCCCCC
8464
8465     case 6:                     // AABBBBBB:CCDDDDDD
8466
8467       tlbl = newiTempLabel (NULL);
8468       emitcode ("mov", "c,acc.7");
8469       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8470
8471       emitcode ("mov", "c,acc.7");
8472       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8473
8474       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8475
8476       emitcode ("anl", "a,#0x%02x",
8477                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8478
8479       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8480       emitcode ("orl", "a,#0x%02x",
8481                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8482
8483       emitLabel (tlbl);
8484       break;
8485     case 7:                     // ABBBBBBB:CDDDDDDD
8486
8487       tlbl = newiTempLabel (NULL);
8488       emitcode ("mov", "c,acc.7");      // c = A
8489
8490       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8491
8492       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8493
8494       emitcode ("anl", "a,#0x%02x",
8495                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8496
8497       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8498       emitcode ("orl", "a,#0x%02x",
8499                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8500
8501       emitLabel (tlbl);
8502       break;
8503     default:
8504       break;
8505     }
8506 }
8507
8508 /*-----------------------------------------------------------------*/
8509 /* shiftL2Left2Result - shift left two bytes from left to result   */
8510 /*-----------------------------------------------------------------*/
8511 static void
8512 shiftL2Left2Result (operand * left, int offl,
8513                     operand * result, int offr, int shCount)
8514 {
8515   char * x;
8516   bool pushedB = FALSE;
8517   bool usedB = FALSE;
8518
8519   if (sameRegs (AOP (result), AOP (left)) &&
8520       ((offl + MSB16) == offr))
8521     {
8522       /* don't crash result[offr] */
8523       MOVA (aopGet (left, offl, FALSE, FALSE));
8524       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8525       usedB = !strncmp(x, "b", 1);
8526     }
8527   else if (aopGetUsesAcc (result, offr))
8528     {
8529       movLeft2Result (left, offl, result, offr, 0);
8530       pushedB = pushB ();
8531       usedB = TRUE;
8532       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8533       MOVA (aopGet (result, offr, FALSE, FALSE));
8534       emitcode ("xch", "a,b");
8535       x = "b";
8536     }
8537   else
8538     {
8539       movLeft2Result (left, offl, result, offr, 0);
8540       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8541       x = aopGet (result, offr, FALSE, FALSE);
8542     }
8543   /* ax << shCount (x = lsb(result)) */
8544   AccAXLsh (x, shCount);
8545   if (usedB)
8546     {
8547       emitcode ("xch", "a,b");
8548       aopPut (result, "a", offr);
8549       aopPut (result, "b", offr + MSB16);
8550       popB (pushedB);
8551     }
8552   else
8553     {
8554       aopPut (result, "a", offr + MSB16);
8555     }
8556 }
8557
8558
8559 /*-----------------------------------------------------------------*/
8560 /* shiftR2Left2Result - shift right two bytes from left to result  */
8561 /*-----------------------------------------------------------------*/
8562 static void
8563 shiftR2Left2Result (operand * left, int offl,
8564                     operand * result, int offr,
8565                     int shCount, int sign)
8566 {
8567   char * x;
8568   bool pushedB = FALSE;
8569   bool usedB = FALSE;
8570
8571   if (sameRegs (AOP (result), AOP (left)) &&
8572       ((offl + MSB16) == offr))
8573     {
8574       /* don't crash result[offr] */
8575       MOVA (aopGet (left, offl, FALSE, FALSE));
8576       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8577       usedB = !strncmp(x, "b", 1);
8578     }
8579   else if (aopGetUsesAcc (result, offr))
8580     {
8581       movLeft2Result (left, offl, result, offr, 0);
8582       pushedB = pushB ();
8583       usedB = TRUE;
8584       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8585       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8586       x = "b";
8587     }
8588   else
8589     {
8590       movLeft2Result (left, offl, result, offr, 0);
8591       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8592       x = aopGet (result, offr, FALSE, FALSE);
8593     }
8594   /* a:x >> shCount (x = lsb(result)) */
8595   if (sign)
8596     AccAXRshS (x, shCount);
8597   else
8598     AccAXRsh (x, shCount);
8599   if (usedB)
8600     {
8601       emitcode ("xch", "a,b");
8602       aopPut (result, "a", offr);
8603       emitcode ("xch", "a,b");
8604       popB (pushedB);
8605     }
8606   if (getDataSize (result) > 1)
8607     aopPut (result, "a", offr + MSB16);
8608 }
8609
8610 /*-----------------------------------------------------------------*/
8611 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8612 /*-----------------------------------------------------------------*/
8613 static void
8614 shiftLLeftOrResult (operand * left, int offl,
8615                     operand * result, int offr, int shCount)
8616 {
8617   MOVA (aopGet (left, offl, FALSE, FALSE));
8618   /* shift left accumulator */
8619   AccLsh (shCount);
8620   /* or with result */
8621   if (aopGetUsesAcc (result, offr))
8622     {
8623       emitcode ("xch", "a,b");
8624       MOVA (aopGet (result, offr, FALSE, FALSE));
8625       emitcode ("orl", "a,b");
8626     }
8627   else
8628     {
8629       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8630     }
8631   /* back to result */
8632   aopPut (result, "a", offr);
8633 }
8634
8635 /*-----------------------------------------------------------------*/
8636 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8637 /*-----------------------------------------------------------------*/
8638 static void
8639 shiftRLeftOrResult (operand * left, int offl,
8640                     operand * result, int offr, int shCount)
8641 {
8642   MOVA (aopGet (left, offl, FALSE, FALSE));
8643   /* shift right accumulator */
8644   AccRsh (shCount);
8645   /* or with result */
8646   if (aopGetUsesAcc(result, offr))
8647     {
8648       emitcode ("xch", "a,b");
8649       MOVA (aopGet (result, offr, FALSE, FALSE));
8650       emitcode ("orl", "a,b");
8651     }
8652   else
8653     {
8654       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8655     }
8656   /* back to result */
8657   aopPut (result, "a", offr);
8658 }
8659
8660 /*-----------------------------------------------------------------*/
8661 /* genlshOne - left shift a one byte quantity by known count       */
8662 /*-----------------------------------------------------------------*/
8663 static void
8664 genlshOne (operand * result, operand * left, int shCount)
8665 {
8666   D (emitcode (";", "genlshOne"));
8667
8668   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8669 }
8670
8671 /*-----------------------------------------------------------------*/
8672 /* genlshTwo - left shift two bytes by known amount != 0           */
8673 /*-----------------------------------------------------------------*/
8674 static void
8675 genlshTwo (operand * result, operand * left, int shCount)
8676 {
8677   int size;
8678
8679   D (emitcode (";", "genlshTwo"));
8680
8681   size = getDataSize (result);
8682
8683   /* if shCount >= 8 */
8684   if (shCount >= 8)
8685     {
8686       shCount -= 8;
8687
8688       if (size > 1)
8689         {
8690           if (shCount)
8691             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8692           else
8693             movLeft2Result (left, LSB, result, MSB16, 0);
8694         }
8695       aopPut (result, zero, LSB);
8696     }
8697
8698   /*  1 <= shCount <= 7 */
8699   else
8700     {
8701       if (size == 1)
8702         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8703       else
8704         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8705     }
8706 }
8707
8708 /*-----------------------------------------------------------------*/
8709 /* shiftLLong - shift left one long from left to result            */
8710 /* offl = LSB or MSB16                                             */
8711 /*-----------------------------------------------------------------*/
8712 static void
8713 shiftLLong (operand * left, operand * result, int offr)
8714 {
8715   char *l;
8716   int size = AOP_SIZE (result);
8717
8718   if (size >= LSB + offr)
8719     {
8720       l = aopGet (left, LSB, FALSE, FALSE);
8721       MOVA (l);
8722       emitcode ("add", "a,acc");
8723       if (sameRegs (AOP (left), AOP (result)) &&
8724           size >= MSB16 + offr && offr != LSB)
8725         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8726       else
8727         aopPut (result, "a", LSB + offr);
8728     }
8729
8730   if (size >= MSB16 + offr)
8731     {
8732       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8733         {
8734           l = aopGet (left, MSB16, FALSE, FALSE);
8735           MOVA (l);
8736         }
8737       emitcode ("rlc", "a");
8738       if (sameRegs (AOP (left), AOP (result)) &&
8739           size >= MSB24 + offr && offr != LSB)
8740         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8741       else
8742         aopPut (result, "a", MSB16 + offr);
8743     }
8744
8745   if (size >= MSB24 + offr)
8746     {
8747       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8748         {
8749           l = aopGet (left, MSB24, FALSE, FALSE);
8750           MOVA (l);
8751         }
8752       emitcode ("rlc", "a");
8753       if (sameRegs (AOP (left), AOP (result)) &&
8754           size >= MSB32 + offr && offr != LSB)
8755         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8756       else
8757         aopPut (result, "a", MSB24 + offr);
8758     }
8759
8760   if (size > MSB32 + offr)
8761     {
8762       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8763         {
8764           l = aopGet (left, MSB32, FALSE, FALSE);
8765           MOVA (l);
8766         }
8767       emitcode ("rlc", "a");
8768       aopPut (result, "a", MSB32 + offr);
8769     }
8770   if (offr != LSB)
8771     aopPut (result, zero, LSB);
8772 }
8773
8774 /*-----------------------------------------------------------------*/
8775 /* genlshFour - shift four byte by a known amount != 0             */
8776 /*-----------------------------------------------------------------*/
8777 static void
8778 genlshFour (operand * result, operand * left, int shCount)
8779 {
8780   int size;
8781
8782   D (emitcode (";", "genlshFour"));
8783
8784   size = AOP_SIZE (result);
8785
8786   /* if shifting more that 3 bytes */
8787   if (shCount >= 24)
8788     {
8789       shCount -= 24;
8790       if (shCount)
8791         /* lowest order of left goes to the highest
8792            order of the destination */
8793         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8794       else
8795         movLeft2Result (left, LSB, result, MSB32, 0);
8796       aopPut (result, zero, LSB);
8797       aopPut (result, zero, MSB16);
8798       aopPut (result, zero, MSB24);
8799       return;
8800     }
8801
8802   /* more than two bytes */
8803   else if (shCount >= 16)
8804     {
8805       /* lower order two bytes goes to higher order two bytes */
8806       shCount -= 16;
8807       /* if some more remaining */
8808       if (shCount)
8809         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8810       else
8811         {
8812           movLeft2Result (left, MSB16, result, MSB32, 0);
8813           movLeft2Result (left, LSB, result, MSB24, 0);
8814         }
8815       aopPut (result, zero, MSB16);
8816       aopPut (result, zero, LSB);
8817       return;
8818     }
8819
8820   /* if more than 1 byte */
8821   else if (shCount >= 8)
8822     {
8823       /* lower order three bytes goes to higher order  three bytes */
8824       shCount -= 8;
8825       if (size == 2)
8826         {
8827           if (shCount)
8828             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8829           else
8830             movLeft2Result (left, LSB, result, MSB16, 0);
8831         }
8832       else
8833         {                       /* size = 4 */
8834           if (shCount == 0)
8835             {
8836               movLeft2Result (left, MSB24, result, MSB32, 0);
8837               movLeft2Result (left, MSB16, result, MSB24, 0);
8838               movLeft2Result (left, LSB, result, MSB16, 0);
8839               aopPut (result, zero, LSB);
8840             }
8841           else if (shCount == 1)
8842             shiftLLong (left, result, MSB16);
8843           else
8844             {
8845               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8846               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8847               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8848               aopPut (result, zero, LSB);
8849             }
8850         }
8851     }
8852
8853   /* 1 <= shCount <= 7 */
8854   else if (shCount <= 2)
8855     {
8856       shiftLLong (left, result, LSB);
8857       if (shCount == 2)
8858         shiftLLong (result, result, LSB);
8859     }
8860   /* 3 <= shCount <= 7, optimize */
8861   else
8862     {
8863       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8864       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8865       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8866     }
8867 }
8868
8869 /*-----------------------------------------------------------------*/
8870 /* genLeftShiftLiteral - left shifting by known count              */
8871 /*-----------------------------------------------------------------*/
8872 static void
8873 genLeftShiftLiteral (operand * left,
8874                      operand * right,
8875                      operand * result,
8876                      iCode * ic)
8877 {
8878   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8879   int size;
8880
8881   D (emitcode (";", "genLeftShiftLiteral"));
8882
8883   freeAsmop (right, NULL, ic, TRUE);
8884
8885   aopOp (left, ic, FALSE);
8886   aopOp (result, ic, FALSE);
8887
8888   size = getSize (operandType (result));
8889
8890 #if VIEW_SIZE
8891   emitcode ("; shift left ", "result %d, left %d", size,
8892             AOP_SIZE (left));
8893 #endif
8894
8895   /* I suppose that the left size >= result size */
8896   if (shCount == 0)
8897     {
8898       while (size--)
8899         {
8900           movLeft2Result (left, size, result, size, 0);
8901         }
8902     }
8903   else if (shCount >= (size * 8))
8904     {
8905       while (size--)
8906         {
8907           aopPut (result, zero, size);
8908         }
8909     }
8910   else
8911     {
8912       switch (size)
8913         {
8914         case 1:
8915           genlshOne (result, left, shCount);
8916           break;
8917
8918         case 2:
8919           genlshTwo (result, left, shCount);
8920           break;
8921
8922         case 4:
8923           genlshFour (result, left, shCount);
8924           break;
8925         default:
8926           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8927                   "*** ack! mystery literal shift!\n");
8928           break;
8929         }
8930     }
8931   freeAsmop (result, NULL, ic, TRUE);
8932   freeAsmop (left, NULL, ic, TRUE);
8933 }
8934
8935 /*-----------------------------------------------------------------*/
8936 /* genLeftShift - generates code for left shifting                 */
8937 /*-----------------------------------------------------------------*/
8938 static void
8939 genLeftShift (iCode * ic)
8940 {
8941   operand *left, *right, *result;
8942   int size, offset;
8943   char *l;
8944   symbol *tlbl, *tlbl1;
8945   bool pushedB;
8946
8947   D (emitcode (";", "genLeftShift"));
8948
8949   right = IC_RIGHT (ic);
8950   left = IC_LEFT (ic);
8951   result = IC_RESULT (ic);
8952
8953   aopOp (right, ic, FALSE);
8954
8955   /* if the shift count is known then do it
8956      as efficiently as possible */
8957   if (AOP_TYPE (right) == AOP_LIT)
8958     {
8959       genLeftShiftLiteral (left, right, result, ic);
8960       return;
8961     }
8962
8963   /* shift count is unknown then we have to form
8964      a loop get the loop count in B : Note: we take
8965      only the lower order byte since shifting
8966      more that 32 bits make no sense anyway, ( the
8967      largest size of an object can be only 32 bits ) */
8968
8969   pushedB = pushB ();
8970   MOVB (aopGet (right, 0, FALSE, FALSE));
8971   emitcode ("inc", "b");
8972   freeAsmop (right, NULL, ic, TRUE);
8973   aopOp (left, ic, FALSE);
8974   aopOp (result, ic, FALSE);
8975
8976   /* now move the left to the result if they are not the same */
8977   if (!sameRegs (AOP (left), AOP (result)) &&
8978       AOP_SIZE (result) > 1)
8979     {
8980
8981       size = AOP_SIZE (result);
8982       offset = 0;
8983       while (size--)
8984         {
8985           l = aopGet (left, offset, FALSE, TRUE);
8986           if (*l == '@' && (IS_AOP_PREG (result)))
8987             {
8988
8989               emitcode ("mov", "a,%s", l);
8990               aopPut (result, "a", offset);
8991             }
8992           else
8993             aopPut (result, l, offset);
8994           offset++;
8995         }
8996     }
8997
8998   tlbl = newiTempLabel (NULL);
8999   size = AOP_SIZE (result);
9000   offset = 0;
9001   tlbl1 = newiTempLabel (NULL);
9002
9003   /* if it is only one byte then */
9004   if (size == 1)
9005     {
9006       symbol *tlbl1 = newiTempLabel (NULL);
9007
9008       l = aopGet (left, 0, FALSE, FALSE);
9009       MOVA (l);
9010       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9011       emitLabel (tlbl);
9012       emitcode ("add", "a,acc");
9013       emitLabel (tlbl1);
9014       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9015       popB (pushedB);
9016       aopPut (result, "a", 0);
9017       goto release;
9018     }
9019
9020   reAdjustPreg (AOP (result));
9021
9022   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9023   emitLabel (tlbl);
9024   l = aopGet (result, offset, FALSE, FALSE);
9025   MOVA (l);
9026   emitcode ("add", "a,acc");
9027   aopPut (result, "a", offset++);
9028   while (--size)
9029     {
9030       l = aopGet (result, offset, FALSE, FALSE);
9031       MOVA (l);
9032       emitcode ("rlc", "a");
9033       aopPut (result, "a", offset++);
9034     }
9035   reAdjustPreg (AOP (result));
9036
9037   emitLabel (tlbl1);
9038   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9039   popB (pushedB);
9040 release:
9041   freeAsmop (result, NULL, ic, TRUE);
9042   freeAsmop (left, NULL, ic, TRUE);
9043 }
9044
9045 /*-----------------------------------------------------------------*/
9046 /* genrshOne - right shift a one byte quantity by known count      */
9047 /*-----------------------------------------------------------------*/
9048 static void
9049 genrshOne (operand * result, operand * left,
9050            int shCount, int sign)
9051 {
9052   D (emitcode (";", "genrshOne"));
9053
9054   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9055 }
9056
9057 /*-----------------------------------------------------------------*/
9058 /* genrshTwo - right shift two bytes by known amount != 0          */
9059 /*-----------------------------------------------------------------*/
9060 static void
9061 genrshTwo (operand * result, operand * left,
9062            int shCount, int sign)
9063 {
9064   D (emitcode (";", "genrshTwo"));
9065
9066   /* if shCount >= 8 */
9067   if (shCount >= 8)
9068     {
9069       shCount -= 8;
9070       if (shCount)
9071         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9072       else
9073         movLeft2Result (left, MSB16, result, LSB, sign);
9074       addSign (result, MSB16, sign);
9075     }
9076
9077   /*  1 <= shCount <= 7 */
9078   else
9079     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9080 }
9081
9082 /*-----------------------------------------------------------------*/
9083 /* shiftRLong - shift right one long from left to result           */
9084 /* offl = LSB or MSB16                                             */
9085 /*-----------------------------------------------------------------*/
9086 static void
9087 shiftRLong (operand * left, int offl,
9088             operand * result, int sign)
9089 {
9090   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9091
9092   if (overlapping && offl>1)
9093     {
9094       // we are in big trouble, but this shouldn't happen
9095       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9096     }
9097
9098   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9099
9100   if (offl==MSB16)
9101     {
9102       // shift is > 8
9103       if (sign)
9104         {
9105           emitcode ("rlc", "a");
9106           emitcode ("subb", "a,acc");
9107           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9108             {
9109               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9110             }
9111           else
9112             {
9113               aopPut (result, "a", MSB32);
9114               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9115             }
9116         }
9117       else
9118         {
9119           if (aopPutUsesAcc (result, zero, MSB32))
9120             {
9121               emitcode("xch", "a,b");
9122               aopPut (result, zero, MSB32);
9123               emitcode("xch", "a,b");
9124             }
9125           else
9126             {
9127               aopPut (result, zero, MSB32);
9128             }
9129         }
9130     }
9131
9132   if (!sign)
9133     {
9134       emitcode ("clr", "c");
9135     }
9136   else
9137     {
9138       emitcode ("mov", "c,acc.7");
9139     }
9140
9141   emitcode ("rrc", "a");
9142
9143   if (overlapping && offl==MSB16 &&
9144       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9145     {
9146       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9147     }
9148   else
9149     {
9150       aopPut (result, "a", MSB32 - offl);
9151       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9152     }
9153
9154   emitcode ("rrc", "a");
9155   if (overlapping && offl==MSB16 &&
9156       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9157     {
9158       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9159     }
9160   else
9161     {
9162       aopPut (result, "a", MSB24 - offl);
9163       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9164     }
9165
9166   emitcode ("rrc", "a");
9167   if (offl != LSB)
9168     {
9169       aopPut (result, "a", MSB16 - offl);
9170     }
9171   else
9172     {
9173       if (overlapping &&
9174           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9175         {
9176           xch_a_aopGet (left, LSB, FALSE, FALSE);
9177         }
9178       else
9179         {
9180           aopPut (result, "a", MSB16 - offl);
9181           MOVA (aopGet (left, LSB, FALSE, FALSE));
9182         }
9183       emitcode ("rrc", "a");
9184       aopPut (result, "a", LSB);
9185     }
9186 }
9187
9188 /*-----------------------------------------------------------------*/
9189 /* genrshFour - shift four byte by a known amount != 0             */
9190 /*-----------------------------------------------------------------*/
9191 static void
9192 genrshFour (operand * result, operand * left,
9193             int shCount, int sign)
9194 {
9195   D (emitcode (";", "genrshFour"));
9196
9197   /* if shifting more that 3 bytes */
9198   if (shCount >= 24)
9199     {
9200       shCount -= 24;
9201       if (shCount)
9202         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9203       else
9204         movLeft2Result (left, MSB32, result, LSB, sign);
9205       addSign (result, MSB16, sign);
9206     }
9207   else if (shCount >= 16)
9208     {
9209       shCount -= 16;
9210       if (shCount)
9211         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9212       else
9213         {
9214           movLeft2Result (left, MSB24, result, LSB, 0);
9215           movLeft2Result (left, MSB32, result, MSB16, sign);
9216         }
9217       addSign (result, MSB24, sign);
9218     }
9219   else if (shCount >= 8)
9220     {
9221       shCount -= 8;
9222       if (shCount == 1)
9223         {
9224           shiftRLong (left, MSB16, result, sign);
9225         }
9226       else if (shCount == 0)
9227         {
9228           movLeft2Result (left, MSB16, result, LSB, 0);
9229           movLeft2Result (left, MSB24, result, MSB16, 0);
9230           movLeft2Result (left, MSB32, result, MSB24, sign);
9231           addSign (result, MSB32, sign);
9232         }
9233       else
9234         {
9235           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9236           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9237           /* the last shift is signed */
9238           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9239           addSign (result, MSB32, sign);
9240         }
9241     }
9242   else
9243     {
9244       /* 1 <= shCount <= 7 */
9245       if (shCount <= 2)
9246         {
9247           shiftRLong (left, LSB, result, sign);
9248           if (shCount == 2)
9249             shiftRLong (result, LSB, result, sign);
9250         }
9251       else
9252         {
9253           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9254           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9255           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9256         }
9257     }
9258 }
9259
9260 /*-----------------------------------------------------------------*/
9261 /* genRightShiftLiteral - right shifting by known count            */
9262 /*-----------------------------------------------------------------*/
9263 static void
9264 genRightShiftLiteral (operand * left,
9265                       operand * right,
9266                       operand * result,
9267                       iCode * ic,
9268                       int sign)
9269 {
9270   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9271   int size;
9272
9273   D (emitcode (";", "genRightShiftLiteral"));
9274
9275   freeAsmop (right, NULL, ic, TRUE);
9276
9277   aopOp (left, ic, FALSE);
9278   aopOp (result, ic, FALSE);
9279
9280 #if VIEW_SIZE
9281   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9282             AOP_SIZE (left));
9283 #endif
9284
9285   size = getDataSize (left);
9286   /* test the LEFT size !!! */
9287
9288   /* I suppose that the left size >= result size */
9289   if (shCount == 0)
9290     {
9291       size = getDataSize (result);
9292       while (size--)
9293         movLeft2Result (left, size, result, size, 0);
9294     }
9295
9296   else if (shCount >= (size * 8))
9297     {
9298       if (sign)
9299         {
9300           /* get sign in acc.7 */
9301           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9302         }
9303       addSign (result, LSB, sign);
9304     }
9305   else
9306     {
9307       switch (size)
9308         {
9309         case 1:
9310           genrshOne (result, left, shCount, sign);
9311           break;
9312
9313         case 2:
9314           genrshTwo (result, left, shCount, sign);
9315           break;
9316
9317         case 4:
9318           genrshFour (result, left, shCount, sign);
9319           break;
9320         default:
9321           break;
9322         }
9323     }
9324   freeAsmop (result, NULL, ic, TRUE);
9325   freeAsmop (left, NULL, ic, TRUE);
9326 }
9327
9328 /*-----------------------------------------------------------------*/
9329 /* genSignedRightShift - right shift of signed number              */
9330 /*-----------------------------------------------------------------*/
9331 static void
9332 genSignedRightShift (iCode * ic)
9333 {
9334   operand *right, *left, *result;
9335   int size, offset;
9336   char *l;
9337   symbol *tlbl, *tlbl1;
9338   bool pushedB;
9339
9340   D (emitcode (";", "genSignedRightShift"));
9341
9342   /* we do it the hard way put the shift count in b
9343      and loop thru preserving the sign */
9344
9345   right = IC_RIGHT (ic);
9346   left = IC_LEFT (ic);
9347   result = IC_RESULT (ic);
9348
9349   aopOp (right, ic, FALSE);
9350
9351
9352   if (AOP_TYPE (right) == AOP_LIT)
9353     {
9354       genRightShiftLiteral (left, right, result, ic, 1);
9355       return;
9356     }
9357   /* shift count is unknown then we have to form
9358      a loop get the loop count in B : Note: we take
9359      only the lower order byte since shifting
9360      more that 32 bits make no sense anyway, ( the
9361      largest size of an object can be only 32 bits ) */
9362
9363   pushedB = pushB ();
9364   MOVB (aopGet (right, 0, FALSE, FALSE));
9365   emitcode ("inc", "b");
9366   freeAsmop (right, NULL, ic, TRUE);
9367   aopOp (left, ic, FALSE);
9368   aopOp (result, ic, FALSE);
9369
9370   /* now move the left to the result if they are not the
9371      same */
9372   if (!sameRegs (AOP (left), AOP (result)) &&
9373       AOP_SIZE (result) > 1)
9374     {
9375
9376       size = AOP_SIZE (result);
9377       offset = 0;
9378       while (size--)
9379         {
9380           l = aopGet (left, offset, FALSE, TRUE);
9381           if (*l == '@' && IS_AOP_PREG (result))
9382             {
9383
9384               emitcode ("mov", "a,%s", l);
9385               aopPut (result, "a", offset);
9386             }
9387           else
9388             aopPut (result, l, offset);
9389           offset++;
9390         }
9391     }
9392
9393   /* mov the highest order bit to OVR */
9394   tlbl = newiTempLabel (NULL);
9395   tlbl1 = newiTempLabel (NULL);
9396
9397   size = AOP_SIZE (result);
9398   offset = size - 1;
9399   MOVA (aopGet (left, offset, FALSE, FALSE));
9400   emitcode ("rlc", "a");
9401   emitcode ("mov", "ov,c");
9402   /* if it is only one byte then */
9403   if (size == 1)
9404     {
9405       l = aopGet (left, 0, FALSE, FALSE);
9406       MOVA (l);
9407       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9408       emitLabel (tlbl);
9409       emitcode ("mov", "c,ov");
9410       emitcode ("rrc", "a");
9411       emitLabel (tlbl1);
9412       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9413       popB (pushedB);
9414       aopPut (result, "a", 0);
9415       goto release;
9416     }
9417
9418   reAdjustPreg (AOP (result));
9419   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9420   emitLabel (tlbl);
9421   emitcode ("mov", "c,ov");
9422   while (size--)
9423     {
9424       l = aopGet (result, offset, FALSE, FALSE);
9425       MOVA (l);
9426       emitcode ("rrc", "a");
9427       aopPut (result, "a", offset--);
9428     }
9429   reAdjustPreg (AOP (result));
9430   emitLabel (tlbl1);
9431   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9432   popB (pushedB);
9433
9434 release:
9435   freeAsmop (result, NULL, ic, TRUE);
9436   freeAsmop (left, NULL, ic, TRUE);
9437 }
9438
9439 /*-----------------------------------------------------------------*/
9440 /* genRightShift - generate code for right shifting                */
9441 /*-----------------------------------------------------------------*/
9442 static void
9443 genRightShift (iCode * ic)
9444 {
9445   operand *right, *left, *result;
9446   sym_link *letype;
9447   int size, offset;
9448   char *l;
9449   symbol *tlbl, *tlbl1;
9450   bool pushedB;
9451
9452   D (emitcode (";", "genRightShift"));
9453
9454   /* if signed then we do it the hard way preserve the
9455      sign bit moving it inwards */
9456   letype = getSpec (operandType (IC_LEFT (ic)));
9457
9458   if (!SPEC_USIGN (letype))
9459     {
9460       genSignedRightShift (ic);
9461       return;
9462     }
9463
9464   /* signed & unsigned types are treated the same : i.e. the
9465      signed is NOT propagated inwards : quoting from the
9466      ANSI - standard : "for E1 >> E2, is equivalent to division
9467      by 2**E2 if unsigned or if it has a non-negative value,
9468      otherwise the result is implementation defined ", MY definition
9469      is that the sign does not get propagated */
9470
9471   right = IC_RIGHT (ic);
9472   left = IC_LEFT (ic);
9473   result = IC_RESULT (ic);
9474
9475   aopOp (right, ic, FALSE);
9476
9477   /* if the shift count is known then do it
9478      as efficiently as possible */
9479   if (AOP_TYPE (right) == AOP_LIT)
9480     {
9481       genRightShiftLiteral (left, right, result, ic, 0);
9482       return;
9483     }
9484
9485   /* shift count is unknown then we have to form
9486      a loop get the loop count in B : Note: we take
9487      only the lower order byte since shifting
9488      more that 32 bits make no sense anyway, ( the
9489      largest size of an object can be only 32 bits ) */
9490
9491   pushedB = pushB ();
9492   MOVB (aopGet (right, 0, FALSE, FALSE));
9493   emitcode ("inc", "b");
9494   freeAsmop (right, NULL, ic, TRUE);
9495   aopOp (left, ic, FALSE);
9496   aopOp (result, ic, FALSE);
9497
9498   /* now move the left to the result if they are not the
9499      same */
9500   if (!sameRegs (AOP (left), AOP (result)) &&
9501       AOP_SIZE (result) > 1)
9502     {
9503       size = AOP_SIZE (result);
9504       offset = 0;
9505       while (size--)
9506         {
9507           l = aopGet (left, offset, FALSE, TRUE);
9508           if (*l == '@' && IS_AOP_PREG (result))
9509             {
9510
9511               emitcode ("mov", "a,%s", l);
9512               aopPut (result, "a", offset);
9513             }
9514           else
9515             aopPut (result, l, offset);
9516           offset++;
9517         }
9518     }
9519
9520   tlbl = newiTempLabel (NULL);
9521   tlbl1 = newiTempLabel (NULL);
9522   size = AOP_SIZE (result);
9523   offset = size - 1;
9524
9525   /* if it is only one byte then */
9526   if (size == 1)
9527     {
9528       l = aopGet (left, 0, FALSE, FALSE);
9529       MOVA (l);
9530       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9531       emitLabel (tlbl);
9532       CLRC;
9533       emitcode ("rrc", "a");
9534       emitLabel (tlbl1);
9535       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9536       popB (pushedB);
9537       aopPut (result, "a", 0);
9538       goto release;
9539     }
9540
9541   reAdjustPreg (AOP (result));
9542   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9543   emitLabel (tlbl);
9544   CLRC;
9545   while (size--)
9546     {
9547       l = aopGet (result, offset, FALSE, FALSE);
9548       MOVA (l);
9549       emitcode ("rrc", "a");
9550       aopPut (result, "a", offset--);
9551     }
9552   reAdjustPreg (AOP (result));
9553
9554   emitLabel (tlbl1);
9555   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9556   popB (pushedB);
9557
9558 release:
9559   freeAsmop (result, NULL, ic, TRUE);
9560   freeAsmop (left, NULL, ic, TRUE);
9561 }
9562
9563 /*-----------------------------------------------------------------*/
9564 /* emitPtrByteGet - emits code to get a byte into A through a      */
9565 /*                  pointer register (R0, R1, or DPTR). The        */
9566 /*                  original value of A can be preserved in B.     */
9567 /*-----------------------------------------------------------------*/
9568 static void
9569 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9570 {
9571   switch (p_type)
9572     {
9573     case IPOINTER:
9574     case POINTER:
9575       if (preserveAinB)
9576         emitcode ("mov", "b,a");
9577       emitcode ("mov", "a,@%s", rname);
9578       break;
9579
9580     case PPOINTER:
9581       if (preserveAinB)
9582         emitcode ("mov", "b,a");
9583       emitcode ("movx", "a,@%s", rname);
9584       break;
9585
9586     case FPOINTER:
9587       if (preserveAinB)
9588         emitcode ("mov", "b,a");
9589       emitcode ("movx", "a,@dptr");
9590       break;
9591
9592     case CPOINTER:
9593       if (preserveAinB)
9594         emitcode ("mov", "b,a");
9595       emitcode ("clr", "a");
9596       emitcode ("movc", "a,@a+dptr");
9597       break;
9598
9599     case GPOINTER:
9600       if (preserveAinB)
9601         {
9602           emitcode ("push", "b");
9603           emitcode ("push", "acc");
9604         }
9605       emitcode ("lcall", "__gptrget");
9606       if (preserveAinB)
9607         emitcode ("pop", "b");
9608       break;
9609     }
9610 }
9611
9612 /*-----------------------------------------------------------------*/
9613 /* emitPtrByteSet - emits code to set a byte from src through a    */
9614 /*                  pointer register (R0, R1, or DPTR).            */
9615 /*-----------------------------------------------------------------*/
9616 static void
9617 emitPtrByteSet (char *rname, int p_type, char *src)
9618 {
9619   switch (p_type)
9620     {
9621     case IPOINTER:
9622     case POINTER:
9623       if (*src=='@')
9624         {
9625           MOVA (src);
9626           emitcode ("mov", "@%s,a", rname);
9627         }
9628       else
9629         emitcode ("mov", "@%s,%s", rname, src);
9630       break;
9631
9632     case PPOINTER:
9633       MOVA (src);
9634       emitcode ("movx", "@%s,a", rname);
9635       break;
9636
9637     case FPOINTER:
9638       MOVA (src);
9639       emitcode ("movx", "@dptr,a");
9640       break;
9641
9642     case GPOINTER:
9643       MOVA (src);
9644       emitcode ("lcall", "__gptrput");
9645       break;
9646     }
9647 }
9648
9649 /*-----------------------------------------------------------------*/
9650 /* genUnpackBits - generates code for unpacking bits               */
9651 /*-----------------------------------------------------------------*/
9652 static void
9653 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9654 {
9655   int offset = 0;       /* result byte offset */
9656   int rsize;            /* result size */
9657   int rlen = 0;         /* remaining bitfield length */
9658   sym_link *etype;      /* bitfield type information */
9659   int blen;             /* bitfield length */
9660   int bstr;             /* bitfield starting bit within byte */
9661   char buffer[10];
9662
9663   D(emitcode (";     genUnpackBits",""));
9664
9665   etype = getSpec (operandType (result));
9666   rsize = getSize (operandType (result));
9667   blen = SPEC_BLEN (etype);
9668   bstr = SPEC_BSTR (etype);
9669
9670   if (ifx && blen <= 8)
9671     {
9672       emitPtrByteGet (rname, ptype, FALSE);
9673       if (blen == 1)
9674         {
9675           SNPRINTF (buffer, sizeof(buffer),
9676                     "acc.%d", bstr);
9677           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9678         }
9679       else
9680         {
9681           if (blen < 8)
9682             emitcode ("anl", "a,#0x%02x",
9683                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9684           genIfxJump (ifx, "a", NULL, NULL, NULL);
9685         }
9686       return;
9687     }
9688   wassert (!ifx);
9689
9690   /* If the bitfield length is less than a byte */
9691   if (blen < 8)
9692     {
9693       emitPtrByteGet (rname, ptype, FALSE);
9694       AccRol (8 - bstr);
9695       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9696       if (!SPEC_USIGN (etype))
9697         {
9698           /* signed bitfield */
9699           symbol *tlbl = newiTempLabel (NULL);
9700
9701           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9702           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9703           emitLabel (tlbl);
9704         }
9705       aopPut (result, "a", offset++);
9706       goto finish;
9707     }
9708
9709   /* Bit field did not fit in a byte. Copy all
9710      but the partial byte at the end.  */
9711   for (rlen=blen;rlen>=8;rlen-=8)
9712     {
9713       emitPtrByteGet (rname, ptype, FALSE);
9714       aopPut (result, "a", offset++);
9715       if (rlen>8)
9716         emitcode ("inc", "%s", rname);
9717     }
9718
9719   /* Handle the partial byte at the end */
9720   if (rlen)
9721     {
9722       emitPtrByteGet (rname, ptype, FALSE);
9723       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9724       if (!SPEC_USIGN (etype))
9725         {
9726           /* signed bitfield */
9727           symbol *tlbl = newiTempLabel (NULL);
9728
9729           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9730           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9731           emitLabel (tlbl);
9732         }
9733       aopPut (result, "a", offset++);
9734     }
9735
9736 finish:
9737   if (offset < rsize)
9738     {
9739       char *source;
9740
9741       if (SPEC_USIGN (etype))
9742         source = zero;
9743       else
9744         {
9745           /* signed bitfield: sign extension with 0x00 or 0xff */
9746           emitcode ("rlc", "a");
9747           emitcode ("subb", "a,acc");
9748
9749           source = "a";
9750         }
9751       rsize -= offset;
9752       while (rsize--)
9753         aopPut (result, source, offset++);
9754     }
9755 }
9756
9757
9758 /*-----------------------------------------------------------------*/
9759 /* genDataPointerGet - generates code when ptr offset is known     */
9760 /*-----------------------------------------------------------------*/
9761 static void
9762 genDataPointerGet (operand * left,
9763                    operand * result,
9764                    iCode * ic)
9765 {
9766   char *l;
9767   char buffer[256];
9768   int size, offset = 0;
9769
9770   D (emitcode (";", "genDataPointerGet"));
9771
9772   aopOp (result, ic, TRUE);
9773
9774   /* get the string representation of the name */
9775   l = aopGet (left, 0, FALSE, TRUE);
9776   l++; // remove #
9777   size = AOP_SIZE (result);
9778   while (size--)
9779     {
9780       if (offset)
9781         {
9782           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9783         }
9784       else
9785         {
9786           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9787         }
9788       aopPut (result, buffer, offset++);
9789     }
9790
9791   freeAsmop (result, NULL, ic, TRUE);
9792   freeAsmop (left, NULL, ic, TRUE);
9793 }
9794
9795 /*-----------------------------------------------------------------*/
9796 /* genNearPointerGet - emitcode for near pointer fetch             */
9797 /*-----------------------------------------------------------------*/
9798 static void
9799 genNearPointerGet (operand * left,
9800                    operand * result,
9801                    iCode * ic,
9802                    iCode * pi,
9803                    iCode * ifx)
9804 {
9805   asmop *aop = NULL;
9806   regs *preg = NULL;
9807   char *rname;
9808   sym_link *rtype, *retype;
9809   sym_link *ltype = operandType (left);
9810   char buffer[80];
9811
9812   D (emitcode (";", "genNearPointerGet"));
9813
9814   rtype = operandType (result);
9815   retype = getSpec (rtype);
9816
9817   aopOp (left, ic, FALSE);
9818
9819   /* if left is rematerialisable and
9820      result is not bitfield variable type and
9821      the left is pointer to data space i.e
9822      lower 128 bytes of space */
9823   if (AOP_TYPE (left) == AOP_IMMD &&
9824       !IS_BITFIELD (retype) &&
9825       DCL_TYPE (ltype) == POINTER)
9826     {
9827       genDataPointerGet (left, result, ic);
9828       return;
9829     }
9830
9831  /* if the value is already in a pointer register
9832      then don't need anything more */
9833   if (!AOP_INPREG (AOP (left)))
9834     {
9835       if (IS_AOP_PREG (left))
9836         {
9837           // Aha, it is a pointer, just in disguise.
9838           rname = aopGet (left, 0, FALSE, FALSE);
9839           if (*rname != '@')
9840             {
9841               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9842                       __FILE__, __LINE__);
9843             }
9844           else
9845             {
9846               // Expected case.
9847               emitcode ("mov", "a%s,%s", rname + 1, rname);
9848               rname++;  // skip the '@'.
9849             }
9850         }
9851       else
9852         {
9853           /* otherwise get a free pointer register */
9854           aop = newAsmop (0);
9855           preg = getFreePtr (ic, &aop, FALSE);
9856           emitcode ("mov", "%s,%s",
9857                     preg->name,
9858                     aopGet (left, 0, FALSE, TRUE));
9859           rname = preg->name;
9860         }
9861     }
9862   else
9863     rname = aopGet (left, 0, FALSE, FALSE);
9864
9865   //aopOp (result, ic, FALSE);
9866   aopOp (result, ic, result?TRUE:FALSE);
9867
9868   /* if bitfield then unpack the bits */
9869   if (IS_BITFIELD (retype))
9870     genUnpackBits (result, rname, POINTER, ifx);
9871   else
9872     {
9873       /* we have can just get the values */
9874       int size = AOP_SIZE (result);
9875       int offset = 0;
9876
9877       while (size--)
9878         {
9879           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9880             {
9881
9882               emitcode ("mov", "a,@%s", rname);
9883               if (!ifx)
9884                 aopPut (result, "a", offset);
9885             }
9886           else
9887             {
9888               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9889               aopPut (result, buffer, offset);
9890             }
9891           offset++;
9892           if (size || pi)
9893             emitcode ("inc", "%s", rname);
9894         }
9895     }
9896
9897   /* now some housekeeping stuff */
9898   if (aop)       /* we had to allocate for this iCode */
9899     {
9900       if (pi) { /* post increment present */
9901         aopPut (left, rname, 0);
9902       }
9903       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9904     }
9905   else
9906     {
9907       /* we did not allocate which means left
9908          already in a pointer register, then
9909          if size > 0 && this could be used again
9910          we have to point it back to where it
9911          belongs */
9912       if ((AOP_SIZE (result) > 1 &&
9913            !OP_SYMBOL (left)->remat &&
9914            (OP_SYMBOL (left)->liveTo > ic->seq ||
9915             ic->depth)) &&
9916           !pi)
9917         {
9918           int size = AOP_SIZE (result) - 1;
9919           while (size--)
9920             emitcode ("dec", "%s", rname);
9921         }
9922     }
9923
9924   if (ifx && !ifx->generated)
9925     {
9926       genIfxJump (ifx, "a", left, NULL, result);
9927     }
9928
9929   /* done */
9930   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9931   freeAsmop (left, NULL, ic, TRUE);
9932   if (pi) pi->generated = 1;
9933 }
9934
9935 /*-----------------------------------------------------------------*/
9936 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9937 /*-----------------------------------------------------------------*/
9938 static void
9939 genPagedPointerGet (operand * left,
9940                     operand * result,
9941                     iCode * ic,
9942                     iCode *pi,
9943                     iCode *ifx)
9944 {
9945   asmop *aop = NULL;
9946   regs *preg = NULL;
9947   char *rname;
9948   sym_link *rtype, *retype;
9949
9950   D (emitcode (";", "genPagedPointerGet"));
9951
9952   rtype = operandType (result);
9953   retype = getSpec (rtype);
9954
9955   aopOp (left, ic, FALSE);
9956
9957   /* if the value is already in a pointer register
9958      then don't need anything more */
9959   if (!AOP_INPREG (AOP (left)))
9960     {
9961       /* otherwise get a free pointer register */
9962       aop = newAsmop (0);
9963       preg = getFreePtr (ic, &aop, FALSE);
9964       emitcode ("mov", "%s,%s",
9965                 preg->name,
9966                 aopGet (left, 0, FALSE, TRUE));
9967       rname = preg->name;
9968     }
9969   else
9970     rname = aopGet (left, 0, FALSE, FALSE);
9971
9972   aopOp (result, ic, FALSE);
9973
9974   /* if bitfield then unpack the bits */
9975   if (IS_BITFIELD (retype))
9976     genUnpackBits (result, rname, PPOINTER, ifx);
9977   else
9978     {
9979       /* we have can just get the values */
9980       int size = AOP_SIZE (result);
9981       int offset = 0;
9982
9983       while (size--)
9984         {
9985
9986           emitcode ("movx", "a,@%s", rname);
9987           if (!ifx)
9988             aopPut (result, "a", offset);
9989
9990           offset++;
9991
9992           if (size || pi)
9993             emitcode ("inc", "%s", rname);
9994         }
9995     }
9996
9997   /* now some housekeeping stuff */
9998   if (aop) /* we had to allocate for this iCode */
9999     {
10000       if (pi)
10001         aopPut (left, rname, 0);
10002       freeAsmop (NULL, aop, ic, TRUE);
10003     }
10004   else
10005     {
10006       /* we did not allocate which means left
10007          already in a pointer register, then
10008          if size > 0 && this could be used again
10009          we have to point it back to where it
10010          belongs */
10011       if ((AOP_SIZE (result) > 1 &&
10012            !OP_SYMBOL (left)->remat &&
10013            (OP_SYMBOL (left)->liveTo > ic->seq ||
10014             ic->depth)) &&
10015           !pi)
10016         {
10017           int size = AOP_SIZE (result) - 1;
10018           while (size--)
10019             emitcode ("dec", "%s", rname);
10020         }
10021     }
10022
10023   if (ifx && !ifx->generated)
10024     {
10025       genIfxJump (ifx, "a", left, NULL, result);
10026     }
10027
10028   /* done */
10029   freeAsmop (result, NULL, ic, TRUE);
10030   freeAsmop (left, NULL, ic, TRUE);
10031   if (pi) pi->generated = 1;
10032 }
10033
10034 /*--------------------------------------------------------------------*/
10035 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10036 /*--------------------------------------------------------------------*/
10037 static void
10038 loadDptrFromOperand (operand *op, bool loadBToo)
10039 {
10040   if (AOP_TYPE (op) != AOP_STR)
10041     {
10042       /* if this is rematerializable */
10043       if (AOP_TYPE (op) == AOP_IMMD)
10044         {
10045           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10046           if (loadBToo)
10047             {
10048               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10049                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10050               else
10051                 {
10052                   wassertl(FALSE, "need pointerCode");
10053                   emitcode ("", "; mov b,???");
10054                   /* genPointerGet and genPointerSet originally did different
10055                   ** things for this case. Both seem wrong.
10056                   ** from genPointerGet:
10057                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10058                   ** from genPointerSet:
10059                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10060                   */
10061                 }
10062             }
10063         }
10064       else if (AOP_TYPE (op) == AOP_DPTR)
10065         {
10066           if (loadBToo)
10067             {
10068               MOVA (aopGet (op, 0, FALSE, FALSE));
10069               emitcode ("push", "acc");
10070               MOVA (aopGet (op, 1, FALSE, FALSE));
10071               emitcode ("push", "acc");
10072               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10073               emitcode ("pop", "dph");
10074               emitcode ("pop", "dpl");
10075             }
10076           else
10077             {
10078               MOVA (aopGet (op, 0, FALSE, FALSE));
10079               emitcode ("push", "acc");
10080               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10081               emitcode ("pop", "dpl");
10082             }
10083         }
10084       else
10085         {                       /* we need to get it byte by byte */
10086           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10087           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10088           if (loadBToo)
10089             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10090         }
10091     }
10092 }
10093
10094 /*-----------------------------------------------------------------*/
10095 /* genFarPointerGet - get value from far space                     */
10096 /*-----------------------------------------------------------------*/
10097 static void
10098 genFarPointerGet (operand * left,
10099                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10100 {
10101   int size, offset;
10102   sym_link *retype = getSpec (operandType (result));
10103
10104   D (emitcode (";", "genFarPointerGet"));
10105
10106   aopOp (left, ic, FALSE);
10107   loadDptrFromOperand (left, FALSE);
10108
10109   /* so dptr now contains the address */
10110   aopOp (result, ic, FALSE);
10111
10112   /* if bit then unpack */
10113   if (IS_BITFIELD (retype))
10114     genUnpackBits (result, "dptr", FPOINTER, ifx);
10115   else
10116     {
10117       size = AOP_SIZE (result);
10118       offset = 0;
10119
10120       while (size--)
10121         {
10122           emitcode ("movx", "a,@dptr");
10123           if (!ifx)
10124             aopPut (result, "a", offset++);
10125           if (size || pi)
10126             emitcode ("inc", "dptr");
10127         }
10128     }
10129
10130   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10131     {
10132       aopPut (left, "dpl", 0);
10133       aopPut (left, "dph", 1);
10134       pi->generated = 1;
10135     }
10136
10137   if (ifx && !ifx->generated)
10138     {
10139       genIfxJump (ifx, "a", left, NULL, result);
10140     }
10141
10142   freeAsmop (result, NULL, ic, TRUE);
10143   freeAsmop (left, NULL, ic, TRUE);
10144 }
10145
10146 /*-----------------------------------------------------------------*/
10147 /* genCodePointerGet - get value from code space                   */
10148 /*-----------------------------------------------------------------*/
10149 static void
10150 genCodePointerGet (operand * left,
10151                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10152 {
10153   int size, offset;
10154   sym_link *retype = getSpec (operandType (result));
10155
10156   D (emitcode (";", "genCodePointerGet"));
10157
10158   aopOp (left, ic, FALSE);
10159   loadDptrFromOperand (left, FALSE);
10160
10161   /* so dptr now contains the address */
10162   aopOp (result, ic, FALSE);
10163
10164   /* if bit then unpack */
10165   if (IS_BITFIELD (retype))
10166     genUnpackBits (result, "dptr", CPOINTER, ifx);
10167   else
10168     {
10169       size = AOP_SIZE (result);
10170       offset = 0;
10171
10172       while (size--)
10173         {
10174           emitcode ("clr", "a");
10175           emitcode ("movc", "a,@a+dptr");
10176           if (!ifx)
10177             aopPut (result, "a", offset++);
10178           if (size || pi)
10179             emitcode ("inc", "dptr");
10180         }
10181     }
10182
10183   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10184     {
10185       aopPut (left, "dpl", 0);
10186       aopPut (left, "dph", 1);
10187       pi->generated = 1;
10188     }
10189
10190   if (ifx && !ifx->generated)
10191     {
10192       genIfxJump (ifx, "a", left, NULL, result);
10193     }
10194
10195   freeAsmop (result, NULL, ic, TRUE);
10196   freeAsmop (left, NULL, ic, TRUE);
10197 }
10198
10199 /*-----------------------------------------------------------------*/
10200 /* genGenPointerGet - get value from generic pointer space         */
10201 /*-----------------------------------------------------------------*/
10202 static void
10203 genGenPointerGet (operand * left,
10204                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10205 {
10206   int size, offset;
10207   sym_link *retype = getSpec (operandType (result));
10208
10209   D (emitcode (";", "genGenPointerGet"));
10210
10211   aopOp (left, ic, FALSE);
10212   loadDptrFromOperand (left, TRUE);
10213
10214   /* so dptr now contains the address */
10215   aopOp (result, ic, FALSE);
10216
10217   /* if bit then unpack */
10218   if (IS_BITFIELD (retype))
10219     {
10220       genUnpackBits (result, "dptr", GPOINTER, ifx);
10221     }
10222   else
10223     {
10224       size = AOP_SIZE (result);
10225       offset = 0;
10226
10227       while (size--)
10228         {
10229           emitcode ("lcall", "__gptrget");
10230           if (!ifx)
10231             aopPut (result, "a", offset++);
10232           if (size || pi)
10233             emitcode ("inc", "dptr");
10234         }
10235     }
10236
10237   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10238     {
10239       aopPut (left, "dpl", 0);
10240       aopPut (left, "dph", 1);
10241       pi->generated = 1;
10242     }
10243
10244   if (ifx && !ifx->generated)
10245     {
10246       genIfxJump (ifx, "a", left, NULL, result);
10247     }
10248
10249   freeAsmop (result, NULL, ic, TRUE);
10250   freeAsmop (left, NULL, ic, TRUE);
10251 }
10252
10253 /*-----------------------------------------------------------------*/
10254 /* genPointerGet - generate code for pointer get                   */
10255 /*-----------------------------------------------------------------*/
10256 static void
10257 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10258 {
10259   operand *left, *result;
10260   sym_link *type, *etype;
10261   int p_type;
10262
10263   D (emitcode (";", "genPointerGet"));
10264
10265   left = IC_LEFT (ic);
10266   result = IC_RESULT (ic);
10267
10268   if (getSize (operandType (result))>1)
10269     ifx = NULL;
10270
10271   /* depending on the type of pointer we need to
10272      move it to the correct pointer register */
10273   type = operandType (left);
10274   etype = getSpec (type);
10275   /* if left is of type of pointer then it is simple */
10276   if (IS_PTR (type) && !IS_FUNC (type->next))
10277     p_type = DCL_TYPE (type);
10278   else
10279     {
10280       /* we have to go by the storage class */
10281       p_type = PTR_TYPE (SPEC_OCLS (etype));
10282     }
10283
10284   /* special case when cast remat */
10285   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10286       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10287     {
10288       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10289       type = operandType (left);
10290       p_type = DCL_TYPE (type);
10291     }
10292   /* now that we have the pointer type we assign
10293      the pointer values */
10294   switch (p_type)
10295     {
10296
10297     case POINTER:
10298     case IPOINTER:
10299       genNearPointerGet (left, result, ic, pi, ifx);
10300       break;
10301
10302     case PPOINTER:
10303       genPagedPointerGet (left, result, ic, pi, ifx);
10304       break;
10305
10306     case FPOINTER:
10307       genFarPointerGet (left, result, ic, pi, ifx);
10308       break;
10309
10310     case CPOINTER:
10311       genCodePointerGet (left, result, ic, pi, ifx);
10312       break;
10313
10314     case GPOINTER:
10315       genGenPointerGet (left, result, ic, pi, ifx);
10316       break;
10317     }
10318 }
10319
10320
10321 /*-----------------------------------------------------------------*/
10322 /* genPackBits - generates code for packed bit storage             */
10323 /*-----------------------------------------------------------------*/
10324 static void
10325 genPackBits (sym_link * etype,
10326              operand * right,
10327              char *rname, int p_type)
10328 {
10329   int offset = 0;       /* source byte offset */
10330   int rlen = 0;         /* remaining bitfield length */
10331   int blen;             /* bitfield length */
10332   int bstr;             /* bitfield starting bit within byte */
10333   int litval;           /* source literal value (if AOP_LIT) */
10334   unsigned char mask;   /* bitmask within current byte */
10335
10336   D(emitcode (";     genPackBits",""));
10337
10338   blen = SPEC_BLEN (etype);
10339   bstr = SPEC_BSTR (etype);
10340
10341   /* If the bitfield length is less than a byte */
10342   if (blen < 8)
10343     {
10344       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10345               (unsigned char) (0xFF >> (8 - bstr)));
10346
10347       if (AOP_TYPE (right) == AOP_LIT)
10348         {
10349           /* Case with a bitfield length <8 and literal source
10350           */
10351           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10352           litval <<= bstr;
10353           litval &= (~mask) & 0xff;
10354           emitPtrByteGet (rname, p_type, FALSE);
10355           if ((mask|litval)!=0xff)
10356             emitcode ("anl","a,#0x%02x", mask);
10357           if (litval)
10358             emitcode ("orl","a,#0x%02x", litval);
10359         }
10360       else
10361         {
10362           if ((blen==1) && (p_type!=GPOINTER))
10363             {
10364               /* Case with a bitfield length == 1 and no generic pointer
10365               */
10366               if (AOP_TYPE (right) == AOP_CRY)
10367                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10368               else
10369                 {
10370                   MOVA (aopGet (right, 0, FALSE, FALSE));
10371                   emitcode ("rrc","a");
10372                 }
10373               emitPtrByteGet (rname, p_type, FALSE);
10374               emitcode ("mov","acc.%d,c",bstr);
10375             }
10376           else
10377             {
10378               bool pushedB;
10379               /* Case with a bitfield length < 8 and arbitrary source
10380               */
10381               MOVA (aopGet (right, 0, FALSE, FALSE));
10382               /* shift and mask source value */
10383               AccLsh (bstr);
10384               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10385
10386               pushedB = pushB ();
10387               /* transfer A to B and get next byte */
10388               emitPtrByteGet (rname, p_type, TRUE);
10389
10390               emitcode ("anl", "a,#0x%02x", mask);
10391               emitcode ("orl", "a,b");
10392               if (p_type == GPOINTER)
10393                 emitcode ("pop", "b");
10394
10395               popB (pushedB);
10396            }
10397         }
10398
10399       emitPtrByteSet (rname, p_type, "a");
10400       return;
10401     }
10402
10403   /* Bit length is greater than 7 bits. In this case, copy  */
10404   /* all except the partial byte at the end                 */
10405   for (rlen=blen;rlen>=8;rlen-=8)
10406     {
10407       emitPtrByteSet (rname, p_type,
10408                       aopGet (right, offset++, FALSE, TRUE) );
10409       if (rlen>8)
10410         emitcode ("inc", "%s", rname);
10411     }
10412
10413   /* If there was a partial byte at the end */
10414   if (rlen)
10415     {
10416       mask = (((unsigned char) -1 << rlen) & 0xff);
10417
10418       if (AOP_TYPE (right) == AOP_LIT)
10419         {
10420           /* Case with partial byte and literal source
10421           */
10422           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10423           litval >>= (blen-rlen);
10424           litval &= (~mask) & 0xff;
10425           emitPtrByteGet (rname, p_type, FALSE);
10426           if ((mask|litval)!=0xff)
10427             emitcode ("anl","a,#0x%02x", mask);
10428           if (litval)
10429             emitcode ("orl","a,#0x%02x", litval);
10430         }
10431       else
10432         {
10433           bool pushedB;
10434           /* Case with partial byte and arbitrary source
10435           */
10436           MOVA (aopGet (right, offset++, FALSE, FALSE));
10437           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10438
10439           pushedB = pushB ();
10440           /* transfer A to B and get next byte */
10441           emitPtrByteGet (rname, p_type, TRUE);
10442
10443           emitcode ("anl", "a,#0x%02x", mask);
10444           emitcode ("orl", "a,b");
10445           if (p_type == GPOINTER)
10446             emitcode ("pop", "b");
10447
10448           popB (pushedB);
10449         }
10450       emitPtrByteSet (rname, p_type, "a");
10451     }
10452 }
10453
10454
10455 /*-----------------------------------------------------------------*/
10456 /* genDataPointerSet - remat pointer to data space                 */
10457 /*-----------------------------------------------------------------*/
10458 static void
10459 genDataPointerSet (operand * right,
10460                    operand * result,
10461                    iCode * ic)
10462 {
10463   int size, offset = 0;
10464   char *l, buffer[256];
10465
10466   D (emitcode (";", "genDataPointerSet"));
10467
10468   aopOp (right, ic, FALSE);
10469
10470   l = aopGet (result, 0, FALSE, TRUE);
10471   l++; //remove #
10472   size = AOP_SIZE (right);
10473   while (size--)
10474     {
10475       if (offset)
10476         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10477       else
10478         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10479       emitcode ("mov", "%s,%s", buffer,
10480                 aopGet (right, offset++, FALSE, FALSE));
10481     }
10482
10483   freeAsmop (result, NULL, ic, TRUE);
10484   freeAsmop (right, NULL, ic, TRUE);
10485 }
10486
10487 /*-----------------------------------------------------------------*/
10488 /* genNearPointerSet - emitcode for near pointer put                */
10489 /*-----------------------------------------------------------------*/
10490 static void
10491 genNearPointerSet (operand * right,
10492                    operand * result,
10493                    iCode * ic,
10494                    iCode * pi)
10495 {
10496   asmop *aop = NULL;
10497   regs *preg = NULL;
10498   char *rname, *l;
10499   sym_link *retype, *letype;
10500   sym_link *ptype = operandType (result);
10501
10502   D (emitcode (";", "genNearPointerSet"));
10503
10504   retype = getSpec (operandType (right));
10505   letype = getSpec (ptype);
10506
10507   aopOp (result, ic, FALSE);
10508
10509   /* if the result is rematerializable &
10510      in data space & not a bit variable */
10511   if (AOP_TYPE (result) == AOP_IMMD &&
10512       DCL_TYPE (ptype) == POINTER &&
10513       !IS_BITVAR (retype) &&
10514       !IS_BITVAR (letype))
10515     {
10516       genDataPointerSet (right, result, ic);
10517       return;
10518     }
10519
10520   /* if the value is already in a pointer register
10521      then don't need anything more */
10522   if (!AOP_INPREG (AOP (result)))
10523     {
10524         if (
10525             //AOP_TYPE (result) == AOP_STK
10526             IS_AOP_PREG(result)
10527             )
10528         {
10529             // Aha, it is a pointer, just in disguise.
10530             rname = aopGet (result, 0, FALSE, FALSE);
10531             if (*rname != '@')
10532             {
10533                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10534                         __FILE__, __LINE__);
10535             }
10536             else
10537             {
10538                 // Expected case.
10539                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10540                 rname++;  // skip the '@'.
10541             }
10542         }
10543         else
10544         {
10545             /* otherwise get a free pointer register */
10546             aop = newAsmop (0);
10547             preg = getFreePtr (ic, &aop, FALSE);
10548             emitcode ("mov", "%s,%s",
10549                       preg->name,
10550                       aopGet (result, 0, FALSE, TRUE));
10551             rname = preg->name;
10552         }
10553     }
10554     else
10555     {
10556         rname = aopGet (result, 0, FALSE, FALSE);
10557     }
10558
10559   aopOp (right, ic, FALSE);
10560
10561   /* if bitfield then unpack the bits */
10562   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10563     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10564   else
10565     {
10566       /* we can just get the values */
10567       int size = AOP_SIZE (right);
10568       int offset = 0;
10569
10570       while (size--)
10571         {
10572           l = aopGet (right, offset, FALSE, TRUE);
10573           if ((*l == '@') || (strcmp (l, "acc") == 0))
10574             {
10575               MOVA (l);
10576               emitcode ("mov", "@%s,a", rname);
10577             }
10578           else
10579             emitcode ("mov", "@%s,%s", rname, l);
10580           if (size || pi)
10581             emitcode ("inc", "%s", rname);
10582           offset++;
10583         }
10584     }
10585
10586   /* now some housekeeping stuff */
10587   if (aop) /* we had to allocate for this iCode */
10588     {
10589       if (pi)
10590         aopPut (result, rname, 0);
10591       freeAsmop (NULL, aop, ic, TRUE);
10592     }
10593   else
10594     {
10595       /* we did not allocate which means left
10596          already in a pointer register, then
10597          if size > 0 && this could be used again
10598          we have to point it back to where it
10599          belongs */
10600       if ((AOP_SIZE (right) > 1 &&
10601            !OP_SYMBOL (result)->remat &&
10602            (OP_SYMBOL (result)->liveTo > ic->seq ||
10603             ic->depth)) &&
10604           !pi)
10605         {
10606           int size = AOP_SIZE (right) - 1;
10607           while (size--)
10608             emitcode ("dec", "%s", rname);
10609         }
10610     }
10611
10612   /* done */
10613   if (pi) pi->generated = 1;
10614   freeAsmop (result, NULL, ic, TRUE);
10615   freeAsmop (right, NULL, ic, TRUE);
10616 }
10617
10618 /*-----------------------------------------------------------------*/
10619 /* genPagedPointerSet - emitcode for Paged pointer put             */
10620 /*-----------------------------------------------------------------*/
10621 static void
10622 genPagedPointerSet (operand * right,
10623                     operand * result,
10624                     iCode * ic,
10625                     iCode * pi)
10626 {
10627   asmop *aop = NULL;
10628   regs *preg = NULL;
10629   char *rname, *l;
10630   sym_link *retype, *letype;
10631
10632   D (emitcode (";", "genPagedPointerSet"));
10633
10634   retype = getSpec (operandType (right));
10635   letype = getSpec (operandType (result));
10636
10637   aopOp (result, ic, FALSE);
10638
10639   /* if the value is already in a pointer register
10640      then don't need anything more */
10641   if (!AOP_INPREG (AOP (result)))
10642     {
10643       /* otherwise get a free pointer register */
10644       aop = newAsmop (0);
10645       preg = getFreePtr (ic, &aop, FALSE);
10646       emitcode ("mov", "%s,%s",
10647                 preg->name,
10648                 aopGet (result, 0, FALSE, TRUE));
10649       rname = preg->name;
10650     }
10651   else
10652     rname = aopGet (result, 0, FALSE, FALSE);
10653
10654   aopOp (right, ic, FALSE);
10655
10656   /* if bitfield then unpack the bits */
10657   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10658     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10659   else
10660     {
10661       /* we have can just get the values */
10662       int size = AOP_SIZE (right);
10663       int offset = 0;
10664
10665       while (size--)
10666         {
10667           l = aopGet (right, offset, FALSE, TRUE);
10668           MOVA (l);
10669           emitcode ("movx", "@%s,a", rname);
10670
10671           if (size || pi)
10672             emitcode ("inc", "%s", rname);
10673
10674           offset++;
10675         }
10676     }
10677
10678   /* now some housekeeping stuff */
10679   if (aop) /* we had to allocate for this iCode */
10680     {
10681       if (pi)
10682         aopPut (result, rname, 0);
10683       freeAsmop (NULL, aop, ic, TRUE);
10684     }
10685   else
10686     {
10687       /* we did not allocate which means left
10688          already in a pointer register, then
10689          if size > 0 && this could be used again
10690          we have to point it back to where it
10691          belongs */
10692       if (AOP_SIZE (right) > 1 &&
10693           !OP_SYMBOL (result)->remat &&
10694           (OP_SYMBOL (result)->liveTo > ic->seq ||
10695            ic->depth))
10696         {
10697           int size = AOP_SIZE (right) - 1;
10698           while (size--)
10699             emitcode ("dec", "%s", rname);
10700         }
10701     }
10702
10703   /* done */
10704   if (pi) pi->generated = 1;
10705   freeAsmop (result, NULL, ic, TRUE);
10706   freeAsmop (right, NULL, ic, TRUE);
10707 }
10708
10709 /*-----------------------------------------------------------------*/
10710 /* genFarPointerSet - set value from far space                     */
10711 /*-----------------------------------------------------------------*/
10712 static void
10713 genFarPointerSet (operand * right,
10714                   operand * result, iCode * ic, iCode * pi)
10715 {
10716   int size, offset;
10717   sym_link *retype = getSpec (operandType (right));
10718   sym_link *letype = getSpec (operandType (result));
10719
10720   D(emitcode (";     genFarPointerSet",""));
10721
10722   aopOp (result, ic, FALSE);
10723   loadDptrFromOperand (result, FALSE);
10724
10725   /* so dptr now contains the address */
10726   aopOp (right, ic, FALSE);
10727
10728   /* if bit then unpack */
10729   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10730     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10731   else
10732     {
10733       size = AOP_SIZE (right);
10734       offset = 0;
10735
10736       while (size--)
10737         {
10738           char *l = aopGet (right, offset++, FALSE, FALSE);
10739           MOVA (l);
10740           emitcode ("movx", "@dptr,a");
10741           if (size || pi)
10742             emitcode ("inc", "dptr");
10743         }
10744     }
10745   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10746     aopPut (result, "dpl", 0);
10747     aopPut (result, "dph", 1);
10748     pi->generated=1;
10749   }
10750   freeAsmop (result, NULL, ic, TRUE);
10751   freeAsmop (right, NULL, ic, TRUE);
10752 }
10753
10754 /*-----------------------------------------------------------------*/
10755 /* genGenPointerSet - set value from generic pointer space         */
10756 /*-----------------------------------------------------------------*/
10757 static void
10758 genGenPointerSet (operand * right,
10759                   operand * result, iCode * ic, iCode * pi)
10760 {
10761   int size, offset;
10762   sym_link *retype = getSpec (operandType (right));
10763   sym_link *letype = getSpec (operandType (result));
10764
10765   D (emitcode (";", "genGenPointerSet"));
10766
10767   aopOp (result, ic, FALSE);
10768   loadDptrFromOperand (result, TRUE);
10769
10770   /* so dptr now contains the address */
10771   aopOp (right, ic, FALSE);
10772
10773   /* if bit then unpack */
10774   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10775     {
10776       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10777     }
10778   else
10779     {
10780       size = AOP_SIZE (right);
10781       offset = 0;
10782
10783       while (size--)
10784         {
10785           char *l = aopGet (right, offset++, FALSE, FALSE);
10786           MOVA (l);
10787           emitcode ("lcall", "__gptrput");
10788           if (size || pi)
10789             emitcode ("inc", "dptr");
10790         }
10791     }
10792
10793   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10794     aopPut (result, "dpl", 0);
10795     aopPut (result, "dph", 1);
10796     pi->generated=1;
10797   }
10798   freeAsmop (result, NULL, ic, TRUE);
10799   freeAsmop (right, NULL, ic, TRUE);
10800 }
10801
10802 /*-----------------------------------------------------------------*/
10803 /* genPointerSet - stores the value into a pointer location        */
10804 /*-----------------------------------------------------------------*/
10805 static void
10806 genPointerSet (iCode * ic, iCode *pi)
10807 {
10808   operand *right, *result;
10809   sym_link *type, *etype;
10810   int p_type;
10811
10812   D (emitcode (";", "genPointerSet"));
10813
10814   right = IC_RIGHT (ic);
10815   result = IC_RESULT (ic);
10816
10817   /* depending on the type of pointer we need to
10818      move it to the correct pointer register */
10819   type = operandType (result);
10820   etype = getSpec (type);
10821   /* if left is of type of pointer then it is simple */
10822   if (IS_PTR (type) && !IS_FUNC (type->next))
10823     {
10824       p_type = DCL_TYPE (type);
10825     }
10826   else
10827     {
10828       /* we have to go by the storage class */
10829       p_type = PTR_TYPE (SPEC_OCLS (etype));
10830     }
10831
10832   /* special case when cast remat */
10833   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10834       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10835           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10836           type = operandType (result);
10837           p_type = DCL_TYPE (type);
10838   }
10839
10840   /* now that we have the pointer type we assign
10841      the pointer values */
10842   switch (p_type)
10843     {
10844
10845     case POINTER:
10846     case IPOINTER:
10847       genNearPointerSet (right, result, ic, pi);
10848       break;
10849
10850     case PPOINTER:
10851       genPagedPointerSet (right, result, ic, pi);
10852       break;
10853
10854     case FPOINTER:
10855       genFarPointerSet (right, result, ic, pi);
10856       break;
10857
10858     case GPOINTER:
10859       genGenPointerSet (right, result, ic, pi);
10860       break;
10861
10862     default:
10863       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10864               "genPointerSet: illegal pointer type");
10865     }
10866 }
10867
10868 /*-----------------------------------------------------------------*/
10869 /* genIfx - generate code for Ifx statement                        */
10870 /*-----------------------------------------------------------------*/
10871 static void
10872 genIfx (iCode * ic, iCode * popIc)
10873 {
10874   operand *cond = IC_COND (ic);
10875   int isbit = 0;
10876   char *dup = NULL;
10877
10878   D (emitcode (";", "genIfx"));
10879
10880   aopOp (cond, ic, FALSE);
10881
10882   /* get the value into acc */
10883   if (AOP_TYPE (cond) != AOP_CRY)
10884     {
10885       toBoolean (cond);
10886     }
10887   else
10888     {
10889       isbit = 1;
10890       if (AOP(cond)->aopu.aop_dir)
10891         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10892     }
10893
10894   /* the result is now in the accumulator or a directly addressable bit */
10895   freeAsmop (cond, NULL, ic, TRUE);
10896
10897   /* if there was something to be popped then do it */
10898   if (popIc)
10899     genIpop (popIc);
10900
10901   /* if the condition is a bit variable */
10902   if (isbit && dup)
10903     genIfxJump(ic, dup, NULL, NULL, NULL);
10904   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10905     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10906   else if (isbit && !IS_ITEMP (cond))
10907     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10908   else
10909     genIfxJump (ic, "a", NULL, NULL, NULL);
10910
10911   ic->generated = 1;
10912 }
10913
10914 /*-----------------------------------------------------------------*/
10915 /* genAddrOf - generates code for address of                       */
10916 /*-----------------------------------------------------------------*/
10917 static void
10918 genAddrOf (iCode * ic)
10919 {
10920   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10921   int size, offset;
10922
10923   D (emitcode (";", "genAddrOf"));
10924
10925   aopOp (IC_RESULT (ic), ic, FALSE);
10926
10927   /* if the operand is on the stack then we
10928      need to get the stack offset of this
10929      variable */
10930   if (sym->onStack)
10931     {
10932       /* if it has an offset then we need to compute it */
10933       if (sym->stack)
10934         {
10935           int stack_offset = ((sym->stack < 0) ?
10936                               ((char) (sym->stack - _G.nRegsSaved)) :
10937                               ((char) sym->stack)) & 0xff;
10938           if ((abs(stack_offset) == 1) &&
10939               !AOP_NEEDSACC(IC_RESULT (ic)) &&
10940               !isOperandVolatile (IC_RESULT (ic), FALSE))
10941             {
10942               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10943               if (stack_offset > 0)
10944                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10945               else
10946                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10947             }
10948           else
10949             {
10950               emitcode ("mov", "a,%s", SYM_BP (sym));
10951               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
10952               aopPut (IC_RESULT (ic), "a", 0);
10953             }
10954         }
10955       else
10956         {
10957           /* we can just move _bp */
10958           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10959         }
10960       /* fill the result with zero */
10961       size = AOP_SIZE (IC_RESULT (ic)) - 1;
10962
10963       offset = 1;
10964       while (size--)
10965         {
10966           aopPut (IC_RESULT (ic), zero, offset++);
10967         }
10968       goto release;
10969     }
10970
10971   /* object not on stack then we need the name */
10972   size = AOP_SIZE (IC_RESULT (ic));
10973   offset = 0;
10974
10975   while (size--)
10976     {
10977       char s[SDCC_NAME_MAX];
10978       if (offset)
10979         sprintf (s, "#(%s >> %d)",
10980                  sym->rname,
10981                  offset * 8);
10982       else
10983         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
10984       aopPut (IC_RESULT (ic), s, offset++);
10985     }
10986
10987 release:
10988   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
10989
10990 }
10991
10992 /*-----------------------------------------------------------------*/
10993 /* genFarFarAssign - assignment when both are in far space         */
10994 /*-----------------------------------------------------------------*/
10995 static void
10996 genFarFarAssign (operand * result, operand * right, iCode * ic)
10997 {
10998   int size = AOP_SIZE (right);
10999   int offset = 0;
11000   char *l;
11001
11002   D (emitcode (";", "genFarFarAssign"));
11003
11004   /* first push the right side on to the stack */
11005   while (size--)
11006     {
11007       l = aopGet (right, offset++, FALSE, FALSE);
11008       MOVA (l);
11009       emitcode ("push", "acc");
11010     }
11011
11012   freeAsmop (right, NULL, ic, FALSE);
11013   /* now assign DPTR to result */
11014   aopOp (result, ic, FALSE);
11015   size = AOP_SIZE (result);
11016   while (size--)
11017     {
11018       emitcode ("pop", "acc");
11019       aopPut (result, "a", --offset);
11020     }
11021   freeAsmop (result, NULL, ic, FALSE);
11022 }
11023
11024 /*-----------------------------------------------------------------*/
11025 /* genAssign - generate code for assignment                        */
11026 /*-----------------------------------------------------------------*/
11027 static void
11028 genAssign (iCode * ic)
11029 {
11030   operand *result, *right;
11031   int size, offset;
11032   unsigned long lit = 0L;
11033
11034   D (emitcode (";", "genAssign"));
11035
11036   result = IC_RESULT (ic);
11037   right = IC_RIGHT (ic);
11038
11039   /* if they are the same */
11040   if (operandsEqu (result, right) &&
11041       !isOperandVolatile (result, FALSE) &&
11042       !isOperandVolatile (right, FALSE))
11043     return;
11044
11045   aopOp (right, ic, FALSE);
11046
11047   /* special case both in far space */
11048   if (AOP_TYPE (right) == AOP_DPTR &&
11049       IS_TRUE_SYMOP (result) &&
11050       isOperandInFarSpace (result))
11051     {
11052       genFarFarAssign (result, right, ic);
11053       return;
11054     }
11055
11056   aopOp (result, ic, TRUE);
11057
11058   /* if they are the same registers */
11059   if (sameRegs (AOP (right), AOP (result)) &&
11060       !isOperandVolatile (result, FALSE) &&
11061       !isOperandVolatile (right, FALSE))
11062     goto release;
11063
11064   /* if the result is a bit */
11065   if (AOP_TYPE (result) == AOP_CRY)
11066     {
11067       /* if the right size is a literal then
11068          we know what the value is */
11069       if (AOP_TYPE (right) == AOP_LIT)
11070         {
11071           if (((int) operandLitValue (right)))
11072             aopPut (result, one, 0);
11073           else
11074             aopPut (result, zero, 0);
11075           goto release;
11076         }
11077
11078       /* the right is also a bit variable */
11079       if (AOP_TYPE (right) == AOP_CRY)
11080         {
11081           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
11082           aopPut (result, "c", 0);
11083           goto release;
11084         }
11085
11086       /* we need to or */
11087       toBoolean (right);
11088       aopPut (result, "a", 0);
11089       goto release;
11090     }
11091
11092   /* bit variables done */
11093   /* general case */
11094   size = AOP_SIZE (result);
11095   offset = 0;
11096   if (AOP_TYPE (right) == AOP_LIT)
11097     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11098
11099   if ((size > 1) &&
11100       (AOP_TYPE (result) != AOP_REG) &&
11101       (AOP_TYPE (right) == AOP_LIT) &&
11102       !IS_FLOAT (operandType (right)) &&
11103       (lit < 256L))
11104     {
11105       while ((size) && (lit))
11106         {
11107           aopPut (result,
11108                   aopGet (right, offset, FALSE, FALSE),
11109                   offset);
11110           lit >>= 8;
11111           offset++;
11112           size--;
11113         }
11114       /* And now fill the rest with zeros. */
11115       if (size)
11116         {
11117           emitcode ("clr", "a");
11118         }
11119       while (size--)
11120         {
11121           aopPut (result, "a", offset);
11122           offset++;
11123         }
11124     }
11125   else
11126     {
11127       while (size--)
11128         {
11129           aopPut (result,
11130                   aopGet (right, offset, FALSE, FALSE),
11131                   offset);
11132           offset++;
11133         }
11134     }
11135
11136 release:
11137   freeAsmop (result, NULL, ic, TRUE);
11138   freeAsmop (right, NULL, ic, TRUE);
11139 }
11140
11141 /*-----------------------------------------------------------------*/
11142 /* genJumpTab - generates code for jump table                      */
11143 /*-----------------------------------------------------------------*/
11144 static void
11145 genJumpTab (iCode * ic)
11146 {
11147   symbol *jtab,*jtablo,*jtabhi;
11148   char *l;
11149   unsigned int count;
11150
11151   D (emitcode (";", "genJumpTab"));
11152
11153   count = elementsInSet( IC_JTLABELS (ic) );
11154
11155   if( count <= 16 )
11156     {
11157       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11158          if the switch argument is in a register.
11159          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11160       /* Peephole may not convert ljmp to sjmp or ret
11161          labelIsReturnOnly & labelInRange must check
11162          currPl->ic->op != JUMPTABLE */
11163       aopOp (IC_JTCOND (ic), ic, FALSE);
11164       /* get the condition into accumulator */
11165       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11166       MOVA (l);
11167       /* multiply by three */
11168       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11169         {
11170           emitcode ("mov", "b,#3");
11171           emitcode ("mul", "ab");
11172         }
11173       else
11174         {
11175           emitcode ("add", "a,acc");
11176           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11177         }
11178       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11179
11180       jtab = newiTempLabel (NULL);
11181       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11182       emitcode ("jmp", "@a+dptr");
11183       emitLabel (jtab);
11184       /* now generate the jump labels */
11185       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11186            jtab = setNextItem (IC_JTLABELS (ic)))
11187         emitcode ("ljmp", "%05d$", jtab->key + 100);
11188     }
11189   else
11190     {
11191       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11192          if the switch argument is in a register.
11193          For n>6 this algorithm may be more compact */
11194       jtablo = newiTempLabel (NULL);
11195       jtabhi = newiTempLabel (NULL);
11196
11197       /* get the condition into accumulator.
11198          Using b as temporary storage, if register push/pop is needed */
11199       aopOp (IC_JTCOND (ic), ic, FALSE);
11200       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11201       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11202           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11203         {
11204           // (MB) what if B is in use???
11205           wassertl(!BINUSE, "B was in use");
11206           emitcode ("mov", "b,%s", l);
11207           l = "b";
11208         }
11209       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11210       MOVA (l);
11211       if( count <= 112 )
11212         {
11213           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11214           emitcode ("movc", "a,@a+pc");
11215           emitcode ("push", "acc");
11216
11217           MOVA (l);
11218           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11219           emitcode ("movc", "a,@a+pc");
11220           emitcode ("push", "acc");
11221         }
11222       else
11223         {
11224           /* this scales up to n<=255, but needs two more bytes
11225              and changes dptr */
11226           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11227           emitcode ("movc", "a,@a+dptr");
11228           emitcode ("push", "acc");
11229
11230           MOVA (l);
11231           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11232           emitcode ("movc", "a,@a+dptr");
11233           emitcode ("push", "acc");
11234         }
11235
11236       emitcode ("ret", "");
11237
11238       /* now generate jump table, LSB */
11239       emitLabel (jtablo);
11240       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11241            jtab = setNextItem (IC_JTLABELS (ic)))
11242         emitcode (".db", "%05d$", jtab->key + 100);
11243
11244       /* now generate jump table, MSB */
11245       emitLabel (jtabhi);
11246       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11247            jtab = setNextItem (IC_JTLABELS (ic)))
11248          emitcode (".db", "%05d$>>8", jtab->key + 100);
11249     }
11250 }
11251
11252 /*-----------------------------------------------------------------*/
11253 /* genCast - gen code for casting                                  */
11254 /*-----------------------------------------------------------------*/
11255 static void
11256 genCast (iCode * ic)
11257 {
11258   operand *result = IC_RESULT (ic);
11259   sym_link *ctype = operandType (IC_LEFT (ic));
11260   sym_link *rtype = operandType (IC_RIGHT (ic));
11261   operand *right = IC_RIGHT (ic);
11262   int size, offset;
11263
11264   D (emitcode (";", "genCast"));
11265
11266   /* if they are equivalent then do nothing */
11267   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11268     return;
11269
11270   aopOp (right, ic, FALSE);
11271   aopOp (result, ic, FALSE);
11272
11273   /* if the result is a bit (and not a bitfield) */
11274   if (IS_BIT (OP_SYMBOL (result)->type))
11275     {
11276       /* if the right size is a literal then
11277          we know what the value is */
11278       if (AOP_TYPE (right) == AOP_LIT)
11279         {
11280           if (((int) operandLitValue (right)))
11281             aopPut (result, one, 0);
11282           else
11283             aopPut (result, zero, 0);
11284
11285           goto release;
11286         }
11287
11288       /* the right is also a bit variable */
11289       if (AOP_TYPE (right) == AOP_CRY)
11290         {
11291           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
11292           aopPut (result, "c", 0);
11293           goto release;
11294         }
11295
11296       /* we need to or */
11297       toBoolean (right);
11298       aopPut (result, "a", 0);
11299       goto release;
11300     }
11301
11302   /* if they are the same size : or less */
11303   if (AOP_SIZE (result) <= AOP_SIZE (right))
11304     {
11305
11306       /* if they are in the same place */
11307       if (sameRegs (AOP (right), AOP (result)))
11308         goto release;
11309
11310       /* if they in different places then copy */
11311       size = AOP_SIZE (result);
11312       offset = 0;
11313       while (size--)
11314         {
11315           aopPut (result,
11316                   aopGet (right, offset, FALSE, FALSE),
11317                   offset);
11318           offset++;
11319         }
11320       goto release;
11321     }
11322
11323   /* if the result is of type pointer */
11324   if (IS_PTR (ctype))
11325     {
11326
11327       int p_type;
11328       sym_link *type = operandType (right);
11329       sym_link *etype = getSpec (type);
11330
11331       /* pointer to generic pointer */
11332       if (IS_GENPTR (ctype))
11333         {
11334           if (IS_PTR (type))
11335             {
11336               p_type = DCL_TYPE (type);
11337             }
11338           else
11339             {
11340               if (SPEC_SCLS(etype)==S_REGISTER) {
11341                 // let's assume it is a generic pointer
11342                 p_type=GPOINTER;
11343               } else {
11344                 /* we have to go by the storage class */
11345                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11346               }
11347             }
11348
11349           /* the first two bytes are known */
11350           size = GPTRSIZE - 1;
11351           offset = 0;
11352           while (size--)
11353             {
11354               aopPut (result,
11355                       aopGet (right, offset, FALSE, FALSE),
11356                       offset);
11357               offset++;
11358             }
11359           /* the last byte depending on type */
11360             {
11361                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11362                 char gpValStr[10];
11363
11364                 if (gpVal == -1)
11365                 {
11366                     // pointerTypeToGPByte will have bitched.
11367                     exit(1);
11368                 }
11369
11370                 sprintf(gpValStr, "#0x%x", gpVal);
11371                 aopPut (result, gpValStr, GPTRSIZE - 1);
11372             }
11373           goto release;
11374         }
11375
11376       /* just copy the pointers */
11377       size = AOP_SIZE (result);
11378       offset = 0;
11379       while (size--)
11380         {
11381           aopPut (result,
11382                   aopGet (right, offset, FALSE, FALSE),
11383                   offset);
11384           offset++;
11385         }
11386       goto release;
11387     }
11388
11389   /* so we now know that the size of destination is greater
11390      than the size of the source */
11391   /* we move to result for the size of source */
11392   size = AOP_SIZE (right);
11393   offset = 0;
11394   while (size--)
11395     {
11396       aopPut (result,
11397               aopGet (right, offset, FALSE, FALSE),
11398               offset);
11399       offset++;
11400     }
11401
11402   /* now depending on the sign of the source && destination */
11403   size = AOP_SIZE (result) - AOP_SIZE (right);
11404   /* if unsigned or not an integral type */
11405   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11406     {
11407       while (size--)
11408         aopPut (result, zero, offset++);
11409     }
11410   else
11411     {
11412       /* we need to extend the sign :{ */
11413       char *l = aopGet (right, AOP_SIZE (right) - 1,
11414                         FALSE, FALSE);
11415       MOVA (l);
11416       emitcode ("rlc", "a");
11417       emitcode ("subb", "a,acc");
11418       while (size--)
11419         aopPut (result, "a", offset++);
11420     }
11421
11422   /* we are done hurray !!!! */
11423
11424 release:
11425   freeAsmop (result, NULL, ic, TRUE);
11426   freeAsmop (right, NULL, ic, TRUE);
11427 }
11428
11429 /*-----------------------------------------------------------------*/
11430 /* genDjnz - generate decrement & jump if not zero instrucion      */
11431 /*-----------------------------------------------------------------*/
11432 static int
11433 genDjnz (iCode * ic, iCode * ifx)
11434 {
11435   symbol *lbl, *lbl1;
11436   if (!ifx)
11437     return 0;
11438
11439   /* if the if condition has a false label
11440      then we cannot save */
11441   if (IC_FALSE (ifx))
11442     return 0;
11443
11444   /* if the minus is not of the form a = a - 1 */
11445   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11446       !IS_OP_LITERAL (IC_RIGHT (ic)))
11447     return 0;
11448
11449   if (operandLitValue (IC_RIGHT (ic)) != 1)
11450     return 0;
11451
11452   /* if the size of this greater than one then no
11453      saving */
11454   if (getSize (operandType (IC_RESULT (ic))) > 1)
11455     return 0;
11456
11457   /* otherwise we can save BIG */
11458
11459   D (emitcode (";", "genDjnz"));
11460
11461   lbl = newiTempLabel (NULL);
11462   lbl1 = newiTempLabel (NULL);
11463
11464   aopOp (IC_RESULT (ic), ic, FALSE);
11465
11466   if (AOP_NEEDSACC(IC_RESULT(ic)))
11467   {
11468       /* If the result is accessed indirectly via
11469        * the accumulator, we must explicitly write
11470        * it back after the decrement.
11471        */
11472       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11473
11474       if (strcmp(rByte, "a"))
11475       {
11476            /* Something is hopelessly wrong */
11477            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11478                    __FILE__, __LINE__);
11479            /* We can just give up; the generated code will be inefficient,
11480             * but what the hey.
11481             */
11482            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11483            return 0;
11484       }
11485       emitcode ("dec", "%s", rByte);
11486       aopPut (IC_RESULT (ic), rByte, 0);
11487       emitcode ("jnz", "%05d$", lbl->key + 100);
11488   }
11489   else if (IS_AOP_PREG (IC_RESULT (ic)))
11490     {
11491       emitcode ("dec", "%s",
11492                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11493       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11494       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11495       ifx->generated = 1;
11496       emitcode ("jnz", "%05d$", lbl->key + 100);
11497     }
11498   else
11499     {
11500       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11501                 lbl->key + 100);
11502     }
11503   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11504   emitLabel (lbl);
11505   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11506   emitLabel (lbl1);
11507
11508   if (!ifx->generated)
11509       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11510   ifx->generated = 1;
11511   return 1;
11512 }
11513
11514 /*-----------------------------------------------------------------*/
11515 /* genReceive - generate code for a receive iCode                  */
11516 /*-----------------------------------------------------------------*/
11517 static void
11518 genReceive (iCode * ic)
11519 {
11520   int size = getSize (operandType (IC_RESULT (ic)));
11521   int offset = 0;
11522
11523   D (emitcode (";", "genReceive"));
11524
11525   if (ic->argreg == 1)
11526     { /* first parameter */
11527       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11528            isOperandInPagedSpace (IC_RESULT (ic))) &&
11529           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11530            IS_TRUE_SYMOP (IC_RESULT (ic))))
11531         {
11532           regs *tempRegs[4];
11533           int receivingA = 0;
11534           int roffset = 0;
11535
11536           for (offset = 0; offset<size; offset++)
11537             if (!strcmp (fReturn[offset], "a"))
11538               receivingA = 1;
11539
11540           if (!receivingA)
11541             {
11542               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11543                 {
11544                   for (offset = size-1; offset>0; offset--)
11545                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11546                   emitcode("mov","a,%s", fReturn[0]);
11547                   _G.accInUse++;
11548                   aopOp (IC_RESULT (ic), ic, FALSE);
11549                   _G.accInUse--;
11550                   aopPut (IC_RESULT (ic), "a", offset);
11551                   for (offset = 1; offset<size; offset++)
11552                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11553                   goto release;
11554                 }
11555             }
11556           else
11557             {
11558               if (getTempRegs(tempRegs, size, ic))
11559                 {
11560                   for (offset = 0; offset<size; offset++)
11561                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11562                   aopOp (IC_RESULT (ic), ic, FALSE);
11563                   for (offset = 0; offset<size; offset++)
11564                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11565                   goto release;
11566                 }
11567             }
11568
11569           offset = fReturnSizeMCS51 - size;
11570           while (size--)
11571             {
11572               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11573                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11574               offset++;
11575             }
11576           aopOp (IC_RESULT (ic), ic, FALSE);
11577           size = AOP_SIZE (IC_RESULT (ic));
11578           offset = 0;
11579           while (size--)
11580             {
11581               emitcode ("pop", "acc");
11582               aopPut (IC_RESULT (ic), "a", offset++);
11583             }
11584         }
11585       else
11586         {
11587           _G.accInUse++;
11588           aopOp (IC_RESULT (ic), ic, FALSE);
11589           _G.accInUse--;
11590           assignResultValue (IC_RESULT (ic), NULL);
11591         }
11592     }
11593   else if (ic->argreg > 12)
11594     { /* bit parameters */
11595       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11596         {
11597           aopOp (IC_RESULT (ic), ic, FALSE);
11598           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11599           outBitC(IC_RESULT (ic));
11600         }
11601     }
11602   else
11603     { /* other parameters */
11604       int rb1off ;
11605       aopOp (IC_RESULT (ic), ic, FALSE);
11606       rb1off = ic->argreg;
11607       while (size--)
11608         {
11609           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11610         }
11611     }
11612
11613 release:
11614   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11615 }
11616
11617 /*-----------------------------------------------------------------*/
11618 /* genDummyRead - generate code for dummy read of volatiles        */
11619 /*-----------------------------------------------------------------*/
11620 static void
11621 genDummyRead (iCode * ic)
11622 {
11623   operand *op;
11624   int size, offset;
11625
11626   D (emitcode(";", "genDummyRead"));
11627
11628   op = IC_RIGHT (ic);
11629   if (op && IS_SYMOP (op))
11630     {
11631       aopOp (op, ic, FALSE);
11632
11633       /* if the result is a bit */
11634       if (AOP_TYPE (op) == AOP_CRY)
11635         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11636       else
11637         {
11638           /* bit variables done */
11639           /* general case */
11640           size = AOP_SIZE (op);
11641           offset = 0;
11642           while (size--)
11643           {
11644             MOVA (aopGet (op, offset, FALSE, FALSE));
11645             offset++;
11646           }
11647         }
11648
11649       freeAsmop (op, NULL, ic, TRUE);
11650     }
11651
11652   op = IC_LEFT (ic);
11653   if (op && IS_SYMOP (op))
11654     {
11655       aopOp (op, ic, FALSE);
11656
11657       /* if the result is a bit */
11658       if (AOP_TYPE (op) == AOP_CRY)
11659         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11660       else
11661         {
11662           /* bit variables done */
11663           /* general case */
11664           size = AOP_SIZE (op);
11665           offset = 0;
11666           while (size--)
11667           {
11668             MOVA (aopGet (op, offset, FALSE, FALSE));
11669             offset++;
11670           }
11671         }
11672
11673       freeAsmop (op, NULL, ic, TRUE);
11674     }
11675 }
11676
11677 /*-----------------------------------------------------------------*/
11678 /* genCritical - generate code for start of a critical sequence    */
11679 /*-----------------------------------------------------------------*/
11680 static void
11681 genCritical (iCode *ic)
11682 {
11683   symbol *tlbl = newiTempLabel (NULL);
11684
11685   D (emitcode(";", "genCritical"));
11686
11687   if (IC_RESULT (ic))
11688     {
11689       aopOp (IC_RESULT (ic), ic, TRUE);
11690       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11691       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11692       aopPut (IC_RESULT (ic), zero, 0);
11693       emitLabel (tlbl);
11694       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11695     }
11696   else
11697     {
11698       emitcode ("setb", "c");
11699       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11700       emitcode ("clr", "c");
11701       emitLabel (tlbl);
11702       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11703     }
11704 }
11705
11706 /*-----------------------------------------------------------------*/
11707 /* genEndCritical - generate code for end of a critical sequence   */
11708 /*-----------------------------------------------------------------*/
11709 static void
11710 genEndCritical (iCode *ic)
11711 {
11712   D(emitcode(";     genEndCritical",""));
11713
11714   if (IC_RIGHT (ic))
11715     {
11716       aopOp (IC_RIGHT (ic), ic, FALSE);
11717       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11718         {
11719           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11720           emitcode ("mov", "ea,c");
11721         }
11722       else
11723         {
11724           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11725             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11726           emitcode ("rrc", "a");
11727           emitcode ("mov", "ea,c");
11728         }
11729       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11730     }
11731   else
11732     {
11733       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11734       emitcode ("mov", "ea,c");
11735     }
11736 }
11737
11738 /*-----------------------------------------------------------------*/
11739 /* gen51Code - generate code for 8051 based controllers            */
11740 /*-----------------------------------------------------------------*/
11741 void
11742 gen51Code (iCode * lic)
11743 {
11744   iCode *ic;
11745   int cln = 0;
11746   /* int cseq = 0; */
11747
11748   _G.currentFunc = NULL;
11749   lineHead = lineCurr = NULL;
11750
11751   /* print the allocation information */
11752   if (allocInfo && currFunc)
11753     printAllocInfo (currFunc, codeOutBuf);
11754   /* if debug information required */
11755   if (options.debug && currFunc)
11756     {
11757       debugFile->writeFunction (currFunc, lic);
11758     }
11759   /* stack pointer name */
11760   if (options.useXstack)
11761     spname = "_spx";
11762   else
11763     spname = "sp";
11764
11765
11766   for (ic = lic; ic; ic = ic->next)
11767     {
11768       _G.current_iCode = ic;
11769
11770       if (ic->lineno && cln != ic->lineno)
11771         {
11772           if (options.debug)
11773             {
11774               debugFile->writeCLine (ic);
11775             }
11776           if (!options.noCcodeInAsm) {
11777             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
11778                       printCLine(ic->filename, ic->lineno));
11779           }
11780           cln = ic->lineno;
11781         }
11782       #if 0
11783       if (ic->seqPoint && ic->seqPoint != cseq)
11784         {
11785           emitcode ("", "; sequence point %d", ic->seqPoint);
11786           cseq = ic->seqPoint;
11787         }
11788       #endif
11789       if (options.iCodeInAsm) {
11790         char regsInUse[80];
11791         int i;
11792         char *iLine;
11793
11794         #if 0
11795         for (i=0; i<8; i++) {
11796           sprintf (&regsInUse[i],
11797                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11798         regsInUse[i]=0;
11799         #else
11800         strcpy (regsInUse, "--------");
11801         for (i=0; i < 8; i++) {
11802           if (bitVectBitValue (ic->rMask, i))
11803             {
11804               int offset = regs8051[i].offset;
11805               regsInUse[offset] = offset + '0'; /* show rMask */
11806             }
11807         #endif
11808         }
11809         iLine = printILine(ic);
11810         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11811         dbuf_free(iLine);
11812       }
11813       /* if the result is marked as
11814          spilt and rematerializable or code for
11815          this has already been generated then
11816          do nothing */
11817       if (resultRemat (ic) || ic->generated)
11818         continue;
11819
11820       /* depending on the operation */
11821       switch (ic->op)
11822         {
11823         case '!':
11824           genNot (ic);
11825           break;
11826
11827         case '~':
11828           genCpl (ic);
11829           break;
11830
11831         case UNARYMINUS:
11832           genUminus (ic);
11833           break;
11834
11835         case IPUSH:
11836           genIpush (ic);
11837           break;
11838
11839         case IPOP:
11840           /* IPOP happens only when trying to restore a
11841              spilt live range, if there is an ifx statement
11842              following this pop then the if statement might
11843              be using some of the registers being popped which
11844              would destory the contents of the register so
11845              we need to check for this condition and handle it */
11846           if (ic->next &&
11847               ic->next->op == IFX &&
11848               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11849             genIfx (ic->next, ic);
11850           else
11851             genIpop (ic);
11852           break;
11853
11854         case CALL:
11855           genCall (ic);
11856           break;
11857
11858         case PCALL:
11859           genPcall (ic);
11860           break;
11861
11862         case FUNCTION:
11863           genFunction (ic);
11864           break;
11865
11866         case ENDFUNCTION:
11867           genEndFunction (ic);
11868           break;
11869
11870         case RETURN:
11871           genRet (ic);
11872           break;
11873
11874         case LABEL:
11875           genLabel (ic);
11876           break;
11877
11878         case GOTO:
11879           genGoto (ic);
11880           break;
11881
11882         case '+':
11883           genPlus (ic);
11884           break;
11885
11886         case '-':
11887           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11888             genMinus (ic);
11889           break;
11890
11891         case '*':
11892           genMult (ic);
11893           break;
11894
11895         case '/':
11896           genDiv (ic);
11897           break;
11898
11899         case '%':
11900           genMod (ic);
11901           break;
11902
11903         case '>':
11904           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11905           break;
11906
11907         case '<':
11908           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11909           break;
11910
11911         case LE_OP:
11912         case GE_OP:
11913         case NE_OP:
11914
11915           /* note these two are xlated by algebraic equivalence
11916              in decorateType() in SDCCast.c */
11917           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11918                   "got '>=' or '<=' shouldn't have come here");
11919           break;
11920
11921         case EQ_OP:
11922           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11923           break;
11924
11925         case AND_OP:
11926           genAndOp (ic);
11927           break;
11928
11929         case OR_OP:
11930           genOrOp (ic);
11931           break;
11932
11933         case '^':
11934           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11935           break;
11936
11937         case '|':
11938           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11939           break;
11940
11941         case BITWISEAND:
11942           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11943           break;
11944
11945         case INLINEASM:
11946           genInline (ic);
11947           break;
11948
11949         case RRC:
11950           genRRC (ic);
11951           break;
11952
11953         case RLC:
11954           genRLC (ic);
11955           break;
11956
11957         case GETHBIT:
11958           genGetHbit (ic);
11959           break;
11960
11961         case GETABIT:
11962           genGetAbit (ic);
11963           break;
11964
11965         case GETBYTE:
11966           genGetByte (ic);
11967           break;
11968
11969         case GETWORD:
11970           genGetWord (ic);
11971           break;
11972
11973         case LEFT_OP:
11974           genLeftShift (ic);
11975           break;
11976
11977         case RIGHT_OP:
11978           genRightShift (ic);
11979           break;
11980
11981         case GET_VALUE_AT_ADDRESS:
11982           genPointerGet (ic,
11983                          hasInc (IC_LEFT (ic), ic,
11984                                  getSize (operandType (IC_RESULT (ic)))),
11985                          ifxForOp (IC_RESULT (ic), ic) );
11986           break;
11987
11988         case '=':
11989           if (POINTER_SET (ic))
11990             genPointerSet (ic,
11991                            hasInc (IC_RESULT (ic), ic,
11992                                    getSize (operandType (IC_RIGHT (ic)))));
11993           else
11994             genAssign (ic);
11995           break;
11996
11997         case IFX:
11998           genIfx (ic, NULL);
11999           break;
12000
12001         case ADDRESS_OF:
12002           genAddrOf (ic);
12003           break;
12004
12005         case JUMPTABLE:
12006           genJumpTab (ic);
12007           break;
12008
12009         case CAST:
12010           genCast (ic);
12011           break;
12012
12013         case RECEIVE:
12014           genReceive (ic);
12015           break;
12016
12017         case SEND:
12018           addSet (&_G.sendSet, ic);
12019           break;
12020
12021         case DUMMY_READ_VOLATILE:
12022           genDummyRead (ic);
12023           break;
12024
12025         case CRITICAL:
12026           genCritical (ic);
12027           break;
12028
12029         case ENDCRITICAL:
12030           genEndCritical (ic);
12031           break;
12032
12033         case SWAP:
12034           genSwap (ic);
12035           break;
12036
12037         default:
12038           ic = ic;
12039         }
12040     }
12041
12042   _G.current_iCode = NULL;
12043
12044   /* now we are ready to call the
12045      peep hole optimizer */
12046   if (!options.nopeep)
12047     peepHole (&lineHead);
12048
12049   /* now do the actual printing */
12050   printLine (lineHead, codeOutBuf);
12051   return;
12052 }