* src/mcs51/gen.c, src/avr/gen.c, src/pic/gen.c, src/z80/gen.c,
[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) do if (options.verboseAsm) {x;} while(0)
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include "SDCCglobl.h"
38 #include "newalloc.h"
39
40 #include "common.h"
41 #include "SDCCpeeph.h"
42 #include "ralloc.h"
43 #include "rtrack.h"
44 #include "gen.h"
45 #include "dbuf_string.h"
46
47 char *aopLiteral (value * val, int offset);
48 char *aopLiteralLong (value * val, int offset, int size);
49 extern int allocInfo;
50
51 /* this is the down and dirty file with all kinds of
52    kludgy & hacky stuff. This is what it is all about
53    CODE GENERATION for a specific MCU . some of the
54    routines may be reusable, will have to see */
55
56 static char *zero = "#0x00";
57 static char *one = "#0x01";
58 static char *spname;
59
60 char *fReturn8051[] =
61 {"dpl", "dph", "b", "a"};
62 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
63 char **fReturn = fReturn8051;
64 static char *accUse[] =
65 {"a", "b"};
66
67 static unsigned short rbank = -1;
68
69 #define REG_WITH_INDEX   mcs51_regWithIdx
70
71 #define AOP(op) op->aop
72 #define AOP_TYPE(op) AOP(op)->type
73 #define AOP_SIZE(op) AOP(op)->size
74 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
75                         AOP_TYPE(x) == AOP_R0))
76
77 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
78                          AOP_TYPE(x) == AOP_DPTR || \
79                          AOP(x)->paged))
80
81 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
82                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
83                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
84
85 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
86
87 #define R0INB   _G.bu.bs.r0InB
88 #define R1INB   _G.bu.bs.r1InB
89 #define OPINB   _G.bu.bs.OpInB
90 #define BINUSE  _G.bu.BInUse
91
92 static struct
93   {
94     short r0Pushed;
95     short r1Pushed;
96     union
97       {
98         struct
99           {
100             short r0InB : 2;//2 so we can see it overflow
101             short r1InB : 2;//2 so we can see it overflow
102             short OpInB : 2;//2 so we can see it overflow
103           } bs;
104         short BInUse;
105       } bu;
106     short accInUse;
107     short inLine;
108     short debugLine;
109     short nRegsSaved;
110     set *sendSet;
111     iCode *current_iCode;
112     symbol *currentFunc;
113   }
114 _G;
115
116 static char *rb1regs[] = {
117     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
118     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
119 };
120
121 extern struct dbuf_s *codeOutBuf;
122
123 #define RESULTONSTACK(x) \
124                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
125                          IC_RESULT(x)->aop->type == AOP_STK )
126
127 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
128 #define MOVB(x)  movb(x)
129
130 #define CLRC     emitcode("clr","c")
131 #define SETC     emitcode("setb","c")
132
133 static lineNode *lineHead = NULL;
134 static lineNode *lineCurr = NULL;
135
136 static unsigned char SLMask[] =
137 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
138  0xE0, 0xC0, 0x80, 0x00};
139 static unsigned char SRMask[] =
140 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
141  0x07, 0x03, 0x01, 0x00};
142
143 #define LSB     0
144 #define MSB16   1
145 #define MSB24   2
146 #define MSB32   3
147
148 /*-----------------------------------------------------------------*/
149 /* emitcode - writes the code into a file : for now it is simple    */
150 /*-----------------------------------------------------------------*/
151 void
152 emitcode (const char *inst, const char *fmt,...)
153 {
154   va_list ap;
155   struct dbuf_s dbuf;
156   const char *lbp, *lb;
157
158   dbuf_init (&dbuf, INITIAL_INLINEASM);
159
160   va_start (ap, fmt);
161
162   if (inst && *inst)
163     {
164       dbuf_append_str (&dbuf, inst);
165
166       if (fmt && *fmt)
167         {
168           dbuf_append_char (&dbuf, '\t');
169           dbuf_tvprintf (&dbuf, fmt, ap);
170         }
171     }
172   else
173     {
174       dbuf_tvprintf (&dbuf, fmt, ap);
175     }
176
177   lbp = lb = dbuf_c_str(&dbuf);
178
179   while (isspace ((unsigned char)*lbp))
180     {
181       lbp++;
182     }
183
184   if (lbp)
185     {
186       rtrackUpdate (lbp);
187
188       lineCurr = (lineCurr ?
189                   connectLine (lineCurr, newLineNode (lb)) :
190                   (lineHead = newLineNode (lb)));
191
192       lineCurr->isInline = _G.inLine;
193       lineCurr->isDebug = _G.debugLine;
194       lineCurr->ic = _G.current_iCode;
195       lineCurr->isComment = (*lbp==';');
196     }
197
198   va_end (ap);
199
200   dbuf_destroy(&dbuf);
201 }
202
203 static void
204 emitLabel (symbol *tlbl)
205 {
206   emitcode ("", "%05d$:", tlbl->key + 100);
207   lineCurr->isLabel = 1;
208 }
209
210 /*-----------------------------------------------------------------*/
211 /* mcs51_emitDebuggerSymbol - associate the current code location  */
212 /*   with a debugger symbol                                        */
213 /*-----------------------------------------------------------------*/
214 void
215 mcs51_emitDebuggerSymbol (char * debugSym)
216 {
217   _G.debugLine = 1;
218   emitcode ("", "%s ==.", debugSym);
219   _G.debugLine = 0;
220 }
221
222 /*-----------------------------------------------------------------*/
223 /* mova - moves specified value into accumulator                   */
224 /*-----------------------------------------------------------------*/
225 static void
226 mova (const char *x)
227 {
228   /* do some early peephole optimization */
229   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
230     return;
231
232   /* if it is a literal mov try to get it cheaper */
233   if (*x == '#' &&
234       rtrackMoveALit(x))
235     return;
236
237   emitcode("mov", "a,%s", x);
238 }
239
240 /*-----------------------------------------------------------------*/
241 /* movb - moves specified value into register b                    */
242 /*-----------------------------------------------------------------*/
243 static void
244 movb (const char *x)
245 {
246   /* do some early peephole optimization */
247   if (!strncmp(x, "b", 2))
248     return;
249
250   /* if it is a literal mov try to get it cheaper */
251   if (*x == '#')
252     {
253       emitcode("mov","b,%s", rtrackGetLit(x));
254       return;
255     }
256
257   emitcode("mov","b,%s", x);
258 }
259
260 /*-----------------------------------------------------------------*/
261 /* pushB - saves register B if necessary                           */
262 /*-----------------------------------------------------------------*/
263 static bool
264 pushB (void)
265 {
266   bool pushedB = FALSE;
267
268   if (BINUSE)
269     {
270       emitcode ("push", "b");
271 //    printf("B was in use !\n");
272       pushedB = TRUE;
273     }
274   else
275     {
276       OPINB++;
277     }
278   return pushedB;
279 }
280
281 /*-----------------------------------------------------------------*/
282 /* popB - restores value of register B if necessary                */
283 /*-----------------------------------------------------------------*/
284 static void
285 popB (bool pushedB)
286 {
287   if (pushedB)
288     {
289       emitcode ("pop", "b");
290     }
291   else
292     {
293       OPINB--;
294     }
295 }
296
297 /*-----------------------------------------------------------------*/
298 /* pushReg - saves register                                        */
299 /*-----------------------------------------------------------------*/
300 static bool
301 pushReg (int index, bool bits_pushed)
302 {
303   regs * reg = REG_WITH_INDEX (index);
304   if (reg->type == REG_BIT)
305     {
306       if (!bits_pushed)
307         emitcode ("push", "%s", reg->base);
308       return TRUE;
309     }
310   else
311     emitcode ("push", "%s", reg->dname);
312   return bits_pushed;
313 }
314
315 /*-----------------------------------------------------------------*/
316 /* popReg - restores register                                      */
317 /*-----------------------------------------------------------------*/
318 static bool
319 popReg (int index, bool bits_popped)
320 {
321   regs * reg = REG_WITH_INDEX (index);
322   if (reg->type == REG_BIT)
323     {
324       if (!bits_popped)
325         emitcode ("pop", "%s", reg->base);
326       return TRUE;
327     }
328   else
329     emitcode ("pop", "%s", reg->dname);
330   return bits_popped;
331 }
332
333 /*-----------------------------------------------------------------*/
334 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
335 /*-----------------------------------------------------------------*/
336 static regs *
337 getFreePtr (iCode * ic, asmop ** aopp, bool result)
338 {
339   bool r0iu, r1iu;
340   bool r0ou, r1ou;
341
342   /* the logic: if r0 & r1 used in the instruction
343      then we are in trouble otherwise */
344
345   /* first check if r0 & r1 are used by this
346      instruction, in which case we are in trouble */
347   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
348   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
349   if (r0iu && r1iu) {
350       goto endOfWorld;
351     }
352
353   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
354   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
355
356   /* if no usage of r0 then return it */
357   if (!r0iu && !r0ou)
358     {
359       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
360       (*aopp)->type = AOP_R0;
361
362       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
363     }
364
365   /* if no usage of r1 then return it */
366   if (!r1iu && !r1ou)
367     {
368       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
369       (*aopp)->type = AOP_R1;
370
371       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
372     }
373
374   /* now we know they both have usage */
375   /* if r0 not used in this instruction */
376   if (!r0iu)
377     {
378       /* push it if not already pushed */
379       if (ic->op == IPUSH)
380         {
381           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
382           R0INB++;
383         }
384       else if (!_G.r0Pushed)
385         {
386           emitcode ("push", "%s",
387                     REG_WITH_INDEX (R0_IDX)->dname);
388           _G.r0Pushed++;
389         }
390
391       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
392       (*aopp)->type = AOP_R0;
393
394       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
395     }
396
397   /* if r1 not used then */
398
399   if (!r1iu)
400     {
401       /* push it if not already pushed */
402       if (ic->op == IPUSH)
403         {
404           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
405           R1INB++;
406         }
407       else if (!_G.r1Pushed)
408         {
409           emitcode ("push", "%s",
410                     REG_WITH_INDEX (R1_IDX)->dname);
411           _G.r1Pushed++;
412         }
413
414       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
415       (*aopp)->type = AOP_R1;
416       return REG_WITH_INDEX (R1_IDX);
417     }
418
419 endOfWorld:
420   /* I said end of world, but not quite end of world yet */
421   /* if this is a result then we can push it on the stack */
422   if (result)
423     {
424       (*aopp)->type = AOP_STK;
425       return NULL;
426     }
427   /* in the case that result AND left AND right needs a pointer reg
428      we can safely use the result's */
429   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
430     {
431       (*aopp)->type = AOP_R0;
432       return REG_WITH_INDEX (R0_IDX);
433     }
434   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
435     {
436       (*aopp)->type = AOP_R1;
437       return REG_WITH_INDEX (R1_IDX);
438     }
439
440   /* now this is REALLY the end of the world */
441   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
442           "getFreePtr should never reach here");
443   exit (1);
444 }
445
446
447 /*-----------------------------------------------------------------*/
448 /* getTempRegs - initialize an array of pointers to GPR registers */
449 /*               that are not in use. Returns 1 if the requested   */
450 /*               number of registers were available, 0 otherwise.  */
451 /*-----------------------------------------------------------------*/
452 int
453 getTempRegs(regs **tempRegs, int size, iCode *ic)
454 {
455   bitVect * freeRegs;
456   int i;
457   int offset;
458
459   if (!ic)
460     ic = _G.current_iCode;
461   if (!ic)
462     return 0;
463   if (!_G.currentFunc)
464     return 0;
465
466   freeRegs = newBitVect(8);
467   bitVectSetBit (freeRegs, R2_IDX);
468   bitVectSetBit (freeRegs, R3_IDX);
469   bitVectSetBit (freeRegs, R4_IDX);
470   bitVectSetBit (freeRegs, R5_IDX);
471   bitVectSetBit (freeRegs, R6_IDX);
472   bitVectSetBit (freeRegs, R7_IDX);
473
474   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
475     {
476       bitVect * newfreeRegs;
477       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
478       freeBitVect(freeRegs);
479       freeRegs = newfreeRegs;
480     }
481   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
482
483   offset = 0;
484   for (i=0; i<freeRegs->size; i++)
485     {
486       if (bitVectBitValue(freeRegs,i))
487         tempRegs[offset++] = REG_WITH_INDEX(i);
488       if (offset>=size)
489         {
490           freeBitVect(freeRegs);
491           return 1;
492         }
493     }
494
495   freeBitVect(freeRegs);
496   return 0;
497 }
498
499
500 /*-----------------------------------------------------------------*/
501 /* newAsmop - creates a new asmOp                                  */
502 /*-----------------------------------------------------------------*/
503 static asmop *
504 newAsmop (short type)
505 {
506   asmop *aop;
507
508   aop = Safe_calloc (1, sizeof (asmop));
509   aop->type = type;
510   aop->allocated = 1;
511   return aop;
512 }
513
514 /*-----------------------------------------------------------------*/
515 /* pointerCode - returns the code for a pointer type               */
516 /*-----------------------------------------------------------------*/
517 static int
518 pointerCode (sym_link * etype)
519 {
520
521   return PTR_TYPE (SPEC_OCLS (etype));
522
523 }
524
525 /*-----------------------------------------------------------------*/
526 /* leftRightUseAcc - returns size of accumulator use by operands   */
527 /*-----------------------------------------------------------------*/
528 static int
529 leftRightUseAcc(iCode *ic)
530 {
531   operand *op;
532   int size;
533   int accuseSize = 0;
534   int accuse = 0;
535
536   if (!ic)
537     {
538       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
539               "null iCode pointer");
540       return 0;
541     }
542
543   if (ic->op == IFX)
544     {
545       op = IC_COND (ic);
546       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
547         {
548           accuse = 1;
549           size = getSize (OP_SYMBOL (op)->type);
550           if (size>accuseSize)
551             accuseSize = size;
552         }
553     }
554   else if (ic->op == JUMPTABLE)
555     {
556       op = IC_JTCOND (ic);
557       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
558         {
559           accuse = 1;
560           size = getSize (OP_SYMBOL (op)->type);
561           if (size>accuseSize)
562             accuseSize = size;
563         }
564     }
565   else
566     {
567       op = IC_LEFT (ic);
568       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
569         {
570           accuse = 1;
571           size = getSize (OP_SYMBOL (op)->type);
572           if (size>accuseSize)
573             accuseSize = size;
574         }
575       op = IC_RIGHT (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
585   if (accuseSize)
586     return accuseSize;
587   else
588     return accuse;
589 }
590
591 /*-----------------------------------------------------------------*/
592 /* aopForSym - for a true symbol                                   */
593 /*-----------------------------------------------------------------*/
594 static asmop *
595 aopForSym (iCode * ic, symbol * sym, bool result)
596 {
597   asmop *aop;
598   memmap *space;
599   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
600
601   wassertl (ic != NULL, "Got a null iCode");
602   wassertl (sym != NULL, "Got a null symbol");
603
604   space = SPEC_OCLS (sym->etype);
605
606   /* if already has one */
607   if (sym->aop)
608     {
609       sym->aop->allocated++;
610       return sym->aop;
611     }
612
613   /* assign depending on the storage class */
614   /* if it is on the stack or indirectly addressable */
615   /* space we need to assign either r0 or r1 to it   */
616   if (sym->onStack || sym->iaccess)
617     {
618       sym->aop = aop = newAsmop (0);
619       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
620       aop->size = getSize (sym->type);
621
622       /* now assign the address of the variable to
623          the pointer register */
624       if (aop->type != AOP_STK)
625         {
626           if (sym->onStack)
627             {
628               signed char offset = ((sym->stack < 0) ?
629                          ((signed char) (sym->stack - _G.nRegsSaved)) :
630                          ((signed char) sym->stack)) & 0xff;
631
632               if ((abs(offset) <= 3) ||
633                   (accuse && (abs(offset) <= 7)))
634                 {
635                   emitcode ("mov", "%s,%s",
636                             aop->aopu.aop_ptr->name, SYM_BP (sym));
637                   while (offset < 0)
638                     {
639                       emitcode ("dec", aop->aopu.aop_ptr->name);
640                       offset++;
641                     }
642                   while (offset > 0)
643                     {
644                       emitcode ("inc", aop->aopu.aop_ptr->name);
645                       offset--;
646                     }
647                 }
648               else
649                 {
650                   if (accuse)
651                     emitcode ("push", "acc");
652                   emitcode ("mov", "a,%s", SYM_BP (sym));
653                   emitcode ("add", "a,#0x%02x", offset & 0xff);
654                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
655                   if (accuse)
656                     emitcode ("pop", "acc");
657                 }
658             }
659           else
660             {
661               emitcode ("mov", "%s,#%s",
662                         aop->aopu.aop_ptr->name,
663                         sym->rname);
664             }
665           aop->paged = space->paged;
666         }
667       else
668         aop->aopu.aop_stk = sym->stack;
669       return aop;
670     }
671
672   /* if in bit space */
673   if (IN_BITSPACE (space))
674     {
675       sym->aop = aop = newAsmop (AOP_CRY);
676       aop->aopu.aop_dir = sym->rname;
677       aop->size = getSize (sym->type);
678       return aop;
679     }
680   /* if it is in direct space */
681   if (IN_DIRSPACE (space))
682     {
683       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
684       //printTypeChainRaw(sym->type, NULL);
685       //printf("space = %s\n", space ? space->sname : "NULL");
686       sym->aop = aop = newAsmop (AOP_DIR);
687       aop->aopu.aop_dir = sym->rname;
688       aop->size = getSize (sym->type);
689       return aop;
690     }
691
692   /* special case for a function */
693   if (IS_FUNC (sym->type))
694     {
695       sym->aop = aop = newAsmop (AOP_IMMD);
696       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
697       aop->size = getSize (sym->type);
698       return aop;
699     }
700
701   /* only remaining is far space */
702   /* in which case DPTR gets the address */
703   sym->aop = aop = newAsmop (AOP_DPTR);
704   emitcode ("mov", "dptr,#%s", sym->rname);
705   aop->size = getSize (sym->type);
706
707   /* if it is in code space */
708   if (IN_CODESPACE (space))
709     aop->code = 1;
710
711   return aop;
712 }
713
714 /*-----------------------------------------------------------------*/
715 /* aopForRemat - rematerialzes an object                           */
716 /*-----------------------------------------------------------------*/
717 static asmop *
718 aopForRemat (symbol * sym)
719 {
720   iCode *ic = sym->rematiCode;
721   asmop *aop = newAsmop (AOP_IMMD);
722   int ptr_type = 0;
723   int val = 0;
724
725   for (;;)
726     {
727       if (ic->op == '+')
728         val += (int) operandLitValue (IC_RIGHT (ic));
729       else if (ic->op == '-')
730         val -= (int) operandLitValue (IC_RIGHT (ic));
731       else if (IS_CAST_ICODE(ic)) {
732               sym_link *from_type = operandType(IC_RIGHT(ic));
733               aop->aopu.aop_immd.from_cast_remat = 1;
734               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
735               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
736               continue;
737       } else break;
738
739       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
740     }
741
742   if (val)
743     {
744       SNPRINTF (buffer, sizeof(buffer),
745                 "(%s %c 0x%04x)",
746                 OP_SYMBOL (IC_LEFT (ic))->rname,
747                 val >= 0 ? '+' : '-',
748                 abs (val) & 0xffff);
749     }
750   else
751     {
752       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
753     }
754
755   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
756   /* set immd2 field if required */
757   if (aop->aopu.aop_immd.from_cast_remat)
758     {
759       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
760       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
761     }
762
763   return aop;
764 }
765
766 /*-----------------------------------------------------------------*/
767 /* regsInCommon - two operands have some registers in common       */
768 /*-----------------------------------------------------------------*/
769 static bool
770 regsInCommon (operand * op1, operand * op2)
771 {
772   symbol *sym1, *sym2;
773   int i;
774
775   /* if they have registers in common */
776   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
777     return FALSE;
778
779   sym1 = OP_SYMBOL (op1);
780   sym2 = OP_SYMBOL (op2);
781
782   if (sym1->nRegs == 0 || sym2->nRegs == 0)
783     return FALSE;
784
785   for (i = 0; i < sym1->nRegs; i++)
786     {
787       int j;
788       if (!sym1->regs[i])
789         continue;
790
791       for (j = 0; j < sym2->nRegs; j++)
792         {
793           if (!sym2->regs[j])
794             continue;
795
796           if (sym2->regs[j] == sym1->regs[i])
797             return TRUE;
798         }
799     }
800
801   return FALSE;
802 }
803
804 /*-----------------------------------------------------------------*/
805 /* operandsEqu - equivalent                                        */
806 /*-----------------------------------------------------------------*/
807 static bool
808 operandsEqu (operand * op1, operand * op2)
809 {
810   symbol *sym1, *sym2;
811
812   /* if they're not symbols */
813   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
814     return FALSE;
815
816   sym1 = OP_SYMBOL (op1);
817   sym2 = OP_SYMBOL (op2);
818
819   /* if both are itemps & one is spilt
820      and the other is not then false */
821   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
822       sym1->isspilt != sym2->isspilt)
823     return FALSE;
824
825   /* if they are the same */
826   if (sym1 == sym2)
827     return TRUE;
828
829   /* if they have the same rname */
830   if (sym1->rname[0] && sym2->rname[0] &&
831       strcmp (sym1->rname, sym2->rname) == 0 &&
832       !(IS_PARM (op2) && IS_ITEMP (op1)))
833     return TRUE;
834
835   /* if left is a tmp & right is not */
836   if (IS_ITEMP (op1) &&
837       !IS_ITEMP (op2) &&
838       sym1->isspilt &&
839       (sym1->usl.spillLoc == sym2))
840     return TRUE;
841
842   if (IS_ITEMP (op2) &&
843       !IS_ITEMP (op1) &&
844       sym2->isspilt &&
845       sym1->level > 0 &&
846       (sym2->usl.spillLoc == sym1))
847     return TRUE;
848
849   return FALSE;
850 }
851
852 /*-----------------------------------------------------------------*/
853 /* sameByte - two asmops have the same address at given offsets    */
854 /*-----------------------------------------------------------------*/
855 static bool
856 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
857 {
858   if (aop1 == aop2 && off1 == off2)
859     return TRUE;
860
861   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
862     return FALSE;
863
864   if (aop1->type != aop2->type)
865     return FALSE;
866
867   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
868     return FALSE;
869
870   return TRUE;
871 }
872
873 /*-----------------------------------------------------------------*/
874 /* sameRegs - two asmops have the same registers                   */
875 /*-----------------------------------------------------------------*/
876 static bool
877 sameRegs (asmop * aop1, asmop * aop2)
878 {
879   int i;
880
881   if (aop1 == aop2)
882     return TRUE;
883
884   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
885     return FALSE;
886
887   if (aop1->type != aop2->type)
888     return FALSE;
889
890   if (aop1->size != aop2->size)
891     return FALSE;
892
893   for (i = 0; i < aop1->size; i++)
894     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
895       return FALSE;
896
897   return TRUE;
898 }
899
900 /*-----------------------------------------------------------------*/
901 /* aopOp - allocates an asmop for an operand  :                    */
902 /*-----------------------------------------------------------------*/
903 static void
904 aopOp (operand * op, iCode * ic, bool result)
905 {
906   asmop *aop;
907   symbol *sym;
908   int i;
909
910   if (!op)
911     return;
912
913   /* if this a literal */
914   if (IS_OP_LITERAL (op))
915     {
916       op->aop = aop = newAsmop (AOP_LIT);
917       aop->aopu.aop_lit = op->operand.valOperand;
918       aop->size = getSize (operandType (op));
919       return;
920     }
921
922   /* if already has a asmop then continue */
923   if (op->aop)
924     {
925       op->aop->allocated++;
926       return;
927     }
928
929   /* if the underlying symbol has a aop */
930   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
931     {
932       op->aop = OP_SYMBOL (op)->aop;
933       op->aop->allocated++;
934       return;
935     }
936
937   /* if this is a true symbol */
938   if (IS_TRUE_SYMOP (op))
939     {
940       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
941       return;
942     }
943
944   /* this is a temporary : this has
945      only five choices :
946      a) register
947      b) spillocation
948      c) rematerialize
949      d) conditional
950      e) can be a return use only */
951
952   sym = OP_SYMBOL (op);
953
954   /* if the type is a conditional */
955   if (sym->regType == REG_CND)
956     {
957       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
958       aop->size = sym->ruonly ? 1 : 0;
959       return;
960     }
961
962   /* if it is spilt then two situations
963      a) is rematerialize
964      b) has a spill location */
965   if (sym->isspilt || sym->nRegs == 0)
966     {
967
968       /* rematerialize it NOW */
969       if (sym->remat)
970         {
971           sym->aop = op->aop = aop = aopForRemat (sym);
972           aop->size = getSize (sym->type);
973           return;
974         }
975
976       if (sym->accuse)
977         {
978           int i;
979           sym->aop = op->aop = aop = newAsmop (AOP_ACC);
980           aop->size = getSize (sym->type);
981           for (i = 0; i < 2; i++)
982             aop->aopu.aop_str[i] = accUse[i];
983           return;
984         }
985
986       if (sym->ruonly)
987         {
988           unsigned i;
989
990           sym->aop = op->aop = aop = newAsmop (AOP_STR);
991           aop->size = getSize (sym->type);
992           for (i = 0; i < fReturnSizeMCS51; i++)
993             aop->aopu.aop_str[i] = fReturn[i];
994           return;
995         }
996
997       if (sym->usl.spillLoc)
998         {
999           asmop *oldAsmOp = NULL;
1000
1001           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1002             {
1003               /* force a new aop if sizes differ */
1004               oldAsmOp = sym->usl.spillLoc->aop;
1005               sym->usl.spillLoc->aop = NULL;
1006             }
1007           sym->aop = op->aop = aop =
1008                      aopForSym (ic, sym->usl.spillLoc, result);
1009           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1010             {
1011               /* Don't reuse the new aop, go with the last one */
1012               sym->usl.spillLoc->aop = oldAsmOp;
1013             }
1014           aop->size = getSize (sym->type);
1015           return;
1016         }
1017
1018       /* else must be a dummy iTemp */
1019       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1020       aop->size = getSize (sym->type);
1021       return;
1022     }
1023
1024   /* if the type is a bit register */
1025   if (sym->regType == REG_BIT)
1026     {
1027       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1028       aop->size = sym->nRegs;//1???
1029       aop->aopu.aop_reg[0] = sym->regs[0];
1030       aop->aopu.aop_dir = sym->regs[0]->name;
1031       return;
1032     }
1033
1034   /* must be in a register */
1035   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1036   aop->size = sym->nRegs;
1037   for (i = 0; i < sym->nRegs; i++)
1038     aop->aopu.aop_reg[i] = sym->regs[i];
1039 }
1040
1041 /*-----------------------------------------------------------------*/
1042 /* freeAsmop - free up the asmop given to an operand               */
1043 /*----------------------------------------------------------------*/
1044 static void
1045 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1046 {
1047   asmop *aop;
1048
1049   if (!op)
1050     aop = aaop;
1051   else
1052     aop = op->aop;
1053
1054   if (!aop)
1055     return;
1056
1057   aop->allocated--;
1058
1059   if (aop->allocated)
1060     goto dealloc;
1061
1062   /* depending on the asmop type only three cases need work
1063      AOP_R0, AOP_R1 & AOP_STK */
1064   switch (aop->type)
1065     {
1066     case AOP_R0:
1067       if (R0INB)
1068         {
1069           emitcode ("mov", "r0,b");
1070           R0INB--;
1071         }
1072       else if (_G.r0Pushed)
1073         {
1074           if (pop)
1075             {
1076               emitcode ("pop", "ar0");
1077               _G.r0Pushed--;
1078             }
1079         }
1080       bitVectUnSetBit (ic->rUsed, R0_IDX);
1081       break;
1082
1083     case AOP_R1:
1084       if (R1INB)
1085         {
1086           emitcode ("mov", "r1,b");
1087           R1INB--;
1088         }
1089       else if (_G.r1Pushed)
1090         {
1091           if (pop)
1092             {
1093               emitcode ("pop", "ar1");
1094               _G.r1Pushed--;
1095             }
1096         }
1097       bitVectUnSetBit (ic->rUsed, R1_IDX);
1098       break;
1099
1100     case AOP_STK:
1101       {
1102         int sz = aop->size;
1103         int stk = aop->aopu.aop_stk + aop->size - 1;
1104         bitVectUnSetBit (ic->rUsed, R0_IDX);
1105         bitVectUnSetBit (ic->rUsed, R1_IDX);
1106
1107         getFreePtr (ic, &aop, FALSE);
1108
1109         if (stk)
1110           {
1111             emitcode ("mov", "a,_bp");
1112             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1113             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1114           }
1115         else
1116           {
1117             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1118           }
1119
1120         while (sz--)
1121           {
1122             emitcode ("pop", "acc");
1123             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1124             if (!sz)
1125               break;
1126             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1127           }
1128         op->aop = aop;
1129         freeAsmop (op, NULL, ic, TRUE);
1130         if (_G.r1Pushed)
1131           {
1132             emitcode ("pop", "ar1");
1133             _G.r1Pushed--;
1134           }
1135         if (_G.r0Pushed)
1136           {
1137             emitcode ("pop", "ar0");
1138             _G.r0Pushed--;
1139           }
1140       }
1141       break;
1142     }
1143
1144 dealloc:
1145   /* all other cases just dealloc */
1146   if (op)
1147     {
1148       op->aop = NULL;
1149       if (IS_SYMOP (op))
1150         {
1151           OP_SYMBOL (op)->aop = NULL;
1152           /* if the symbol has a spill */
1153           if (SPIL_LOC (op))
1154             SPIL_LOC (op)->aop = NULL;
1155         }
1156     }
1157 }
1158
1159 /*------------------------------------------------------------------*/
1160 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1161 /*                      pop r0 or r1 off stack if pushed            */
1162 /*------------------------------------------------------------------*/
1163 static void
1164 freeForBranchAsmop (operand * op)
1165 {
1166   asmop *aop;
1167
1168   if (!op)
1169     return;
1170
1171   aop = op->aop;
1172
1173   if (!aop)
1174     return;
1175
1176   if (!aop->allocated)
1177     return;
1178
1179   switch (aop->type)
1180     {
1181     case AOP_R0:
1182       if (R0INB)
1183         {
1184           emitcode ("mov", "r0,b");
1185         }
1186       else if (_G.r0Pushed)
1187         {
1188           emitcode ("pop", "ar0");
1189         }
1190       break;
1191
1192     case AOP_R1:
1193       if (R1INB)
1194         {
1195           emitcode ("mov", "r1,b");
1196         }
1197       else if (_G.r1Pushed)
1198         {
1199           emitcode ("pop", "ar1");
1200         }
1201       break;
1202
1203     case AOP_STK:
1204       {
1205         int sz = aop->size;
1206         int stk = aop->aopu.aop_stk + aop->size - 1;
1207
1208         emitcode ("mov", "b,r0");
1209         if (stk)
1210           {
1211             emitcode ("mov", "a,_bp");
1212             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1213             emitcode ("mov", "r0,a");
1214           }
1215         else
1216           {
1217             emitcode ("mov", "r0,_bp");
1218           }
1219
1220         while (sz--)
1221           {
1222             emitcode ("pop", "acc");
1223             emitcode ("mov", "@r0,a");
1224             if (!sz)
1225               break;
1226             emitcode ("dec", "r0");
1227           }
1228         emitcode ("mov", "r0,b");
1229       }
1230     }
1231
1232 }
1233
1234 /*-----------------------------------------------------------------*/
1235 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1236 /*                 clobber the accumulator                         */
1237 /*-----------------------------------------------------------------*/
1238 static bool
1239 aopGetUsesAcc (operand * oper, int offset)
1240 {
1241   asmop * aop = AOP (oper);
1242
1243   if (offset > (aop->size - 1))
1244     return FALSE;
1245
1246   switch (aop->type)
1247     {
1248
1249     case AOP_R0:
1250     case AOP_R1:
1251       if (aop->paged)
1252         return TRUE;
1253       return FALSE;
1254     case AOP_DPTR:
1255       return TRUE;
1256     case AOP_IMMD:
1257       return FALSE;
1258     case AOP_DIR:
1259       return FALSE;
1260     case AOP_REG:
1261       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1262       return FALSE;
1263     case AOP_CRY:
1264       return TRUE;
1265     case AOP_ACC:
1266       if (offset)
1267         return FALSE;
1268       return TRUE;
1269     case AOP_LIT:
1270       return FALSE;
1271     case AOP_STR:
1272       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1273         return TRUE;
1274       return FALSE;
1275     case AOP_DUMMY:
1276       return FALSE;
1277     default:
1278       /* Error case --- will have been caught already */
1279       wassert(0);
1280       return FALSE;
1281     }
1282 }
1283
1284 /*-------------------------------------------------------------------*/
1285 /* aopGet - for fetching value of the aop                            */
1286 /*-------------------------------------------------------------------*/
1287 static char *
1288 aopGet (operand * oper, int offset, bool bit16, bool dname)
1289 {
1290   asmop * aop = AOP (oper);
1291
1292   /* offset is greater than
1293      size then zero */
1294   if (offset > (aop->size - 1) &&
1295       aop->type != AOP_LIT)
1296     return zero;
1297
1298   /* depending on type */
1299   switch (aop->type)
1300     {
1301     case AOP_DUMMY:
1302       return zero;
1303
1304     case AOP_R0:
1305     case AOP_R1:
1306       /* if we need to increment it */
1307       while (offset > aop->coff)
1308         {
1309           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1310           aop->coff++;
1311         }
1312
1313       while (offset < aop->coff)
1314         {
1315           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1316           aop->coff--;
1317         }
1318
1319       aop->coff = offset;
1320       if (aop->paged)
1321         {
1322           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1323           return (dname ? "acc" : "a");
1324         }
1325       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1326       return Safe_strdup(buffer);
1327
1328     case AOP_DPTR:
1329       if (aop->code && aop->coff==0 && offset>=1) {
1330         emitcode ("mov", "a,#0x%02x", offset);
1331         emitcode ("movc", "a,@a+dptr");
1332         return (dname ? "acc" : "a");
1333       }
1334
1335       while (offset > aop->coff)
1336         {
1337           emitcode ("inc", "dptr");
1338           aop->coff++;
1339         }
1340
1341       while (offset < aop->coff)
1342         {
1343           emitcode ("lcall", "__decdptr");
1344           aop->coff--;
1345         }
1346
1347       aop->coff = offset;
1348       if (aop->code)
1349         {
1350           emitcode ("clr", "a");
1351           emitcode ("movc", "a,@a+dptr");
1352         }
1353       else
1354         {
1355           emitcode ("movx", "a,@dptr");
1356         }
1357       return (dname ? "acc" : "a");
1358
1359     case AOP_IMMD:
1360       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1361         {
1362           SNPRINTF(buffer, sizeof(buffer),
1363                    "%s",aop->aopu.aop_immd.aop_immd2);
1364         }
1365       else if (bit16)
1366         {
1367           SNPRINTF(buffer, sizeof(buffer),
1368                    "#%s", aop->aopu.aop_immd.aop_immd1);
1369         }
1370       else if (offset)
1371         {
1372           SNPRINTF (buffer, sizeof(buffer),
1373                     "#(%s >> %d)",
1374                     aop->aopu.aop_immd.aop_immd1,
1375                     offset * 8);
1376         }
1377       else
1378         {
1379           SNPRINTF (buffer, sizeof(buffer),
1380                     "#%s",
1381                     aop->aopu.aop_immd.aop_immd1);
1382         }
1383       return Safe_strdup(buffer);
1384
1385     case AOP_DIR:
1386       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1387         {
1388           SNPRINTF (buffer, sizeof(buffer),
1389                     "(%s >> %d)",
1390                     aop->aopu.aop_dir, offset * 8);
1391         }
1392       else if (offset)
1393         {
1394           SNPRINTF (buffer, sizeof(buffer),
1395                     "(%s + %d)",
1396                     aop->aopu.aop_dir,
1397                     offset);
1398         }
1399       else
1400         {
1401           SNPRINTF (buffer, sizeof(buffer),
1402                     "%s",
1403                     aop->aopu.aop_dir);
1404         }
1405
1406       return Safe_strdup(buffer);
1407
1408     case AOP_REG:
1409       if (dname)
1410         return aop->aopu.aop_reg[offset]->dname;
1411       else
1412         return aop->aopu.aop_reg[offset]->name;
1413
1414     case AOP_CRY:
1415       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1416       emitcode ("clr", "a");
1417       emitcode ("rlc", "a");
1418       return (dname ? "acc" : "a");
1419
1420     case AOP_ACC:
1421       if (!offset && dname)
1422         return "acc";
1423       return aop->aopu.aop_str[offset];
1424
1425     case AOP_LIT:
1426       return aopLiteral (aop->aopu.aop_lit, offset);
1427
1428     case AOP_STR:
1429       aop->coff = offset;
1430       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1431           dname)
1432         return "acc";
1433
1434       return aop->aopu.aop_str[offset];
1435
1436     }
1437
1438   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1439           "aopget got unsupported aop->type");
1440   exit (1);
1441 }
1442
1443 /*-----------------------------------------------------------------*/
1444 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1445 /*                 clobber the accumulator                         */
1446 /*-----------------------------------------------------------------*/
1447 static bool
1448 aopPutUsesAcc (operand * oper, const char *s, int offset)
1449 {
1450   asmop * aop = AOP (oper);
1451
1452   if (offset > (aop->size - 1))
1453     return FALSE;
1454
1455   switch (aop->type)
1456     {
1457     case AOP_DUMMY:
1458       return TRUE;
1459     case AOP_DIR:
1460       return FALSE;
1461     case AOP_REG:
1462       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1463       return FALSE;
1464     case AOP_DPTR:
1465       return TRUE;
1466     case AOP_R0:
1467     case AOP_R1:
1468       return ((aop->paged) || (*s == '@'));
1469     case AOP_STK:
1470       return (*s == '@');
1471     case AOP_CRY:
1472       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1473     case AOP_STR:
1474       return FALSE;
1475     case AOP_IMMD:
1476       return FALSE;
1477     case AOP_ACC:
1478       return FALSE;
1479     default:
1480       /* Error case --- will have been caught already */
1481       wassert(0);
1482       return FALSE;
1483     }
1484 }
1485
1486 /*-----------------------------------------------------------------*/
1487 /* aopPut - puts a string for a aop and indicates if acc is in use */
1488 /*-----------------------------------------------------------------*/
1489 static bool
1490 aopPut (operand * result, const char *s, int offset)
1491 {
1492   bool bvolatile = isOperandVolatile (result, FALSE);
1493   bool accuse = FALSE;
1494   asmop * aop = AOP (result);
1495   const char *d = NULL;
1496
1497   if (aop->size && offset > (aop->size - 1))
1498     {
1499       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1500               "aopPut got offset > aop->size");
1501       exit (1);
1502     }
1503
1504   /* will assign value to value */
1505   /* depending on where it is ofcourse */
1506   switch (aop->type)
1507     {
1508     case AOP_DUMMY:
1509       MOVA (s);         /* read s in case it was volatile */
1510       accuse = TRUE;
1511       break;
1512
1513     case AOP_DIR:
1514       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1515         {
1516           SNPRINTF (buffer, sizeof(buffer),
1517                     "(%s >> %d)",
1518                     aop->aopu.aop_dir, offset * 8);
1519         }
1520       else if (offset)
1521         {
1522           SNPRINTF (buffer, sizeof(buffer),
1523                     "(%s + %d)",
1524                     aop->aopu.aop_dir, offset);
1525         }
1526       else
1527         {
1528           SNPRINTF (buffer, sizeof(buffer),
1529                     "%s",
1530                     aop->aopu.aop_dir);
1531         }
1532
1533       if (strcmp (buffer, s) || bvolatile)
1534         {
1535           emitcode ("mov", "%s,%s", buffer, s);
1536         }
1537       if (!strcmp (buffer, "acc"))
1538         {
1539           accuse = TRUE;
1540         }
1541       break;
1542
1543     case AOP_REG:
1544       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1545           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1546         {
1547           if (*s == '@' ||
1548               strcmp (s, "r0") == 0 ||
1549               strcmp (s, "r1") == 0 ||
1550               strcmp (s, "r2") == 0 ||
1551               strcmp (s, "r3") == 0 ||
1552               strcmp (s, "r4") == 0 ||
1553               strcmp (s, "r5") == 0 ||
1554               strcmp (s, "r6") == 0 ||
1555               strcmp (s, "r7") == 0)
1556             {
1557               emitcode ("mov", "%s,%s",
1558                         aop->aopu.aop_reg[offset]->dname, s);
1559             }
1560           else
1561             {
1562               emitcode ("mov", "%s,%s",
1563                         aop->aopu.aop_reg[offset]->name, s);
1564             }
1565         }
1566       break;
1567
1568     case AOP_DPTR:
1569       if (aop->code)
1570         {
1571           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1572                   "aopPut writing to code space");
1573           exit (1);
1574         }
1575
1576       while (offset > aop->coff)
1577         {
1578           aop->coff++;
1579           emitcode ("inc", "dptr");
1580         }
1581
1582       while (offset < aop->coff)
1583         {
1584           aop->coff--;
1585           emitcode ("lcall", "__decdptr");
1586         }
1587
1588       aop->coff = offset;
1589
1590       /* if not in accumulator */
1591       MOVA (s);
1592
1593       emitcode ("movx", "@dptr,a");
1594       break;
1595
1596     case AOP_R0:
1597     case AOP_R1:
1598       while (offset > aop->coff)
1599         {
1600           aop->coff++;
1601           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1602         }
1603       while (offset < aop->coff)
1604         {
1605           aop->coff--;
1606           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1607         }
1608       aop->coff = offset;
1609
1610       if (aop->paged)
1611         {
1612           MOVA (s);
1613           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1614         }
1615       else if (*s == '@')
1616         {
1617           MOVA (s);
1618           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1619         }
1620       else if (strcmp (s, "r0") == 0 ||
1621                strcmp (s, "r1") == 0 ||
1622                strcmp (s, "r2") == 0 ||
1623                strcmp (s, "r3") == 0 ||
1624                strcmp (s, "r4") == 0 ||
1625                strcmp (s, "r5") == 0 ||
1626                strcmp (s, "r6") == 0 ||
1627                strcmp (s, "r7") == 0)
1628         {
1629           char buffer[10];
1630           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1631           emitcode ("mov", "@%s,%s",
1632                     aop->aopu.aop_ptr->name, buffer);
1633         }
1634       else
1635         {
1636           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1637         }
1638       break;
1639
1640     case AOP_STK:
1641       if (strcmp (s, "a") == 0)
1642         {
1643           emitcode ("push", "acc");
1644         }
1645       else if (*s=='@')
1646         {
1647           MOVA(s);
1648           emitcode ("push", "acc");
1649         }
1650       else if (strcmp (s, "r0") == 0 ||
1651                strcmp (s, "r1") == 0 ||
1652                strcmp (s, "r2") == 0 ||
1653                strcmp (s, "r3") == 0 ||
1654                strcmp (s, "r4") == 0 ||
1655                strcmp (s, "r5") == 0 ||
1656                strcmp (s, "r6") == 0 ||
1657                strcmp (s, "r7") == 0)
1658         {
1659           char buffer[10];
1660           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1661           emitcode ("push", buffer);
1662         }
1663       else
1664         {
1665           emitcode ("push", s);
1666         }
1667
1668       break;
1669
1670     case AOP_CRY:
1671       // destination is carry for return-use-only
1672       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1673       // source is no literal and not in carry
1674       if ((s != zero) && (s != one) && strcmp (s, "c"))
1675         {
1676           MOVA (s);
1677           /* set C, if a >= 1 */
1678           emitcode ("add", "a,#0xff");
1679           s = "c";
1680         }
1681       // now source is zero, one or carry
1682
1683       /* if result no bit variable */
1684       if (!d)
1685         {
1686           if (!strcmp (s, "c"))
1687             {
1688               /* inefficient: move carry into A and use jz/jnz */
1689               emitcode ("clr", "a");
1690               emitcode ("rlc", "a");
1691               accuse = TRUE;
1692             }
1693           else
1694             {
1695               MOVA (s);
1696               accuse = TRUE;
1697             }
1698         }
1699       else if (s == zero)
1700           emitcode ("clr", "%s", d);
1701       else if (s == one)
1702           emitcode ("setb", "%s", d);
1703       else if (strcmp (s, d))
1704           emitcode ("mov", "%s,c", d);
1705       break;
1706
1707     case AOP_STR:
1708       aop->coff = offset;
1709       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1710         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1711       break;
1712
1713     case AOP_ACC:
1714       accuse = TRUE;
1715       aop->coff = offset;
1716       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1717         break;
1718
1719       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1720         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1721       break;
1722
1723     default:
1724       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1725               "aopPut got unsupported aop->type");
1726       exit (1);
1727     }
1728
1729     return accuse;
1730 }
1731
1732
1733 #if 0
1734 /*-----------------------------------------------------------------*/
1735 /* pointToEnd :- points to the last byte of the operand            */
1736 /*-----------------------------------------------------------------*/
1737 static void
1738 pointToEnd (asmop * aop)
1739 {
1740   int count;
1741   if (!aop)
1742     return;
1743
1744   aop->coff = count = (aop->size - 1);
1745   switch (aop->type)
1746     {
1747     case AOP_R0:
1748     case AOP_R1:
1749       while (count--)
1750         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1751       break;
1752     case AOP_DPTR:
1753       while (count--)
1754         emitcode ("inc", "dptr");
1755       break;
1756     }
1757
1758 }
1759 #endif
1760
1761 /*-----------------------------------------------------------------*/
1762 /* reAdjustPreg - points a register back to where it should        */
1763 /*-----------------------------------------------------------------*/
1764 static void
1765 reAdjustPreg (asmop * aop)
1766 {
1767   if ((aop->coff==0) || (aop->size <= 1))
1768     return;
1769
1770   switch (aop->type)
1771     {
1772     case AOP_R0:
1773     case AOP_R1:
1774       while (aop->coff--)
1775         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1776       break;
1777     case AOP_DPTR:
1778       while (aop->coff--)
1779         {
1780           emitcode ("lcall", "__decdptr");
1781         }
1782       break;
1783     }
1784   aop->coff = 0;
1785 }
1786
1787 /*-----------------------------------------------------------------*/
1788 /* opIsGptr: returns non-zero if the passed operand is       */
1789 /* a generic pointer type.             */
1790 /*-----------------------------------------------------------------*/
1791 static int
1792 opIsGptr (operand * op)
1793 {
1794   sym_link *type = operandType (op);
1795
1796   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1797     {
1798       return 1;
1799     }
1800   return 0;
1801 }
1802
1803 /*-----------------------------------------------------------------*/
1804 /* getDataSize - get the operand data size                         */
1805 /*-----------------------------------------------------------------*/
1806 static int
1807 getDataSize (operand * op)
1808 {
1809   int size;
1810   size = AOP_SIZE (op);
1811   if (size == GPTRSIZE)
1812     {
1813       sym_link *type = operandType (op);
1814       if (IS_GENPTR (type))
1815         {
1816           /* generic pointer; arithmetic operations
1817            * should ignore the high byte (pointer type).
1818            */
1819           size--;
1820         }
1821     }
1822   return size;
1823 }
1824
1825 /*-----------------------------------------------------------------*/
1826 /* outAcc - output Acc                                             */
1827 /*-----------------------------------------------------------------*/
1828 static void
1829 outAcc (operand * result)
1830 {
1831   int size, offset;
1832   size = getDataSize (result);
1833   if (size)
1834     {
1835       aopPut (result, "a", 0);
1836       size--;
1837       offset = 1;
1838       /* unsigned or positive */
1839       while (size--)
1840         {
1841           aopPut (result, zero, offset++);
1842         }
1843     }
1844 }
1845
1846 /*-----------------------------------------------------------------*/
1847 /* outBitC - output a bit C                                        */
1848 /*-----------------------------------------------------------------*/
1849 static void
1850 outBitC (operand * result)
1851 {
1852   /* if the result is bit */
1853   if (AOP_TYPE (result) == AOP_CRY)
1854     {
1855       if (!IS_OP_RUONLY (result))
1856         aopPut (result, "c", 0);
1857     }
1858   else
1859     {
1860       emitcode ("clr", "a");
1861       emitcode ("rlc", "a");
1862       outAcc (result);
1863     }
1864 }
1865
1866 /*-----------------------------------------------------------------*/
1867 /* toBoolean - emit code for orl a,operator(sizeop)                */
1868 /*-----------------------------------------------------------------*/
1869 static void
1870 toBoolean (operand * oper)
1871 {
1872   int size = AOP_SIZE (oper) - 1;
1873   int offset = 1;
1874   bool AccUsed = FALSE;
1875   bool pushedB;
1876
1877   while (!AccUsed && size--)
1878     {
1879       AccUsed |= aopGetUsesAcc(oper, offset++);
1880     }
1881
1882   size = AOP_SIZE (oper) - 1;
1883   offset = 1;
1884   MOVA (aopGet (oper, 0, FALSE, FALSE));
1885   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1886     {
1887       pushedB = pushB ();
1888       emitcode("mov", "b,a");
1889       while (--size)
1890         {
1891           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1892           emitcode ("orl", "b,a");
1893         }
1894       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1895       emitcode ("orl", "a,b");
1896       popB (pushedB);
1897     }
1898   else
1899     {
1900       while (size--)
1901         {
1902           emitcode ("orl", "a,%s",
1903                     aopGet (oper, offset++, FALSE, FALSE));
1904         }
1905     }
1906 }
1907
1908 /*-----------------------------------------------------------------*/
1909 /* toCarry - make boolean and move into carry                      */
1910 /*-----------------------------------------------------------------*/
1911 static void
1912 toCarry (operand * oper)
1913 {
1914   /* if the operand is a literal then
1915      we know what the value is */
1916   if (AOP_TYPE (oper) == AOP_LIT)
1917     {
1918       if ((int) operandLitValue (oper))
1919         SETC;
1920       else
1921         CLRC;
1922     }
1923   else if (AOP_TYPE (oper) == AOP_CRY)
1924     {
1925       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1926     }
1927   else
1928     {
1929       /* or the operand into a */
1930       toBoolean (oper);
1931       /* set C, if a >= 1 */
1932       emitcode ("add", "a,#0xff");
1933     }
1934 }
1935
1936 /*-----------------------------------------------------------------*/
1937 /* assignBit - assign operand to bit operand                       */
1938 /*-----------------------------------------------------------------*/
1939 static void
1940 assignBit (operand * result, operand * right)
1941 {
1942   /* if the right side is a literal then
1943      we know what the value is */
1944   if (AOP_TYPE (right) == AOP_LIT)
1945     {
1946       if ((int) operandLitValue (right))
1947         aopPut (result, one, 0);
1948       else
1949         aopPut (result, zero, 0);
1950     }
1951   else
1952     {
1953       toCarry (right);
1954       aopPut (result, "c", 0);
1955     }
1956 }
1957
1958
1959 /*-------------------------------------------------------------------*/
1960 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1961 /*-------------------------------------------------------------------*/
1962 static char *
1963 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1964 {
1965   char * l;
1966
1967   if (aopGetUsesAcc (oper, offset))
1968     {
1969       emitcode("mov", "b,a");
1970       MOVA (aopGet (oper, offset, bit16, dname));
1971       emitcode("xch", "a,b");
1972       aopPut (oper, "a", offset);
1973       emitcode("xch", "a,b");
1974       l = "b";
1975     }
1976   else
1977     {
1978       l = aopGet (oper, offset, bit16, dname);
1979       emitcode("xch", "a,%s", l);
1980     }
1981   return l;
1982 }
1983
1984
1985 /*-----------------------------------------------------------------*/
1986 /* genNot - generate code for ! operation                          */
1987 /*-----------------------------------------------------------------*/
1988 static void
1989 genNot (iCode * ic)
1990 {
1991   symbol *tlbl;
1992
1993   D (emitcode (";", "genNot"));
1994
1995   /* assign asmOps to operand & result */
1996   aopOp (IC_LEFT (ic), ic, FALSE);
1997   aopOp (IC_RESULT (ic), ic, TRUE);
1998
1999   /* if in bit space then a special case */
2000   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2001     {
2002       /* if left==result then cpl bit */
2003       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2004         {
2005           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2006         }
2007       else
2008         {
2009           toCarry (IC_LEFT (ic));
2010           emitcode ("cpl", "c");
2011           outBitC (IC_RESULT (ic));
2012         }
2013       goto release;
2014     }
2015
2016   toBoolean (IC_LEFT (ic));
2017
2018   /* set C, if a == 0 */
2019   tlbl = newiTempLabel (NULL);
2020   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2021   emitLabel (tlbl);
2022   outBitC (IC_RESULT (ic));
2023
2024 release:
2025   /* release the aops */
2026   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2027   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2028 }
2029
2030
2031 /*-----------------------------------------------------------------*/
2032 /* genCpl - generate code for complement                           */
2033 /*-----------------------------------------------------------------*/
2034 static void
2035 genCpl (iCode * ic)
2036 {
2037   int offset = 0;
2038   int size;
2039   symbol *tlbl;
2040   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2041
2042   D(emitcode (";", "genCpl"));
2043
2044   /* assign asmOps to operand & result */
2045   aopOp (IC_LEFT (ic), ic, FALSE);
2046   aopOp (IC_RESULT (ic), ic, TRUE);
2047
2048   /* special case if in bit space */
2049   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2050     {
2051       char *l;
2052
2053       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2054           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2055         {
2056           /* promotion rules are responsible for this strange result:
2057              bit -> int -> ~int -> bit
2058              uchar -> int -> ~int -> bit
2059           */
2060           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2061           goto release;
2062         }
2063
2064       tlbl=newiTempLabel(NULL);
2065       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2066       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2067           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2068           IS_AOP_PREG (IC_LEFT (ic)))
2069         {
2070           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2071         }
2072       else
2073         {
2074           MOVA (l);
2075           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2076         }
2077       emitLabel (tlbl);
2078       outBitC (IC_RESULT(ic));
2079       goto release;
2080     }
2081
2082   size = AOP_SIZE (IC_RESULT (ic));
2083   while (size--)
2084     {
2085       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2086       MOVA (l);
2087       emitcode ("cpl", "a");
2088       aopPut (IC_RESULT (ic), "a", offset++);
2089     }
2090
2091
2092 release:
2093   /* release the aops */
2094   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2095   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2096 }
2097
2098 /*-----------------------------------------------------------------*/
2099 /* genUminusFloat - unary minus for floating points                */
2100 /*-----------------------------------------------------------------*/
2101 static void
2102 genUminusFloat (operand * op, operand * result)
2103 {
2104   int size, offset = 0;
2105   char *l;
2106
2107   D (emitcode (";", "genUminusFloat"));
2108
2109   /* for this we just copy and then flip the bit */
2110
2111   size = AOP_SIZE (op) - 1;
2112
2113   while (size--)
2114     {
2115       aopPut (result,
2116               aopGet (op, offset, FALSE, FALSE),
2117               offset);
2118       offset++;
2119     }
2120
2121   l = aopGet (op, offset, FALSE, FALSE);
2122   MOVA (l);
2123
2124   emitcode ("cpl", "acc.7");
2125   aopPut (result, "a", offset);
2126 }
2127
2128 /*-----------------------------------------------------------------*/
2129 /* genUminus - unary minus code generation                         */
2130 /*-----------------------------------------------------------------*/
2131 static void
2132 genUminus (iCode * ic)
2133 {
2134   int offset, size;
2135   sym_link *optype;
2136
2137   D (emitcode (";", "genUminus"));
2138
2139   /* assign asmops */
2140   aopOp (IC_LEFT (ic), ic, FALSE);
2141   aopOp (IC_RESULT (ic), ic, TRUE);
2142
2143   /* if both in bit space then special
2144      case */
2145   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2146       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2147     {
2148
2149       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2150       emitcode ("cpl", "c");
2151       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2152       goto release;
2153     }
2154
2155   optype = operandType (IC_LEFT (ic));
2156
2157   /* if float then do float stuff */
2158   if (IS_FLOAT (optype))
2159     {
2160       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2161       goto release;
2162     }
2163
2164   /* otherwise subtract from zero */
2165   size = AOP_SIZE (IC_LEFT (ic));
2166   offset = 0;
2167   while (size--)
2168     {
2169       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2170       if (!strcmp (l, "a"))
2171         {
2172           if (offset == 0)
2173             SETC;
2174           emitcode ("cpl", "a");
2175           emitcode ("addc", "a,#0");
2176         }
2177       else
2178         {
2179           if (offset == 0)
2180             CLRC;
2181           emitcode ("clr", "a");
2182           emitcode ("subb", "a,%s", l);
2183         }
2184       aopPut (IC_RESULT (ic), "a", offset++);
2185     }
2186
2187   /* if any remaining bytes in the result */
2188   /* we just need to propagate the sign   */
2189   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2190     {
2191       emitcode ("rlc", "a");
2192       emitcode ("subb", "a,acc");
2193       while (size--)
2194         aopPut (IC_RESULT (ic), "a", offset++);
2195     }
2196
2197 release:
2198   /* release the aops */
2199   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2200   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2201 }
2202
2203 /*-----------------------------------------------------------------*/
2204 /* saveRegisters - will look for a call and save the registers     */
2205 /*-----------------------------------------------------------------*/
2206 static void
2207 saveRegisters (iCode * lic)
2208 {
2209   int i;
2210   iCode *ic;
2211   bitVect *rsave;
2212
2213   /* look for call */
2214   for (ic = lic; ic; ic = ic->next)
2215     if (ic->op == CALL || ic->op == PCALL)
2216       break;
2217
2218   if (!ic)
2219     {
2220       fprintf (stderr, "found parameter push with no function call\n");
2221       return;
2222     }
2223
2224   /* if the registers have been saved already or don't need to be then
2225      do nothing */
2226   if (ic->regsSaved)
2227     return;
2228   if (IS_SYMOP(IC_LEFT(ic)) &&
2229       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2230        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2231     return;
2232
2233   /* save the registers in use at this time but skip the
2234      ones for the result */
2235   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2236                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2237
2238   ic->regsSaved = 1;
2239   if (options.useXstack)
2240     {
2241       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2242       int nBits = bitVectnBitsOn (rsavebits);
2243       int count = bitVectnBitsOn (rsave);
2244
2245       if (nBits != 0)
2246         {
2247           count = count - nBits + 1;
2248           /* remove all but the first bits as they are pushed all at once */
2249           rsave = bitVectCplAnd (rsave, rsavebits);
2250           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2251         }
2252       freeBitVect (rsavebits);
2253
2254       if (count == 1)
2255         {
2256           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2257           if (reg->type == REG_BIT)
2258             {
2259               emitcode ("mov", "a,%s", reg->base);
2260             }
2261           else
2262             {
2263               emitcode ("mov", "a,%s", reg->name);
2264             }
2265           emitcode ("mov", "r0,%s", spname);
2266           emitcode ("inc", "%s", spname);// allocate before use
2267           emitcode ("movx", "@r0,a");
2268           if (bitVectBitValue (rsave, R0_IDX))
2269             emitcode ("mov", "r0,a");
2270         }
2271       else if (count != 0)
2272         {
2273           if (bitVectBitValue (rsave, R0_IDX))
2274             {
2275               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2276             }
2277           emitcode ("mov", "r0,%s", spname);
2278           MOVA ("r0");
2279           emitcode ("add", "a,#%d", count);
2280           emitcode ("mov", "%s,a", spname);
2281           for (i = 0; i < mcs51_nRegs; i++)
2282             {
2283               if (bitVectBitValue (rsave, i))
2284                 {
2285                   regs * reg = REG_WITH_INDEX (i);
2286                   if (i == R0_IDX)
2287                     {
2288                       emitcode ("pop", "acc");
2289                       emitcode ("push", "acc");
2290                     }
2291                   else if (reg->type == REG_BIT)
2292                     {
2293                       emitcode ("mov", "a,%s", reg->base);
2294                     }
2295                   else
2296                     {
2297                       emitcode ("mov", "a,%s", reg->name);
2298                     }
2299                   emitcode ("movx", "@r0,a");
2300                   if (--count)
2301                     {
2302                       emitcode ("inc", "r0");
2303                     }
2304                 }
2305             }
2306           if (bitVectBitValue (rsave, R0_IDX))
2307             {
2308               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2309             }
2310         }
2311     }
2312   else
2313     {
2314       bool bits_pushed = FALSE;
2315       for (i = 0; i < mcs51_nRegs; i++)
2316         {
2317           if (bitVectBitValue (rsave, i))
2318             {
2319               bits_pushed = pushReg (i, bits_pushed);
2320             }
2321         }
2322     }
2323   freeBitVect (rsave);
2324 }
2325
2326 /*-----------------------------------------------------------------*/
2327 /* unsaveRegisters - pop the pushed registers                      */
2328 /*-----------------------------------------------------------------*/
2329 static void
2330 unsaveRegisters (iCode * ic)
2331 {
2332   int i;
2333   bitVect *rsave;
2334
2335   /* restore the registers in use at this time but skip the
2336      ones for the result */
2337   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2338                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2339
2340   if (options.useXstack)
2341     {
2342       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2343       int nBits = bitVectnBitsOn (rsavebits);
2344       int count = bitVectnBitsOn (rsave);
2345
2346       if (nBits != 0)
2347         {
2348           count = count - nBits + 1;
2349           /* remove all but the first bits as they are popped all at once */
2350           rsave = bitVectCplAnd (rsave, rsavebits);
2351           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2352         }
2353       freeBitVect (rsavebits);
2354
2355       if (count == 1)
2356         {
2357           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2358           emitcode ("mov", "r0,%s", spname);
2359           emitcode ("dec", "r0");
2360           emitcode ("movx", "a,@r0");
2361           if (reg->type == REG_BIT)
2362             {
2363               emitcode ("mov", "%s,a", reg->base);
2364             }
2365           else
2366             {
2367               emitcode ("mov", "%s,a", reg->name);
2368             }
2369           emitcode ("dec", "%s", spname);
2370         }
2371       else if (count != 0)
2372         {
2373           emitcode ("mov", "r0,%s", spname);
2374           for (i = mcs51_nRegs; i >= 0; i--)
2375             {
2376               if (bitVectBitValue (rsave, i))
2377                 {
2378                   regs * reg = REG_WITH_INDEX (i);
2379                   emitcode ("dec", "r0");
2380                   emitcode ("movx", "a,@r0");
2381                   if (i == R0_IDX)
2382                     {
2383                       emitcode ("push", "acc");
2384                     }
2385                   else if (reg->type == REG_BIT)
2386                     {
2387                       emitcode ("mov", "%s,a", reg->base);
2388                     }
2389                   else
2390                     {
2391                       emitcode ("mov", "%s,a", reg->name);
2392                     }
2393                 }
2394             }
2395           emitcode ("mov", "%s,r0", spname);
2396           if (bitVectBitValue (rsave, R0_IDX))
2397             {
2398               emitcode ("pop", "ar0");
2399             }
2400         }
2401     }
2402   else
2403     {
2404       bool bits_popped = FALSE;
2405       for (i = mcs51_nRegs; i >= 0; i--)
2406         {
2407           if (bitVectBitValue (rsave, i))
2408             {
2409               bits_popped = popReg (i, bits_popped);
2410             }
2411         }
2412     }
2413   freeBitVect (rsave);
2414 }
2415
2416
2417 /*-----------------------------------------------------------------*/
2418 /* pushSide -                                                      */
2419 /*-----------------------------------------------------------------*/
2420 static void
2421 pushSide (operand * oper, int size)
2422 {
2423   int offset = 0;
2424   while (size--)
2425     {
2426       char *l = aopGet (oper, offset++, FALSE, TRUE);
2427       if (AOP_TYPE (oper) != AOP_REG &&
2428           AOP_TYPE (oper) != AOP_DIR &&
2429           strcmp (l, "a"))
2430         {
2431           MOVA (l);
2432           emitcode ("push", "acc");
2433         }
2434       else
2435         {
2436           emitcode ("push", "%s", l);
2437         }
2438     }
2439 }
2440
2441 /*-----------------------------------------------------------------*/
2442 /* assignResultValue - also indicates if acc is in use afterwards  */
2443 /*-----------------------------------------------------------------*/
2444 static bool
2445 assignResultValue (operand * oper, operand * func)
2446 {
2447   int offset = 0;
2448   int size = AOP_SIZE (oper);
2449   bool accuse = FALSE;
2450   bool pushedA = FALSE;
2451
2452   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2453     {
2454       outBitC (oper);
2455       return FALSE;
2456     }
2457
2458   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2459     {
2460       emitcode ("push", "acc");
2461       pushedA = TRUE;
2462     }
2463   while (size--)
2464     {
2465       if ((offset == 3) && pushedA)
2466         emitcode ("pop", "acc");
2467       accuse |= aopPut (oper, fReturn[offset], offset);
2468       offset++;
2469     }
2470   return accuse;
2471 }
2472
2473
2474 /*-----------------------------------------------------------------*/
2475 /* genXpush - pushes onto the external stack                       */
2476 /*-----------------------------------------------------------------*/
2477 static void
2478 genXpush (iCode * ic)
2479 {
2480   asmop *aop = newAsmop (0);
2481   regs *r;
2482   int size, offset = 0;
2483
2484   D (emitcode (";", "genXpush"));
2485
2486   aopOp (IC_LEFT (ic), ic, FALSE);
2487   r = getFreePtr (ic, &aop, FALSE);
2488
2489   size = AOP_SIZE (IC_LEFT (ic));
2490
2491   if (size == 1)
2492     {
2493       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2494       emitcode ("mov", "%s,%s", r->name, spname);
2495       emitcode ("inc", "%s", spname); // allocate space first
2496       emitcode ("movx", "@%s,a", r->name);
2497     }
2498   else
2499     {
2500       // allocate space first
2501       emitcode ("mov", "%s,%s", r->name, spname);
2502       MOVA (r->name);
2503       emitcode ("add", "a,#%d", size);
2504       emitcode ("mov", "%s,a", spname);
2505
2506       while (size--)
2507         {
2508           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2509           emitcode ("movx", "@%s,a", r->name);
2510           emitcode ("inc", "%s", r->name);
2511         }
2512     }
2513
2514   freeAsmop (NULL, aop, ic, TRUE);
2515   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2516 }
2517
2518 /*-----------------------------------------------------------------*/
2519 /* genIpush - generate code for pushing this gets a little complex */
2520 /*-----------------------------------------------------------------*/
2521 static void
2522 genIpush (iCode * ic)
2523 {
2524   int size, offset = 0;
2525   char *l;
2526   char *prev = "";
2527
2528   D (emitcode (";", "genIpush"));
2529
2530   /* if this is not a parm push : ie. it is spill push
2531      and spill push is always done on the local stack */
2532   if (!ic->parmPush)
2533     {
2534
2535       /* and the item is spilt then do nothing */
2536       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2537         return;
2538
2539       aopOp (IC_LEFT (ic), ic, FALSE);
2540       size = AOP_SIZE (IC_LEFT (ic));
2541       /* push it on the stack */
2542       while (size--)
2543         {
2544           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2545           if (*l == '#')
2546             {
2547               MOVA (l);
2548               l = "acc";
2549             }
2550           emitcode ("push", "%s", l);
2551         }
2552       return;
2553     }
2554
2555   /* this is a parameter push: in this case we call
2556      the routine to find the call and save those
2557      registers that need to be saved */
2558   saveRegisters (ic);
2559
2560   /* if use external stack then call the external
2561      stack pushing routine */
2562   if (options.useXstack)
2563     {
2564       genXpush (ic);
2565       return;
2566     }
2567
2568   /* then do the push */
2569   aopOp (IC_LEFT (ic), ic, FALSE);
2570
2571   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2572   size = AOP_SIZE (IC_LEFT (ic));
2573
2574   while (size--)
2575     {
2576       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2577       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2578           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2579         {
2580           if (strcmp (l, prev) || *l == '@')
2581             MOVA (l);
2582           emitcode ("push", "acc");
2583         }
2584       else
2585         {
2586           emitcode ("push", "%s", l);
2587         }
2588       prev = l;
2589     }
2590
2591   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2592 }
2593
2594 /*-----------------------------------------------------------------*/
2595 /* genIpop - recover the registers: can happen only for spilling   */
2596 /*-----------------------------------------------------------------*/
2597 static void
2598 genIpop (iCode * ic)
2599 {
2600   int size, offset;
2601
2602   D (emitcode (";", "genIpop"));
2603
2604   /* if the temp was not pushed then */
2605   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2606     return;
2607
2608   aopOp (IC_LEFT (ic), ic, FALSE);
2609   size = AOP_SIZE (IC_LEFT (ic));
2610   offset = (size - 1);
2611   while (size--)
2612     {
2613       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2614                                      FALSE, TRUE));
2615     }
2616
2617   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2618 }
2619
2620 /*-----------------------------------------------------------------*/
2621 /* saveRBank - saves an entire register bank on the stack          */
2622 /*-----------------------------------------------------------------*/
2623 static void
2624 saveRBank (int bank, iCode * ic, bool pushPsw)
2625 {
2626   int i;
2627   int count = 8 + (pushPsw ? 1 : 0);
2628   asmop *aop = NULL;
2629   regs *r = NULL;
2630
2631   if (options.useXstack)
2632     {
2633       if (!ic)
2634         {
2635           /* Assume r0 is available for use. */
2636           r = REG_WITH_INDEX (R0_IDX);
2637         }
2638       else
2639         {
2640           aop = newAsmop (0);
2641           r = getFreePtr (ic, &aop, FALSE);
2642         }
2643       // allocate space first
2644       emitcode ("mov", "%s,%s", r->name, spname);
2645       MOVA (r->name);
2646       emitcode ("add", "a,#%d", count);
2647       emitcode ("mov", "%s,a", spname);
2648     }
2649
2650   for (i = 0; i < 8; i++)
2651     {
2652       if (options.useXstack)
2653         {
2654           emitcode ("mov", "a,(%s+%d)",
2655                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2656           emitcode ("movx", "@%s,a", r->name);
2657           if (--count)
2658             emitcode ("inc", "%s", r->name);
2659         }
2660       else
2661         emitcode ("push", "(%s+%d)",
2662                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2663     }
2664
2665   if (pushPsw)
2666     {
2667       if (options.useXstack)
2668         {
2669           emitcode ("mov", "a,psw");
2670           emitcode ("movx", "@%s,a", r->name);
2671         }
2672       else
2673         {
2674           emitcode ("push", "psw");
2675         }
2676
2677       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2678     }
2679
2680   if (aop)
2681     {
2682       freeAsmop (NULL, aop, ic, TRUE);
2683     }
2684
2685   if (ic)
2686     {
2687       ic->bankSaved = 1;
2688     }
2689 }
2690
2691 /*-----------------------------------------------------------------*/
2692 /* unsaveRBank - restores the register bank from stack             */
2693 /*-----------------------------------------------------------------*/
2694 static void
2695 unsaveRBank (int bank, iCode * ic, bool popPsw)
2696 {
2697   int i;
2698   asmop *aop = NULL;
2699   regs *r = NULL;
2700
2701   if (options.useXstack)
2702     {
2703       if (!ic)
2704         {
2705           /* Assume r0 is available for use. */
2706           r = REG_WITH_INDEX (R0_IDX);;
2707         }
2708       else
2709         {
2710           aop = newAsmop (0);
2711           r = getFreePtr (ic, &aop, FALSE);
2712         }
2713       emitcode ("mov", "%s,%s", r->name, spname);
2714     }
2715
2716   if (popPsw)
2717     {
2718       if (options.useXstack)
2719         {
2720           emitcode ("dec", "%s", r->name);
2721           emitcode ("movx", "a,@%s", r->name);
2722           emitcode ("mov", "psw,a");
2723         }
2724       else
2725         {
2726           emitcode ("pop", "psw");
2727         }
2728     }
2729
2730   for (i = 7; i >= 0; i--)
2731     {
2732       if (options.useXstack)
2733         {
2734           emitcode ("dec", "%s", r->name);
2735           emitcode ("movx", "a,@%s", r->name);
2736           emitcode ("mov", "(%s+%d),a",
2737                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2738         }
2739       else
2740         {
2741           emitcode ("pop", "(%s+%d)",
2742                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2743         }
2744     }
2745
2746   if (options.useXstack)
2747     {
2748       emitcode ("mov", "%s,%s", spname, r->name);
2749     }
2750
2751   if (aop)
2752     {
2753       freeAsmop (NULL, aop, ic, TRUE);
2754     }
2755 }
2756
2757 /*-----------------------------------------------------------------*/
2758 /* genSend - gen code for SEND                                     */
2759 /*-----------------------------------------------------------------*/
2760 static void genSend(set *sendSet)
2761 {
2762   iCode *sic;
2763   int bit_count = 0;
2764
2765   /* first we do all bit parameters */
2766   for (sic = setFirstItem (sendSet); sic;
2767        sic = setNextItem (sendSet))
2768     {
2769       if (sic->argreg > 12)
2770         {
2771           int bit = sic->argreg-13;
2772
2773           aopOp (IC_LEFT (sic), sic, FALSE);
2774
2775           /* if left is a literal then
2776              we know what the value is */
2777           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2778             {
2779               if (((int) operandLitValue (IC_LEFT (sic))))
2780                   emitcode ("setb", "b[%d]", bit);
2781               else
2782                   emitcode ("clr", "b[%d]", bit);
2783             }
2784           else
2785             {
2786               /* we need to or */
2787               toCarry (IC_LEFT (sic));
2788               emitcode ("mov", "b[%d],c", bit);
2789             }
2790           bit_count++;
2791           BitBankUsed = 1;
2792
2793           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2794         }
2795     }
2796
2797   if (bit_count)
2798     {
2799       saveRegisters (setFirstItem (sendSet));
2800       emitcode ("mov", "bits,b");
2801     }
2802
2803   /* then we do all other parameters */
2804   for (sic = setFirstItem (sendSet); sic;
2805        sic = setNextItem (sendSet))
2806     {
2807       if (sic->argreg <= 12)
2808         {
2809           int size, offset = 0;
2810           aopOp (IC_LEFT (sic), sic, FALSE);
2811           size = AOP_SIZE (IC_LEFT (sic));
2812
2813           if (sic->argreg == 1)
2814             {
2815               while (size--)
2816                 {
2817                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2818                   if (strcmp (l, fReturn[offset]))
2819                     {
2820                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2821                     }
2822                   offset++;
2823                 }
2824             }
2825           else
2826             {
2827               while (size--)
2828                 {
2829                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2830                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2831                   offset++;
2832                 }
2833             }
2834           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2835         }
2836     }
2837 }
2838
2839 /*-----------------------------------------------------------------*/
2840 /* selectRegBank - emit code to select the register bank           */
2841 /*-----------------------------------------------------------------*/
2842 static void
2843 selectRegBank (short bank, bool keepFlags)
2844 {
2845   /* if f.e. result is in carry */
2846   if (keepFlags)
2847     {
2848       emitcode ("anl", "psw,#0xE7");
2849       if (bank)
2850         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2851     }
2852   else
2853     {
2854       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2855     }
2856 }
2857
2858 /*-----------------------------------------------------------------*/
2859 /* genCall - generates a call statement                            */
2860 /*-----------------------------------------------------------------*/
2861 static void
2862 genCall (iCode * ic)
2863 {
2864   sym_link *dtype;
2865   sym_link *etype;
2866 //  bool restoreBank = FALSE;
2867   bool swapBanks = FALSE;
2868   bool accuse = FALSE;
2869   bool accPushed = FALSE;
2870   bool resultInF0 = FALSE;
2871   bool assignResultGenerated = FALSE;
2872
2873   D (emitcode (";", "genCall"));
2874
2875   dtype = operandType (IC_LEFT (ic));
2876   etype = getSpec(dtype);
2877   /* if send set is not empty then assign */
2878   if (_G.sendSet)
2879     {
2880         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2881             genSend(reverseSet(_G.sendSet));
2882         } else {
2883             genSend(_G.sendSet);
2884         }
2885       _G.sendSet = NULL;
2886     }
2887
2888   /* if we are calling a not _naked function that is not using
2889      the same register bank then we need to save the
2890      destination registers on the stack */
2891   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2892       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2893        !IFFUNC_ISISR (dtype))
2894     {
2895       swapBanks = TRUE;
2896     }
2897
2898   /* if caller saves & we have not saved then */
2899   if (!ic->regsSaved)
2900       saveRegisters (ic);
2901
2902   if (swapBanks)
2903     {
2904         emitcode ("mov", "psw,#0x%02x",
2905            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2906     }
2907
2908   /* make the call */
2909   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2910     {
2911       if (IFFUNC_CALLEESAVES(dtype))
2912         {
2913           werror (E_BANKED_WITH_CALLEESAVES);
2914         }
2915       else
2916         {
2917           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2918                      OP_SYMBOL (IC_LEFT (ic))->rname :
2919                      OP_SYMBOL (IC_LEFT (ic))->name);
2920
2921           emitcode ("mov", "r0,#%s", l);
2922           emitcode ("mov", "r1,#(%s >> 8)", l);
2923           emitcode ("mov", "r2,#(%s >> 16)", l);
2924           emitcode ("lcall", "__sdcc_banked_call");
2925         }
2926     }
2927   else
2928     {
2929       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2930                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2931                                 OP_SYMBOL (IC_LEFT (ic))->name));
2932     }
2933
2934   if (swapBanks)
2935     {
2936       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2937     }
2938
2939   /* if we need assign a result value */
2940   if ((IS_ITEMP (IC_RESULT (ic)) &&
2941        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2942        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2943         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2944         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2945       IS_TRUE_SYMOP (IC_RESULT (ic)))
2946     {
2947
2948       _G.accInUse++;
2949       aopOp (IC_RESULT (ic), ic, FALSE);
2950       _G.accInUse--;
2951
2952       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2953       assignResultGenerated = TRUE;
2954
2955       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2956     }
2957
2958   /* adjust the stack for parameters if required */
2959   if (ic->parmBytes)
2960     {
2961       int i;
2962       if (ic->parmBytes > 3)
2963         {
2964           if (accuse)
2965             {
2966               emitcode ("push", "acc");
2967               accPushed = TRUE;
2968             }
2969           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2970               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2971               !assignResultGenerated)
2972             {
2973               emitcode ("mov", "F0,c");
2974               resultInF0 = TRUE;
2975             }
2976
2977           emitcode ("mov", "a,%s", spname);
2978           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2979           emitcode ("mov", "%s,a", spname);
2980
2981           /* unsaveRegisters from xstack needs acc, but */
2982           /* unsaveRegisters from stack needs this popped */
2983           if (accPushed && !options.useXstack)
2984             {
2985               emitcode ("pop", "acc");
2986               accPushed = FALSE;
2987             }
2988         }
2989       else
2990         for (i = 0; i < ic->parmBytes; i++)
2991           emitcode ("dec", "%s", spname);
2992     }
2993
2994   /* if we had saved some registers then unsave them */
2995   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2996     {
2997       if (accuse && !accPushed && options.useXstack)
2998         {
2999           /* xstack needs acc, but doesn't touch normal stack */
3000           emitcode ("push", "acc");
3001           accPushed = TRUE;
3002         }
3003       unsaveRegisters (ic);
3004     }
3005
3006 //  /* if register bank was saved then pop them */
3007 //  if (restoreBank)
3008 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3009
3010   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3011     {
3012       if (resultInF0)
3013           emitcode ("mov", "c,F0");
3014
3015       aopOp (IC_RESULT (ic), ic, FALSE);
3016       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3017       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3018     }
3019
3020   if (accPushed)
3021     emitcode ("pop", "acc");
3022 }
3023
3024 /*-----------------------------------------------------------------*/
3025 /* genPcall - generates a call by pointer statement                */
3026 /*-----------------------------------------------------------------*/
3027 static void
3028 genPcall (iCode * ic)
3029 {
3030   sym_link *dtype;
3031   sym_link *etype;
3032   symbol *rlbl = newiTempLabel (NULL);
3033 //  bool restoreBank=FALSE;
3034   bool swapBanks = FALSE;
3035   bool resultInF0 = FALSE;
3036
3037   D (emitcode (";", "genPcall"));
3038
3039   dtype = operandType (IC_LEFT (ic))->next;
3040   etype = getSpec(dtype);
3041   /* if caller saves & we have not saved then */
3042   if (!ic->regsSaved)
3043     saveRegisters (ic);
3044
3045   /* if we are calling a not _naked function that is not using
3046      the same register bank then we need to save the
3047      destination registers on the stack */
3048   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3049       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3050       !IFFUNC_ISISR (dtype))
3051     {
3052 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3053 //    restoreBank=TRUE;
3054       swapBanks = TRUE;
3055       // need caution message to user here
3056     }
3057
3058   if (IS_LITERAL (etype))
3059     {
3060       /* if send set is not empty then assign */
3061       if (_G.sendSet)
3062         {
3063           genSend(reverseSet(_G.sendSet));
3064           _G.sendSet = NULL;
3065         }
3066
3067       if (swapBanks)
3068         {
3069           emitcode ("mov", "psw,#0x%02x",
3070            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3071         }
3072
3073       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3074         {
3075           if (IFFUNC_CALLEESAVES (dtype))
3076             {
3077               werror (E_BANKED_WITH_CALLEESAVES);
3078             }
3079           else
3080             {
3081               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3082
3083               emitcode ("mov", "r0,#%s", l);
3084               emitcode ("mov", "r1,#(%s >> 8)", l);
3085               emitcode ("mov", "r2,#(%s >> 16)", l);
3086               emitcode ("lcall", "__sdcc_banked_call");
3087             }
3088         }
3089       else
3090         {
3091           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3092         }
3093     }
3094   else
3095     {
3096       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3097         {
3098           if (IFFUNC_CALLEESAVES (dtype))
3099             {
3100               werror (E_BANKED_WITH_CALLEESAVES);
3101             }
3102           else
3103             {
3104               aopOp (IC_LEFT (ic), ic, FALSE);
3105
3106               if (!swapBanks)
3107                 {
3108                   /* what if aopGet needs r0 or r1 ??? */
3109                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3110                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3111                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3112                 }
3113               else
3114                 {
3115                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3116                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3117                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3118                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3119                 }
3120
3121               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3122
3123               /* if send set is not empty then assign */
3124               if (_G.sendSet)
3125                 {
3126                   genSend(reverseSet(_G.sendSet));
3127                   _G.sendSet = NULL;
3128                 }
3129
3130               if (swapBanks)
3131                 {
3132                   emitcode ("mov", "psw,#0x%02x",
3133                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3134                 }
3135
3136               /* make the call */
3137               emitcode ("lcall", "__sdcc_banked_call");
3138             }
3139         }
3140       else if (_G.sendSet)
3141         {
3142           /* push the return address on to the stack */
3143           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3144           emitcode ("push", "acc");
3145           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3146           emitcode ("push", "acc");
3147
3148           /* now push the calling address */
3149           aopOp (IC_LEFT (ic), ic, FALSE);
3150
3151           pushSide (IC_LEFT (ic), FPTRSIZE);
3152
3153           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3154
3155           /* if send set is not empty the assign */
3156           if (_G.sendSet)
3157             {
3158               genSend(reverseSet(_G.sendSet));
3159               _G.sendSet = NULL;
3160             }
3161
3162           if (swapBanks)
3163             {
3164               emitcode ("mov", "psw,#0x%02x",
3165                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3166             }
3167
3168           /* make the call */
3169           emitcode ("ret", "");
3170           emitLabel (rlbl);
3171         }
3172       else /* the send set is empty */
3173         {
3174           char *l;
3175           /* now get the calling address into dptr */
3176           aopOp (IC_LEFT (ic), ic, FALSE);
3177
3178           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3179           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3180             {
3181               emitcode ("mov", "r0,%s", l);
3182               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3183               emitcode ("mov", "dph,%s", l);
3184               emitcode ("mov", "dpl,r0");
3185             }
3186           else
3187             {
3188               emitcode ("mov", "dpl,%s", l);
3189               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3190               emitcode ("mov", "dph,%s", l);
3191             }
3192
3193           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3194
3195           if (swapBanks)
3196             {
3197               emitcode ("mov", "psw,#0x%02x",
3198                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3199             }
3200
3201           /* make the call */
3202           emitcode ("lcall", "__sdcc_call_dptr");
3203         }
3204     }
3205   if (swapBanks)
3206     {
3207       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3208     }
3209
3210   /* if we need assign a result value */
3211   if ((IS_ITEMP (IC_RESULT (ic)) &&
3212        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3213        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3214         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3215       IS_TRUE_SYMOP (IC_RESULT (ic)))
3216     {
3217
3218       _G.accInUse++;
3219       aopOp (IC_RESULT (ic), ic, FALSE);
3220       _G.accInUse--;
3221
3222       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3223
3224       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3225     }
3226
3227   /* adjust the stack for parameters if required */
3228   if (ic->parmBytes)
3229     {
3230       int i;
3231       if (ic->parmBytes > 3)
3232         {
3233           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3234               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3235             {
3236               emitcode ("mov", "F0,c");
3237               resultInF0 = TRUE;
3238             }
3239
3240           emitcode ("mov", "a,%s", spname);
3241           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3242           emitcode ("mov", "%s,a", spname);
3243         }
3244       else
3245         for (i = 0; i < ic->parmBytes; i++)
3246           emitcode ("dec", "%s", spname);
3247     }
3248
3249 //  /* if register bank was saved then unsave them */
3250 //  if (restoreBank)
3251 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3252
3253   /* if we had saved some registers then unsave them */
3254   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3255     unsaveRegisters (ic);
3256
3257   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3258     {
3259       if (resultInF0)
3260           emitcode ("mov", "c,F0");
3261
3262       aopOp (IC_RESULT (ic), ic, FALSE);
3263       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3264       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3265     }
3266 }
3267
3268 /*-----------------------------------------------------------------*/
3269 /* resultRemat - result  is rematerializable                       */
3270 /*-----------------------------------------------------------------*/
3271 static int
3272 resultRemat (iCode * ic)
3273 {
3274   if (SKIP_IC (ic) || ic->op == IFX)
3275     return 0;
3276
3277   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3278     {
3279       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3280       if (sym->remat && !POINTER_SET (ic))
3281         return 1;
3282     }
3283
3284   return 0;
3285 }
3286
3287 /*-----------------------------------------------------------------*/
3288 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3289 /*-----------------------------------------------------------------*/
3290 static int
3291 regsCmp(void *p1, void *p2)
3292 {
3293   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3294 }
3295
3296 static bool
3297 inExcludeList (char *s)
3298 {
3299   const char *p = setFirstItem(options.excludeRegsSet);
3300
3301   if (p == NULL || STRCASECMP(p, "none") == 0)
3302     return FALSE;
3303
3304
3305   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3306 }
3307
3308 /*-----------------------------------------------------------------*/
3309 /* genFunction - generated code for function entry                 */
3310 /*-----------------------------------------------------------------*/
3311 static void
3312 genFunction (iCode * ic)
3313 {
3314   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3315   sym_link *ftype;
3316   bool     switchedPSW = FALSE;
3317   int      calleesaves_saved_register = -1;
3318   int      stackAdjust = sym->stack;
3319   int      accIsFree = sym->recvSize < 4;
3320   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3321   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3322
3323   _G.nRegsSaved = 0;
3324   /* create the function header */
3325   emitcode (";", "-----------------------------------------");
3326   emitcode (";", " function %s", sym->name);
3327   emitcode (";", "-----------------------------------------");
3328
3329   emitcode ("", "%s:", sym->rname);
3330   lineCurr->isLabel = 1;
3331   ftype = operandType (IC_LEFT (ic));
3332   _G.currentFunc = sym;
3333
3334   if (IFFUNC_ISNAKED(ftype))
3335   {
3336       emitcode(";", "naked function: no prologue.");
3337       return;
3338   }
3339
3340   /* here we need to generate the equates for the
3341      register bank if required */
3342   if (FUNC_REGBANK (ftype) != rbank)
3343     {
3344       int i;
3345
3346       rbank = FUNC_REGBANK (ftype);
3347       for (i = 0; i < mcs51_nRegs; i++)
3348         {
3349           if (regs8051[i].type != REG_BIT)
3350             {
3351               if (strcmp (regs8051[i].base, "0") == 0)
3352                 emitcode ("", "%s = 0x%02x",
3353                           regs8051[i].dname,
3354                           8 * rbank + regs8051[i].offset);
3355               else
3356                 emitcode ("", "%s = %s + 0x%02x",
3357                           regs8051[i].dname,
3358                           regs8051[i].base,
3359                           8 * rbank + regs8051[i].offset);
3360             }
3361         }
3362     }
3363
3364   /* if this is an interrupt service routine then
3365      save acc, b, dpl, dph  */
3366   if (IFFUNC_ISISR (sym->type))
3367     {
3368       bitVect *rsavebits;
3369
3370       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3371       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3372         {
3373           emitcode ("push", "bits");
3374           BitBankUsed = 1;
3375         }
3376       freeBitVect (rsavebits);
3377
3378       if (!inExcludeList ("acc"))
3379         emitcode ("push", "acc");
3380       if (!inExcludeList ("b"))
3381         emitcode ("push", "b");
3382       if (!inExcludeList ("dpl"))
3383         emitcode ("push", "dpl");
3384       if (!inExcludeList ("dph"))
3385         emitcode ("push", "dph");
3386       /* if this isr has no bank i.e. is going to
3387          run with bank 0 , then we need to save more
3388          registers :-) */
3389       if (!FUNC_REGBANK (sym->type))
3390         {
3391           int i;
3392
3393           /* if this function does not call any other
3394              function then we can be economical and
3395              save only those registers that are used */
3396           if (!IFFUNC_HASFCALL(sym->type))
3397             {
3398               /* if any registers used */
3399               if (sym->regsUsed)
3400                 {
3401                   /* save the registers used */
3402                   for (i = 0; i < sym->regsUsed->size; i++)
3403                     {
3404                       if (bitVectBitValue (sym->regsUsed, i))
3405                         pushReg (i, TRUE);
3406                     }
3407                 }
3408             }
3409           else
3410             {
3411               /* this function has a function call. We cannot
3412                  determine register usage so we will have to push the
3413                  entire bank */
3414                 saveRBank (0, ic, FALSE);
3415                 if (options.parms_in_bank1) {
3416                     for (i=0; i < 8 ; i++ ) {
3417                         emitcode ("push","%s",rb1regs[i]);
3418                     }
3419                 }
3420             }
3421         }
3422       else
3423         {
3424             /* This ISR uses a non-zero bank.
3425              *
3426              * We assume that the bank is available for our
3427              * exclusive use.
3428              *
3429              * However, if this ISR calls a function which uses some
3430              * other bank, we must save that bank entirely.
3431              */
3432             unsigned long banksToSave = 0;
3433
3434             if (IFFUNC_HASFCALL(sym->type))
3435             {
3436
3437 #define MAX_REGISTER_BANKS 4
3438
3439                 iCode *i;
3440                 int ix;
3441
3442                 for (i = ic; i; i = i->next)
3443                 {
3444                     if (i->op == ENDFUNCTION)
3445                     {
3446                         /* we got to the end OK. */
3447                         break;
3448                     }
3449
3450                     if (i->op == CALL)
3451                     {
3452                         sym_link *dtype;
3453
3454                         dtype = operandType (IC_LEFT(i));
3455                         if (dtype
3456                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3457                         {
3458                              /* Mark this bank for saving. */
3459                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3460                              {
3461                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3462                              }
3463                              else
3464                              {
3465                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3466                              }
3467
3468                              /* And note that we don't need to do it in
3469                               * genCall.
3470                               */
3471                              i->bankSaved = 1;
3472                         }
3473                     }
3474                     if (i->op == PCALL)
3475                     {
3476                         /* This is a mess; we have no idea what
3477                          * register bank the called function might
3478                          * use.
3479                          *
3480                          * The only thing I can think of to do is
3481                          * throw a warning and hope.
3482                          */
3483                         werror(W_FUNCPTR_IN_USING_ISR);
3484                     }
3485                 }
3486
3487                 if (banksToSave && options.useXstack)
3488                 {
3489                     /* Since we aren't passing it an ic,
3490                      * saveRBank will assume r0 is available to abuse.
3491                      *
3492                      * So switch to our (trashable) bank now, so
3493                      * the caller's R0 isn't trashed.
3494                      */
3495                     emitcode ("push", "psw");
3496                     emitcode ("mov", "psw,#0x%02x",
3497                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3498                     switchedPSW = TRUE;
3499                 }
3500
3501                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3502                 {
3503                      if (banksToSave & (1 << ix))
3504                      {
3505                          saveRBank(ix, NULL, FALSE);
3506                      }
3507                 }
3508             }
3509             // TODO: this needs a closer look
3510             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3511         }
3512
3513       /* Set the register bank to the desired value if nothing else */
3514       /* has done so yet. */
3515       if (!switchedPSW)
3516         {
3517           emitcode ("push", "psw");
3518           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3519         }
3520     }
3521   else
3522     {
3523       /* This is a non-ISR function. The caller has already switched register */
3524       /* banks, if necessary, so just handle the callee-saves option. */
3525
3526       /* if callee-save to be used for this function
3527          then save the registers being used in this function */
3528       if (IFFUNC_CALLEESAVES(sym->type))
3529         {
3530           int i;
3531
3532           /* if any registers used */
3533           if (sym->regsUsed)
3534             {
3535               bool bits_pushed = FALSE;
3536               /* save the registers used */
3537               for (i = 0; i < sym->regsUsed->size; i++)
3538                 {
3539                   if (bitVectBitValue (sym->regsUsed, i))
3540                     {
3541                       /* remember one saved register for later usage */
3542                       if (calleesaves_saved_register < 0)
3543                         calleesaves_saved_register = i;
3544                       bits_pushed = pushReg (i, bits_pushed);
3545                       _G.nRegsSaved++;
3546                     }
3547                 }
3548             }
3549         }
3550     }
3551
3552   if (fReentrant)
3553     {
3554       if (options.useXstack)
3555         {
3556           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3557             {
3558               emitcode ("mov", "r0,%s", spname);
3559               emitcode ("inc", "%s", spname);
3560               emitcode ("xch", "a,_bpx");
3561               emitcode ("movx", "@r0,a");
3562               emitcode ("inc", "r0");
3563               emitcode ("mov", "a,r0");
3564               emitcode ("xch", "a,_bpx");
3565             }
3566           if (sym->stack)
3567             {
3568               emitcode ("push", "_bp");     /* save the callers stack  */
3569               emitcode ("mov", "_bp,sp");
3570             }
3571         }
3572       else
3573         {
3574           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3575             {
3576               /* set up the stack */
3577               emitcode ("push", "_bp");     /* save the callers stack  */
3578               emitcode ("mov", "_bp,sp");
3579             }
3580         }
3581     }
3582
3583   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3584   /* before setting up the stack frame completely. */
3585   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3586     {
3587       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3588
3589       if (rsym->isitmp)
3590         {
3591           if (rsym && rsym->regType == REG_CND)
3592             rsym = NULL;
3593           if (rsym && (rsym->accuse || rsym->ruonly))
3594             rsym = NULL;
3595           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3596             rsym = rsym->usl.spillLoc;
3597         }
3598
3599       /* If the RECEIVE operand immediately spills to the first entry on the */
3600       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3601       /* rather than the usual @r0/r1 machinations. */
3602       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3603         {
3604           int ofs;
3605
3606           _G.current_iCode = ric;
3607           D(emitcode (";", "genReceive"));
3608           for (ofs=0; ofs < sym->recvSize; ofs++)
3609             {
3610               if (!strcmp (fReturn[ofs], "a"))
3611                 emitcode ("push", "acc");
3612               else
3613                 emitcode ("push", fReturn[ofs]);
3614             }
3615           stackAdjust -= sym->recvSize;
3616           if (stackAdjust<0)
3617             {
3618               assert (stackAdjust>=0);
3619               stackAdjust = 0;
3620             }
3621           _G.current_iCode = ic;
3622           ric->generated = 1;
3623           accIsFree = 1;
3624         }
3625       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3626       /* to free up the accumulator. */
3627       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3628         {
3629           int ofs;
3630
3631           _G.current_iCode = ric;
3632           D(emitcode (";", "genReceive"));
3633           for (ofs=0; ofs < sym->recvSize; ofs++)
3634             {
3635               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3636             }
3637           _G.current_iCode = ic;
3638           ric->generated = 1;
3639           accIsFree = 1;
3640         }
3641     }
3642
3643   /* adjust the stack for the function */
3644   if (stackAdjust)
3645     {
3646       int i = stackAdjust;
3647       if (i > 256)
3648         werror (W_STACK_OVERFLOW, sym->name);
3649
3650       if (i > 3 && accIsFree)
3651         {
3652           emitcode ("mov", "a,sp");
3653           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3654           emitcode ("mov", "sp,a");
3655         }
3656       else if (i > 5)
3657         {
3658           /* The accumulator is not free, so we will need another register */
3659           /* to clobber. No need to worry about a possible conflict with */
3660           /* the above early RECEIVE optimizations since they would have */
3661           /* freed the accumulator if they were generated. */
3662
3663           if (IFFUNC_CALLEESAVES(sym->type))
3664             {
3665               /* if it's a callee-saves function we need a saved register */
3666               if (calleesaves_saved_register >= 0)
3667                 {
3668                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3669                   emitcode ("mov", "a,sp");
3670                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3671                   emitcode ("mov", "sp,a");
3672                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3673                 }
3674               else
3675                 /* do it the hard way */
3676                 while (i--)
3677                   emitcode ("inc", "sp");
3678             }
3679           else
3680             {
3681               /* not callee-saves, we can clobber r0 */
3682               emitcode ("mov", "r0,a");
3683               emitcode ("mov", "a,sp");
3684               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3685               emitcode ("mov", "sp,a");
3686               emitcode ("mov", "a,r0");
3687             }
3688         }
3689       else
3690         while (i--)
3691           emitcode ("inc", "sp");
3692     }
3693
3694   if (sym->xstack)
3695     {
3696       char i = ((char) sym->xstack & 0xff);
3697
3698       if (i > 3 && accIsFree)
3699         {
3700           emitcode ("mov", "a,_spx");
3701           emitcode ("add", "a,#0x%02x", i & 0xff);
3702           emitcode ("mov", "_spx,a");
3703         }
3704       else if (i > 5)
3705         {
3706           emitcode ("push", "acc");
3707           emitcode ("mov", "a,_spx");
3708           emitcode ("add", "a,#0x%02x", i & 0xff);
3709           emitcode ("mov", "_spx,a");
3710           emitcode ("pop", "acc");
3711         }
3712       else
3713         {
3714           while (i--)
3715             emitcode ("inc", "_spx");
3716         }
3717     }
3718
3719   /* if critical function then turn interrupts off */
3720   if (IFFUNC_ISCRITICAL (ftype))
3721     {
3722       symbol *tlbl = newiTempLabel (NULL);
3723       emitcode ("setb", "c");
3724       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3725       emitcode ("clr", "c");
3726       emitLabel (tlbl);
3727       emitcode ("push", "psw"); /* save old ea via c in psw */
3728     }
3729 }
3730
3731 /*-----------------------------------------------------------------*/
3732 /* genEndFunction - generates epilogue for functions               */
3733 /*-----------------------------------------------------------------*/
3734 static void
3735 genEndFunction (iCode * ic)
3736 {
3737   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3738   lineNode *lnp = lineCurr;
3739   bitVect  *regsUsed;
3740   bitVect  *regsUsedPrologue;
3741   bitVect  *regsUnneeded;
3742   int      idx;
3743
3744   _G.currentFunc = NULL;
3745   if (IFFUNC_ISNAKED(sym->type))
3746   {
3747       emitcode(";", "naked function: no epilogue.");
3748       if (options.debug && currFunc)
3749         debugFile->writeEndFunction (currFunc, ic, 0);
3750       return;
3751   }
3752
3753   if (IFFUNC_ISCRITICAL (sym->type))
3754     {
3755       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3756         {
3757           emitcode ("rlc", "a");   /* save c in a */
3758           emitcode ("pop", "psw"); /* restore ea via c in psw */
3759           emitcode ("mov", "ea,c");
3760           emitcode ("rrc", "a");   /* restore c from a */
3761         }
3762       else
3763         {
3764           emitcode ("pop", "psw"); /* restore ea via c in psw */
3765           emitcode ("mov", "ea,c");
3766         }
3767     }
3768
3769   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3770     {
3771       if (options.useXstack)
3772         {
3773           if (sym->stack)
3774             {
3775               emitcode ("mov", "sp,_bp");
3776               emitcode ("pop", "_bp");
3777             }
3778           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3779             {
3780               emitcode ("xch", "a,_bpx");
3781               emitcode ("mov", "r0,a");
3782               emitcode ("dec", "r0");
3783               emitcode ("movx", "a,@r0");
3784               emitcode ("xch", "a,_bpx");
3785               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3786             }
3787         }
3788       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3789         {
3790           if (sym->stack)
3791             emitcode ("mov", "sp,_bp");
3792           emitcode ("pop", "_bp");
3793         }
3794     }
3795
3796   /* restore the register bank  */
3797   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3798   {
3799     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3800      || !options.useXstack)
3801     {
3802         /* Special case of ISR using non-zero bank with useXstack
3803          * is handled below.
3804          */
3805         emitcode ("pop", "psw");
3806     }
3807   }
3808
3809   if (IFFUNC_ISISR (sym->type))
3810     {
3811       bitVect *rsavebits;
3812
3813       /* now we need to restore the registers */
3814       /* if this isr has no bank i.e. is going to
3815          run with bank 0 , then we need to save more
3816          registers :-) */
3817       if (!FUNC_REGBANK (sym->type))
3818         {
3819           int i;
3820           /* if this function does not call any other
3821              function then we can be economical and
3822              save only those registers that are used */
3823           if (!IFFUNC_HASFCALL(sym->type))
3824             {
3825               /* if any registers used */
3826               if (sym->regsUsed)
3827                 {
3828                   /* save the registers used */
3829                   for (i = sym->regsUsed->size; i >= 0; i--)
3830                     {
3831                       if (bitVectBitValue (sym->regsUsed, i))
3832                         popReg (i, TRUE);
3833                     }
3834                 }
3835             }
3836           else
3837             {
3838               if (options.parms_in_bank1) {
3839                   for (i = 7 ; i >= 0 ; i-- ) {
3840                       emitcode ("pop","%s",rb1regs[i]);
3841                   }
3842               }
3843               /* this function has a function call. We cannot
3844                  determine register usage so we will have to pop the
3845                  entire bank */
3846               unsaveRBank (0, ic, FALSE);
3847             }
3848         }
3849         else
3850         {
3851             /* This ISR uses a non-zero bank.
3852              *
3853              * Restore any register banks saved by genFunction
3854              * in reverse order.
3855              */
3856             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3857             int ix;
3858
3859             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3860             {
3861                 if (savedBanks & (1 << ix))
3862                 {
3863                     unsaveRBank(ix, NULL, FALSE);
3864                 }
3865             }
3866
3867             if (options.useXstack)
3868             {
3869                 /* Restore bank AFTER calling unsaveRBank,
3870                  * since it can trash r0.
3871                  */
3872                 emitcode ("pop", "psw");
3873             }
3874         }
3875
3876       if (!inExcludeList ("dph"))
3877         emitcode ("pop", "dph");
3878       if (!inExcludeList ("dpl"))
3879         emitcode ("pop", "dpl");
3880       if (!inExcludeList ("b"))
3881         emitcode ("pop", "b");
3882       if (!inExcludeList ("acc"))
3883         emitcode ("pop", "acc");
3884
3885       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3886       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3887         emitcode ("pop", "bits");
3888       freeBitVect (rsavebits);
3889
3890       /* if debug then send end of function */
3891       if (options.debug && currFunc)
3892         {
3893           debugFile->writeEndFunction (currFunc, ic, 1);
3894         }
3895
3896       emitcode ("reti", "");
3897     }
3898   else
3899     {
3900       if (IFFUNC_CALLEESAVES(sym->type))
3901         {
3902           int i;
3903
3904           /* if any registers used */
3905           if (sym->regsUsed)
3906             {
3907               /* save the registers used */
3908               for (i = sym->regsUsed->size; i >= 0; i--)
3909                 {
3910                   if (bitVectBitValue (sym->regsUsed, i) ||
3911                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3912                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3913                 }
3914             }
3915           else if (mcs51_ptrRegReq)
3916             {
3917               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3918               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3919             }
3920
3921         }
3922
3923       /* if debug then send end of function */
3924       if (options.debug && currFunc)
3925         {
3926           debugFile->writeEndFunction (currFunc, ic, 1);
3927         }
3928
3929       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3930         {
3931           emitcode ("ljmp", "__sdcc_banked_ret");
3932         }
3933       else
3934         {
3935           emitcode ("ret", "");
3936         }
3937     }
3938
3939   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3940     return;
3941
3942   /* If this was an interrupt handler using bank 0 that called another */
3943   /* function, then all registers must be saved; nothing to optimized. */
3944   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3945       && !FUNC_REGBANK(sym->type))
3946     return;
3947
3948   /* There are no push/pops to optimize if not callee-saves or ISR */
3949   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3950     return;
3951
3952   /* If there were stack parameters, we cannot optimize without also    */
3953   /* fixing all of the stack offsets; this is too dificult to consider. */
3954   if (FUNC_HASSTACKPARM(sym->type))
3955     return;
3956
3957   /* Compute the registers actually used */
3958   regsUsed = newBitVect (mcs51_nRegs);
3959   regsUsedPrologue = newBitVect (mcs51_nRegs);
3960   while (lnp)
3961     {
3962       if (lnp->ic && lnp->ic->op == FUNCTION)
3963         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3964       else
3965         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3966
3967       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3968           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3969         break;
3970       if (!lnp->prev)
3971         break;
3972       lnp = lnp->prev;
3973     }
3974
3975   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3976       && !bitVectBitValue (regsUsed, CND_IDX))
3977     {
3978       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3979       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3980           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3981         bitVectUnSetBit (regsUsed, CND_IDX);
3982     }
3983   else
3984     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3985
3986   /* If this was an interrupt handler that called another function */
3987   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3988   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3989     {
3990       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3991       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3992       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3993       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3995     }
3996
3997   /* Remove the unneeded push/pops */
3998   regsUnneeded = newBitVect (mcs51_nRegs);
3999   while (lnp)
4000     {
4001       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4002         {
4003           if (!strncmp(lnp->line, "push", 4))
4004             {
4005               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4006               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4007                 {
4008                   connectLine (lnp->prev, lnp->next);
4009                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4010                 }
4011             }
4012           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4013             {
4014               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4015               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4016                 {
4017                   connectLine (lnp->prev, lnp->next);
4018                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4019                 }
4020             }
4021         }
4022       lnp = lnp->next;
4023     }
4024
4025   for (idx = 0; idx < regsUnneeded->size; idx++)
4026     if (bitVectBitValue (regsUnneeded, idx))
4027       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4028
4029   freeBitVect (regsUnneeded);
4030   freeBitVect (regsUsed);
4031   freeBitVect (regsUsedPrologue);
4032 }
4033
4034 /*-----------------------------------------------------------------*/
4035 /* genRet - generate code for return statement                     */
4036 /*-----------------------------------------------------------------*/
4037 static void
4038 genRet (iCode * ic)
4039 {
4040   int size, offset = 0, pushed = 0;
4041
4042   D (emitcode (";", "genRet"));
4043
4044   /* if we have no return value then
4045      just generate the "ret" */
4046   if (!IC_LEFT (ic))
4047     goto jumpret;
4048
4049   /* we have something to return then
4050      move the return value into place */
4051   aopOp (IC_LEFT (ic), ic, FALSE);
4052   size = AOP_SIZE (IC_LEFT (ic));
4053
4054   if (IS_BIT(_G.currentFunc->etype))
4055     {
4056       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4057         toCarry (IC_LEFT (ic));
4058     }
4059   else
4060     {
4061       while (size--)
4062         {
4063           char *l;
4064           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4065             {
4066               /* #NOCHANGE */
4067               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4068               emitcode ("push", "%s", l);
4069               pushed++;
4070             }
4071           else
4072             {
4073               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4074               if (strcmp (fReturn[offset], l))
4075                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4076             }
4077         }
4078
4079       while (pushed)
4080         {
4081           pushed--;
4082           if (strcmp (fReturn[pushed], "a"))
4083             emitcode ("pop", fReturn[pushed]);
4084           else
4085             emitcode ("pop", "acc");
4086         }
4087     }
4088   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4089
4090 jumpret:
4091   /* generate a jump to the return label
4092      if the next is not the return statement */
4093   if (!(ic->next && ic->next->op == LABEL &&
4094         IC_LABEL (ic->next) == returnLabel))
4095
4096     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4097
4098 }
4099
4100 /*-----------------------------------------------------------------*/
4101 /* genLabel - generates a label                                    */
4102 /*-----------------------------------------------------------------*/
4103 static void
4104 genLabel (iCode * ic)
4105 {
4106   /* special case never generate */
4107   if (IC_LABEL (ic) == entryLabel)
4108     return;
4109
4110   emitLabel (IC_LABEL (ic));
4111 }
4112
4113 /*-----------------------------------------------------------------*/
4114 /* genGoto - generates a ljmp                                      */
4115 /*-----------------------------------------------------------------*/
4116 static void
4117 genGoto (iCode * ic)
4118 {
4119   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4120 }
4121
4122 /*-----------------------------------------------------------------*/
4123 /* findLabelBackwards: walks back through the iCode chain looking  */
4124 /* for the given label. Returns number of iCode instructions     */
4125 /* between that label and given ic.          */
4126 /* Returns zero if label not found.          */
4127 /*-----------------------------------------------------------------*/
4128 static int
4129 findLabelBackwards (iCode * ic, int key)
4130 {
4131   int count = 0;
4132
4133   while (ic->prev)
4134     {
4135       ic = ic->prev;
4136       count++;
4137
4138       /* If we have any pushes or pops, we cannot predict the distance.
4139          I don't like this at all, this should be dealt with in the
4140          back-end */
4141       if (ic->op == IPUSH || ic->op == IPOP) {
4142         return 0;
4143       }
4144
4145       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4146         {
4147           return count;
4148         }
4149     }
4150
4151   return 0;
4152 }
4153
4154 /*-----------------------------------------------------------------*/
4155 /* genPlusIncr :- does addition with increment if possible         */
4156 /*-----------------------------------------------------------------*/
4157 static bool
4158 genPlusIncr (iCode * ic)
4159 {
4160   unsigned int icount;
4161   unsigned int size = getDataSize (IC_RESULT (ic));
4162
4163   /* will try to generate an increment */
4164   /* if the right side is not a literal
4165      we cannot */
4166   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4167     return FALSE;
4168
4169   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4170
4171   D(emitcode (";","genPlusIncr"));
4172
4173   /* if increment >=16 bits in register or direct space */
4174   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4175         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4176         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4177       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4178       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4179       (size > 1) &&
4180       (icount == 1))
4181     {
4182       symbol *tlbl;
4183       int emitTlbl;
4184       int labelRange;
4185
4186       /* If the next instruction is a goto and the goto target
4187        * is < 10 instructions previous to this, we can generate
4188        * jumps straight to that target.
4189        */
4190       if (ic->next && ic->next->op == GOTO
4191           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4192           && labelRange <= 10)
4193         {
4194           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4195           tlbl = IC_LABEL (ic->next);
4196           emitTlbl = 0;
4197         }
4198       else
4199         {
4200           tlbl = newiTempLabel (NULL);
4201           emitTlbl = 1;
4202         }
4203       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4204       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4205           IS_AOP_PREG (IC_RESULT (ic)))
4206         emitcode ("cjne", "%s,#0x00,%05d$",
4207                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4208                   tlbl->key + 100);
4209       else
4210         {
4211           emitcode ("clr", "a");
4212           emitcode ("cjne", "a,%s,%05d$",
4213                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4214                     tlbl->key + 100);
4215         }
4216
4217       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4218       if (size > 2)
4219         {
4220           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4221               IS_AOP_PREG (IC_RESULT (ic)))
4222             emitcode ("cjne", "%s,#0x00,%05d$",
4223                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4224                       tlbl->key + 100);
4225           else
4226             emitcode ("cjne", "a,%s,%05d$",
4227                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4228                       tlbl->key + 100);
4229
4230           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4231         }
4232       if (size > 3)
4233         {
4234           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4235               IS_AOP_PREG (IC_RESULT (ic)))
4236             emitcode ("cjne", "%s,#0x00,%05d$",
4237                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4238                       tlbl->key + 100);
4239           else
4240             {
4241               emitcode ("cjne", "a,%s,%05d$",
4242                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4243                         tlbl->key + 100);
4244             }
4245           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4246         }
4247
4248       if (emitTlbl)
4249         {
4250           emitLabel (tlbl);
4251         }
4252       return TRUE;
4253     }
4254
4255   /* if result is dptr */
4256   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4257       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4258       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4259       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4260     {
4261       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4262         return FALSE;
4263
4264       if (icount > 9)
4265         return FALSE;
4266
4267       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4268         return FALSE;
4269
4270       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4271       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4272       while (icount--)
4273         emitcode ("inc", "dptr");
4274
4275       return TRUE;
4276     }
4277
4278   /* if the literal value of the right hand side
4279      is greater than 4 then it is not worth it */
4280   if (icount > 4)
4281     return FALSE;
4282
4283   /* if the sizes are greater than 1 then we cannot */
4284   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4285       AOP_SIZE (IC_LEFT (ic)) > 1)
4286     return FALSE;
4287
4288   /* we can if the aops of the left & result match or
4289      if they are in registers and the registers are the
4290      same */
4291   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4292     {
4293       if (icount > 3)
4294         {
4295           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4296           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4297           aopPut (IC_RESULT (ic), "a", 0);
4298         }
4299       else
4300         {
4301           while (icount--)
4302             {
4303               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4304             }
4305         }
4306
4307       return TRUE;
4308     }
4309
4310   if (icount == 1)
4311     {
4312       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4313       emitcode ("inc", "a");
4314       aopPut (IC_RESULT (ic), "a", 0);
4315       return TRUE;
4316     }
4317
4318   return FALSE;
4319 }
4320
4321 /*-----------------------------------------------------------------*/
4322 /* outBitAcc - output a bit in acc                                 */
4323 /*-----------------------------------------------------------------*/
4324 static void
4325 outBitAcc (operand * result)
4326 {
4327   symbol *tlbl = newiTempLabel (NULL);
4328   /* if the result is a bit */
4329   if (AOP_TYPE (result) == AOP_CRY)
4330     {
4331       aopPut (result, "a", 0);
4332     }
4333   else
4334     {
4335       emitcode ("jz", "%05d$", tlbl->key + 100);
4336       emitcode ("mov", "a,%s", one);
4337       emitLabel (tlbl);
4338       outAcc (result);
4339     }
4340 }
4341
4342 /*-----------------------------------------------------------------*/
4343 /* genPlusBits - generates code for addition of two bits           */
4344 /*-----------------------------------------------------------------*/
4345 static void
4346 genPlusBits (iCode * ic)
4347 {
4348   D (emitcode (";", "genPlusBits"));
4349
4350   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4351   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4352     {
4353       symbol *lbl = newiTempLabel (NULL);
4354       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4355       emitcode ("cpl", "c");
4356       emitLabel (lbl);
4357       outBitC (IC_RESULT (ic));
4358     }
4359   else
4360     {
4361       emitcode ("clr", "a");
4362       emitcode ("rlc", "a");
4363       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4364       emitcode ("addc", "a,%s", zero);
4365       outAcc (IC_RESULT (ic));
4366     }
4367 }
4368
4369 #if 0
4370 /* This is the original version of this code.
4371
4372  * This is being kept around for reference,
4373  * because I am not entirely sure I got it right...
4374  */
4375 static void
4376 adjustArithmeticResult (iCode * ic)
4377 {
4378   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4379       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4380       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4381     aopPut (IC_RESULT (ic),
4382             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4383             2);
4384
4385   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4386       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4387       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4388     aopPut (IC_RESULT (ic),
4389             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4390             2);
4391
4392   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4393       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4394       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4395       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4396       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4397     {
4398       char buffer[5];
4399       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4400       aopPut (IC_RESULT (ic), buffer, 2);
4401     }
4402 }
4403 #else
4404 /* This is the pure and virtuous version of this code.
4405  * I'm pretty certain it's right, but not enough to toss the old
4406  * code just yet...
4407  */
4408 static void
4409 adjustArithmeticResult (iCode * ic)
4410 {
4411   if (opIsGptr (IC_RESULT (ic)) &&
4412       opIsGptr (IC_LEFT (ic)) &&
4413       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4414     {
4415       aopPut (IC_RESULT (ic),
4416               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4417               GPTRSIZE - 1);
4418     }
4419
4420   if (opIsGptr (IC_RESULT (ic)) &&
4421       opIsGptr (IC_RIGHT (ic)) &&
4422       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4423     {
4424       aopPut (IC_RESULT (ic),
4425               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4426               GPTRSIZE - 1);
4427     }
4428
4429   if (opIsGptr (IC_RESULT (ic)) &&
4430       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4431       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4432       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4433       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4434     {
4435       char buffer[5];
4436       SNPRINTF (buffer, sizeof(buffer),
4437                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4438       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4439     }
4440 }
4441 #endif
4442
4443 /*-----------------------------------------------------------------*/
4444 /* genPlus - generates code for addition                           */
4445 /*-----------------------------------------------------------------*/
4446 static void
4447 genPlus (iCode * ic)
4448 {
4449   int size, offset = 0;
4450   int skip_bytes = 0;
4451   char *add = "add";
4452   bool swappedLR = FALSE;
4453   operand *leftOp, *rightOp;
4454   operand * op;
4455
4456   D (emitcode (";", "genPlus"));
4457
4458   /* special cases :- */
4459
4460   aopOp (IC_LEFT (ic), ic, FALSE);
4461   aopOp (IC_RIGHT (ic), ic, FALSE);
4462   aopOp (IC_RESULT (ic), ic, TRUE);
4463
4464   /* if literal, literal on the right or
4465      if left requires ACC or right is already
4466      in ACC */
4467   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4468       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4469       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4470     {
4471       operand *t = IC_RIGHT (ic);
4472       IC_RIGHT (ic) = IC_LEFT (ic);
4473       IC_LEFT (ic) = t;
4474       swappedLR = TRUE;
4475     }
4476
4477   /* if both left & right are in bit
4478      space */
4479   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4480       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4481     {
4482       genPlusBits (ic);
4483       goto release;
4484     }
4485
4486   /* if left in bit space & right literal */
4487   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4488       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4489     {
4490       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4491       /* if result in bit space */
4492       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4493         {
4494           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4495             emitcode ("cpl", "c");
4496           outBitC (IC_RESULT (ic));
4497         }
4498       else
4499         {
4500           size = getDataSize (IC_RESULT (ic));
4501           while (size--)
4502             {
4503               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4504               emitcode ("addc", "a,%s", zero);
4505               aopPut (IC_RESULT (ic), "a", offset++);
4506             }
4507         }
4508       goto release;
4509     }
4510
4511   /* if I can do an increment instead
4512      of add then GOOD for ME */
4513   if (genPlusIncr (ic) == TRUE)
4514     goto release;
4515
4516   size = getDataSize (IC_RESULT (ic));
4517   leftOp = IC_LEFT(ic);
4518   rightOp = IC_RIGHT(ic);
4519   op = IC_LEFT(ic);
4520
4521   /* if this is an add for an array access
4522      at a 256 byte boundary */
4523   if ( 2 == size
4524        && AOP_TYPE (op) == AOP_IMMD
4525        && IS_SYMOP (op)
4526        && IS_SPEC (OP_SYM_ETYPE (op))
4527        && SPEC_ABSA (OP_SYM_ETYPE (op))
4528        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4529      )
4530     {
4531       D(emitcode (";", "genPlus aligned array"));
4532       aopPut (IC_RESULT (ic),
4533               aopGet (rightOp, 0, FALSE, FALSE),
4534               0);
4535
4536       if( 1 == getDataSize (IC_RIGHT (ic)) )
4537         {
4538           aopPut (IC_RESULT (ic),
4539                   aopGet (leftOp, 1, FALSE, FALSE),
4540                   1);
4541         }
4542       else
4543         {
4544           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4545           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4546           aopPut (IC_RESULT (ic), "a", 1);
4547         }
4548       goto release;
4549     }
4550
4551   /* if the lower bytes of a literal are zero skip the addition */
4552   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4553     {
4554        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4555               (skip_bytes+1 < size))
4556          {
4557            skip_bytes++;
4558          }
4559        if (skip_bytes)
4560          D(emitcode (";", "genPlus shortcut"));
4561     }
4562
4563   while (size--)
4564     {
4565       if( offset >= skip_bytes )
4566         {
4567           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4568             {
4569               bool pushedB;
4570               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4571               pushedB = pushB ();
4572               emitcode("xch", "a,b");
4573               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4574               emitcode (add, "a,b");
4575               popB (pushedB);
4576             }
4577           else if (aopGetUsesAcc (leftOp, offset))
4578             {
4579               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4580               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4581             }
4582           else
4583             {
4584               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4585               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4586             }
4587           aopPut (IC_RESULT (ic), "a", offset);
4588           add = "addc";  /* further adds must propagate carry */
4589         }
4590       else
4591         {
4592           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4593               isOperandVolatile (IC_RESULT (ic), FALSE))
4594             {
4595               /* just move */
4596               aopPut (IC_RESULT (ic),
4597                       aopGet (leftOp, offset, FALSE, FALSE),
4598                       offset);
4599             }
4600         }
4601       offset++;
4602     }
4603
4604   adjustArithmeticResult (ic);
4605
4606 release:
4607   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4608   if (!swappedLR)
4609     {
4610       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4611       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4612     }
4613   else
4614     {
4615       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4616       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4617     }
4618 }
4619
4620 /*-----------------------------------------------------------------*/
4621 /* genMinusDec :- does subtraction with decrement if possible      */
4622 /*-----------------------------------------------------------------*/
4623 static bool
4624 genMinusDec (iCode * ic)
4625 {
4626   unsigned int icount;
4627   unsigned int size = getDataSize (IC_RESULT (ic));
4628
4629   /* will try to generate an increment */
4630   /* if the right side is not a literal
4631      we cannot */
4632   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4633     return FALSE;
4634
4635   /* if the literal value of the right hand side
4636      is greater than 4 then it is not worth it */
4637   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4638     return FALSE;
4639
4640   D (emitcode (";", "genMinusDec"));
4641
4642   /* if decrement >=16 bits in register or direct space */
4643   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4644         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4645         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4646       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4647       (size > 1) &&
4648       (icount == 1))
4649     {
4650       symbol *tlbl;
4651       int emitTlbl;
4652       int labelRange;
4653
4654       /* If the next instruction is a goto and the goto target
4655        * is <= 10 instructions previous to this, we can generate
4656        * jumps straight to that target.
4657        */
4658       if (ic->next && ic->next->op == GOTO
4659           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4660           && labelRange <= 10)
4661         {
4662           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4663           tlbl = IC_LABEL (ic->next);
4664           emitTlbl = 0;
4665         }
4666       else
4667         {
4668           tlbl = newiTempLabel (NULL);
4669           emitTlbl = 1;
4670         }
4671
4672       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4673       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4674           IS_AOP_PREG (IC_RESULT (ic)))
4675         emitcode ("cjne", "%s,#0xff,%05d$"
4676                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4677                   ,tlbl->key + 100);
4678       else
4679         {
4680           emitcode ("mov", "a,#0xff");
4681           emitcode ("cjne", "a,%s,%05d$"
4682                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4683                     ,tlbl->key + 100);
4684         }
4685       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4686       if (size > 2)
4687         {
4688           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4689               IS_AOP_PREG (IC_RESULT (ic)))
4690             emitcode ("cjne", "%s,#0xff,%05d$"
4691                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4692                       ,tlbl->key + 100);
4693           else
4694             {
4695               emitcode ("cjne", "a,%s,%05d$"
4696                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4697                         ,tlbl->key + 100);
4698             }
4699           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4700         }
4701       if (size > 3)
4702         {
4703           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4704               IS_AOP_PREG (IC_RESULT (ic)))
4705             emitcode ("cjne", "%s,#0xff,%05d$"
4706                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4707                       ,tlbl->key + 100);
4708           else
4709             {
4710               emitcode ("cjne", "a,%s,%05d$"
4711                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4712                         ,tlbl->key + 100);
4713             }
4714           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4715         }
4716       if (emitTlbl)
4717         {
4718           emitLabel (tlbl);
4719         }
4720       return TRUE;
4721     }
4722
4723   /* if the sizes are greater than 1 then we cannot */
4724   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4725       AOP_SIZE (IC_LEFT (ic)) > 1)
4726     return FALSE;
4727
4728   /* we can if the aops of the left & result match or
4729      if they are in registers and the registers are the
4730      same */
4731   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4732     {
4733       char *l;
4734
4735       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4736         {
4737           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4738           l = "a";
4739         }
4740       else
4741         {
4742           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4743         }
4744
4745       while (icount--)
4746         {
4747           emitcode ("dec", "%s", l);
4748         }
4749
4750       if (AOP_NEEDSACC (IC_RESULT (ic)))
4751         aopPut (IC_RESULT (ic), "a", 0);
4752
4753       return TRUE;
4754     }
4755
4756   if (icount == 1)
4757     {
4758       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4759       emitcode ("dec", "a");
4760       aopPut (IC_RESULT (ic), "a", 0);
4761       return TRUE;
4762     }
4763
4764   return FALSE;
4765 }
4766
4767 /*-----------------------------------------------------------------*/
4768 /* addSign - complete with sign                                    */
4769 /*-----------------------------------------------------------------*/
4770 static void
4771 addSign (operand * result, int offset, int sign)
4772 {
4773   int size = (getDataSize (result) - offset);
4774   if (size > 0)
4775     {
4776       if (sign)
4777         {
4778           emitcode ("rlc", "a");
4779           emitcode ("subb", "a,acc");
4780           while (size--)
4781             {
4782               aopPut (result, "a", offset++);
4783             }
4784         }
4785       else
4786         {
4787           while (size--)
4788             {
4789               aopPut (result, zero, offset++);
4790             }
4791         }
4792     }
4793 }
4794
4795 /*-----------------------------------------------------------------*/
4796 /* genMinusBits - generates code for subtraction  of two bits      */
4797 /*-----------------------------------------------------------------*/
4798 static void
4799 genMinusBits (iCode * ic)
4800 {
4801   symbol *lbl = newiTempLabel (NULL);
4802
4803   D (emitcode (";", "genMinusBits"));
4804
4805   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4806     {
4807       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4808       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4809       emitcode ("cpl", "c");
4810       emitLabel (lbl);
4811       outBitC (IC_RESULT (ic));
4812     }
4813   else
4814     {
4815       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4816       emitcode ("subb", "a,acc");
4817       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4818       emitcode ("inc", "a");
4819       emitLabel (lbl);
4820       aopPut (IC_RESULT (ic), "a", 0);
4821       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4822     }
4823 }
4824
4825 /*-----------------------------------------------------------------*/
4826 /* genMinus - generates code for subtraction                       */
4827 /*-----------------------------------------------------------------*/
4828 static void
4829 genMinus (iCode * ic)
4830 {
4831   int size, offset = 0;
4832
4833   D (emitcode (";", "genMinus"));
4834
4835   aopOp (IC_LEFT (ic), ic, FALSE);
4836   aopOp (IC_RIGHT (ic), ic, FALSE);
4837   aopOp (IC_RESULT (ic), ic, TRUE);
4838
4839   /* special cases :- */
4840   /* if both left & right are in bit space */
4841   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4842       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4843     {
4844       genMinusBits (ic);
4845       goto release;
4846     }
4847
4848   /* if I can do an decrement instead
4849      of subtract then GOOD for ME */
4850   if (genMinusDec (ic) == TRUE)
4851     goto release;
4852
4853   size = getDataSize (IC_RESULT (ic));
4854
4855   /* if literal, add a,#-lit, else normal subb */
4856   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4857     {
4858       unsigned long lit = 0L;
4859       bool useCarry = FALSE;
4860
4861       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4862       lit = -(long) lit;
4863
4864       while (size--)
4865         {
4866           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4867             {
4868               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4869               if (!offset && !size && lit== (unsigned long) -1)
4870                 {
4871                   emitcode ("dec", "a");
4872                 }
4873               else if (!useCarry)
4874                 {
4875                   /* first add without previous c */
4876                   emitcode ("add", "a,#0x%02x",
4877                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4878                   useCarry = TRUE;
4879                 }
4880               else
4881                 {
4882                   emitcode ("addc", "a,#0x%02x",
4883                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4884                 }
4885               aopPut (IC_RESULT (ic), "a", offset++);
4886             }
4887           else
4888             {
4889               /* no need to add zeroes */
4890               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4891                 {
4892                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4893                           offset);
4894                 }
4895               offset++;
4896             }
4897         }
4898     }
4899   else
4900     {
4901       operand *leftOp, *rightOp;
4902
4903       leftOp = IC_LEFT(ic);
4904       rightOp = IC_RIGHT(ic);
4905
4906       while (size--)
4907         {
4908           if (aopGetUsesAcc(rightOp, offset)) {
4909             if (aopGetUsesAcc(leftOp, offset)) {
4910               bool pushedB;
4911
4912               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4913               pushedB = pushB ();
4914               emitcode ("mov", "b,a");
4915               if (offset == 0)
4916                 CLRC;
4917               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4918               emitcode ("subb", "a,b");
4919               popB (pushedB);
4920             } else {
4921               /* reverse subtraction with 2's complement */
4922               if (offset == 0)
4923                 emitcode( "setb", "c");
4924               else
4925                 emitcode( "cpl", "c");
4926               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4927               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4928               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4929               emitcode("cpl", "a");
4930               if (size) /* skip if last byte */
4931                 emitcode( "cpl", "c");
4932             }
4933           } else {
4934             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4935             if (offset == 0)
4936               CLRC;
4937             emitcode ("subb", "a,%s",
4938                       aopGet(rightOp, offset, FALSE, TRUE));
4939           }
4940
4941           aopPut (IC_RESULT (ic), "a", offset++);
4942         }
4943     }
4944
4945   adjustArithmeticResult (ic);
4946
4947 release:
4948   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4949   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4950   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4951 }
4952
4953
4954 /*-----------------------------------------------------------------*/
4955 /* genMultbits :- multiplication of bits                           */
4956 /*-----------------------------------------------------------------*/
4957 static void
4958 genMultbits (operand * left,
4959              operand * right,
4960              operand * result)
4961 {
4962   D (emitcode (";", "genMultbits"));
4963
4964   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4965   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4966   outBitC (result);
4967 }
4968
4969 /*-----------------------------------------------------------------*/
4970 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4971 /*-----------------------------------------------------------------*/
4972 static void
4973 genMultOneByte (operand * left,
4974                 operand * right,
4975                 operand * result)
4976 {
4977   symbol *lbl;
4978   int size = AOP_SIZE (result);
4979   bool runtimeSign, compiletimeSign;
4980   bool lUnsigned, rUnsigned, pushedB;
4981
4982   D (emitcode (";", "genMultOneByte"));
4983
4984   if (size < 1 || size > 2)
4985     {
4986       /* this should never happen */
4987       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4988                AOP_SIZE(result), __FILE__, lineno);
4989       exit (1);
4990     }
4991
4992   /* (if two literals: the value is computed before) */
4993   /* if one literal, literal on the right */
4994   if (AOP_TYPE (left) == AOP_LIT)
4995     {
4996       operand *t = right;
4997       right = left;
4998       left = t;
4999       /* emitcode (";", "swapped left and right"); */
5000     }
5001   /* if no literal, unsigned on the right: shorter code */
5002   if (   AOP_TYPE (right) != AOP_LIT
5003       && SPEC_USIGN (getSpec (operandType (left))))
5004     {
5005       operand *t = right;
5006       right = left;
5007       left = t;
5008     }
5009
5010   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5011   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5012
5013   pushedB = pushB ();
5014
5015   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5016                    no need to take care about the signedness! */
5017       || (lUnsigned && rUnsigned))
5018     {
5019       /* just an unsigned 8 * 8 = 8 multiply
5020          or 8u * 8u = 16u */
5021       /* emitcode (";","unsigned"); */
5022       /* TODO: check for accumulator clash between left & right aops? */
5023
5024       if (AOP_TYPE (right) == AOP_LIT)
5025         {
5026           /* moving to accumulator first helps peepholes */
5027           MOVA (aopGet (left, 0, FALSE, FALSE));
5028           MOVB (aopGet (right, 0, FALSE, FALSE));
5029         }
5030       else
5031         {
5032           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5033           MOVA (aopGet (left, 0, FALSE, FALSE));
5034         }
5035
5036       emitcode ("mul", "ab");
5037       aopPut (result, "a", 0);
5038       if (size == 2)
5039         aopPut (result, "b", 1);
5040
5041       popB (pushedB);
5042       return;
5043     }
5044
5045   /* we have to do a signed multiply */
5046   /* emitcode (";", "signed"); */
5047
5048   /* now sign adjust for both left & right */
5049
5050   /* let's see what's needed: */
5051   /* apply negative sign during runtime */
5052   runtimeSign = FALSE;
5053   /* negative sign from literals */
5054   compiletimeSign = FALSE;
5055
5056   if (!lUnsigned)
5057     {
5058       if (AOP_TYPE(left) == AOP_LIT)
5059         {
5060           /* signed literal */
5061           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5062           if (val < 0)
5063             compiletimeSign = TRUE;
5064         }
5065       else
5066         /* signed but not literal */
5067         runtimeSign = TRUE;
5068     }
5069
5070   if (!rUnsigned)
5071     {
5072       if (AOP_TYPE(right) == AOP_LIT)
5073         {
5074           /* signed literal */
5075           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5076           if (val < 0)
5077             compiletimeSign ^= TRUE;
5078         }
5079       else
5080         /* signed but not literal */
5081         runtimeSign = TRUE;
5082     }
5083
5084   /* initialize F0, which stores the runtime sign */
5085   if (runtimeSign)
5086     {
5087       if (compiletimeSign)
5088         emitcode ("setb", "F0"); /* set sign flag */
5089       else
5090         emitcode ("clr", "F0"); /* reset sign flag */
5091     }
5092
5093   /* save the signs of the operands */
5094   if (AOP_TYPE(right) == AOP_LIT)
5095     {
5096       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5097
5098       if (!rUnsigned && val < 0)
5099         emitcode ("mov", "b,#0x%02x", -val);
5100       else
5101         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5102     }
5103   else /* ! literal */
5104     {
5105       if (rUnsigned)  /* emitcode (";", "signed"); */
5106         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5107       else
5108         {
5109           MOVA (aopGet (right, 0, FALSE, FALSE));
5110           lbl = newiTempLabel (NULL);
5111           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5112           emitcode ("cpl", "F0"); /* complement sign flag */
5113           emitcode ("cpl", "a");  /* 2's complement */
5114           emitcode ("inc", "a");
5115           emitLabel (lbl);
5116           emitcode ("mov", "b,a");
5117         }
5118     }
5119
5120   if (AOP_TYPE(left) == AOP_LIT)
5121     {
5122       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5123
5124       if (!lUnsigned && val < 0)
5125         emitcode ("mov", "a,#0x%02x", -val);
5126       else
5127         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5128     }
5129   else /* ! literal */
5130     {
5131       MOVA (aopGet (left, 0, FALSE, FALSE));
5132
5133       if (!lUnsigned)
5134         {
5135           lbl = newiTempLabel (NULL);
5136           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5137           emitcode ("cpl", "F0"); /* complement sign flag */
5138           emitcode ("cpl", "a"); /* 2's complement */
5139           emitcode ("inc", "a");
5140           emitLabel (lbl);
5141         }
5142     }
5143
5144   /* now the multiplication */
5145   emitcode ("mul", "ab");
5146   if (runtimeSign || compiletimeSign)
5147     {
5148       lbl = newiTempLabel (NULL);
5149       if (runtimeSign)
5150         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5151       emitcode ("cpl", "a"); /* lsb 2's complement */
5152       if (size != 2)
5153         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5154       else
5155         {
5156           emitcode ("add", "a,#1"); /* this sets carry flag */
5157           emitcode ("xch", "a,b");
5158           emitcode ("cpl", "a"); /* msb 2's complement */
5159           emitcode ("addc", "a,#0");
5160           emitcode ("xch", "a,b");
5161         }
5162       emitLabel (lbl);
5163     }
5164   aopPut (result, "a", 0);
5165   if (size == 2)
5166     aopPut (result, "b", 1);
5167
5168   popB (pushedB);
5169 }
5170
5171 /*-----------------------------------------------------------------*/
5172 /* genMult - generates code for multiplication                     */
5173 /*-----------------------------------------------------------------*/
5174 static void
5175 genMult (iCode * ic)
5176 {
5177   operand *left = IC_LEFT (ic);
5178   operand *right = IC_RIGHT (ic);
5179   operand *result = IC_RESULT (ic);
5180
5181   D (emitcode (";", "genMult"));
5182
5183   /* assign the asmops */
5184   aopOp (left, ic, FALSE);
5185   aopOp (right, ic, FALSE);
5186   aopOp (result, ic, TRUE);
5187
5188   /* special cases first */
5189   /* both are bits */
5190   if (AOP_TYPE (left) == AOP_CRY &&
5191       AOP_TYPE (right) == AOP_CRY)
5192     {
5193       genMultbits (left, right, result);
5194       goto release;
5195     }
5196
5197   /* if both are of size == 1 */
5198 #if 0 // one of them can be a sloc shared with the result
5199     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5200 #else
5201   if (getSize(operandType(left)) == 1 &&
5202       getSize(operandType(right)) == 1)
5203 #endif
5204     {
5205       genMultOneByte (left, right, result);
5206       goto release;
5207     }
5208
5209   /* should have been converted to function call */
5210     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5211              getSize(OP_SYMBOL(right)->type));
5212   assert (0);
5213
5214 release:
5215   freeAsmop (result, NULL, ic, TRUE);
5216   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5217   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5218 }
5219
5220 /*-----------------------------------------------------------------*/
5221 /* genDivbits :- division of bits                                  */
5222 /*-----------------------------------------------------------------*/
5223 static void
5224 genDivbits (operand * left,
5225             operand * right,
5226             operand * result)
5227 {
5228   char *l;
5229   bool pushedB;
5230
5231   D(emitcode (";", "genDivbits"));
5232
5233   pushedB = pushB ();
5234
5235   /* the result must be bit */
5236   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5237   l = aopGet (left, 0, FALSE, FALSE);
5238
5239   MOVA (l);
5240
5241   emitcode ("div", "ab");
5242   emitcode ("rrc", "a");
5243
5244   popB (pushedB);
5245
5246   aopPut (result, "c", 0);
5247 }
5248
5249 /*-----------------------------------------------------------------*/
5250 /* genDivOneByte : 8 bit division                                  */
5251 /*-----------------------------------------------------------------*/
5252 static void
5253 genDivOneByte (operand * left,
5254                operand * right,
5255                operand * result)
5256 {
5257   bool lUnsigned, rUnsigned, pushedB;
5258   bool runtimeSign, compiletimeSign;
5259   bool accuse = FALSE;
5260   bool pushedA = FALSE;
5261   symbol *lbl;
5262   int size, offset;
5263
5264   D(emitcode (";", "genDivOneByte"));
5265
5266   /* Why is it necessary that genDivOneByte() can return an int result?
5267      Have a look at:
5268
5269         volatile unsigned char uc;
5270         volatile signed char sc1, sc2;
5271         volatile int i;
5272
5273         uc  = 255;
5274         sc1 = -1;
5275         i = uc / sc1;
5276
5277      Or:
5278
5279         sc1 = -128;
5280         sc2 = -1;
5281         i = sc1 / sc2;
5282
5283      In all cases a one byte result would overflow, the following cast to int
5284      would return the wrong result.
5285
5286      Two possible solution:
5287         a) cast operands to int, if ((unsigned) / (signed)) or
5288            ((signed) / (signed))
5289         b) return an 16 bit signed int; this is what we're doing here!
5290   */
5291
5292   size = AOP_SIZE (result) - 1;
5293   offset = 1;
5294   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5295   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5296
5297   pushedB = pushB ();
5298
5299   /* signed or unsigned */
5300   if (lUnsigned && rUnsigned)
5301     {
5302       /* unsigned is easy */
5303       MOVB (aopGet (right, 0, FALSE, FALSE));
5304       MOVA (aopGet (left, 0, FALSE, FALSE));
5305       emitcode ("div", "ab");
5306       aopPut (result, "a", 0);
5307       while (size--)
5308         aopPut (result, zero, offset++);
5309
5310       popB (pushedB);
5311       return;
5312     }
5313
5314   /* signed is a little bit more difficult */
5315
5316   /* now sign adjust for both left & right */
5317
5318   /* let's see what's needed: */
5319   /* apply negative sign during runtime */
5320   runtimeSign = FALSE;
5321   /* negative sign from literals */
5322   compiletimeSign = FALSE;
5323
5324   if (!lUnsigned)
5325     {
5326       if (AOP_TYPE(left) == AOP_LIT)
5327         {
5328           /* signed literal */
5329           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5330           if (val < 0)
5331             compiletimeSign = TRUE;
5332         }
5333       else
5334         /* signed but not literal */
5335         runtimeSign = TRUE;
5336     }
5337
5338   if (!rUnsigned)
5339     {
5340       if (AOP_TYPE(right) == AOP_LIT)
5341         {
5342           /* signed literal */
5343           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5344           if (val < 0)
5345             compiletimeSign ^= TRUE;
5346         }
5347       else
5348         /* signed but not literal */
5349         runtimeSign = TRUE;
5350     }
5351
5352   /* initialize F0, which stores the runtime sign */
5353   if (runtimeSign)
5354     {
5355       if (compiletimeSign)
5356         emitcode ("setb", "F0"); /* set sign flag */
5357       else
5358         emitcode ("clr", "F0"); /* reset sign flag */
5359     }
5360
5361   /* save the signs of the operands */
5362   if (AOP_TYPE(right) == AOP_LIT)
5363     {
5364       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5365
5366       if (!rUnsigned && val < 0)
5367         emitcode ("mov", "b,#0x%02x", -val);
5368       else
5369         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5370     }
5371   else /* ! literal */
5372     {
5373       if (rUnsigned)
5374         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5375       else
5376         {
5377           MOVA (aopGet (right, 0, FALSE, FALSE));
5378           lbl = newiTempLabel (NULL);
5379           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5380           emitcode ("cpl", "F0"); /* complement sign flag */
5381           emitcode ("cpl", "a");  /* 2's complement */
5382           emitcode ("inc", "a");
5383           emitLabel (lbl);
5384           emitcode ("mov", "b,a");
5385         }
5386     }
5387
5388   if (AOP_TYPE(left) == AOP_LIT)
5389     {
5390       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5391
5392       if (!lUnsigned && val < 0)
5393         emitcode ("mov", "a,#0x%02x", -val);
5394       else
5395         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5396     }
5397   else /* ! literal */
5398     {
5399       MOVA (aopGet (left, 0, FALSE, FALSE));
5400
5401       if (!lUnsigned)
5402         {
5403           lbl = newiTempLabel (NULL);
5404           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5405           emitcode ("cpl", "F0"); /* complement sign flag */
5406           emitcode ("cpl", "a");  /* 2's complement */
5407           emitcode ("inc", "a");
5408           emitLabel (lbl);
5409         }
5410     }
5411
5412   /* now the division */
5413   emitcode ("div", "ab");
5414
5415   if (runtimeSign || compiletimeSign)
5416     {
5417       lbl = newiTempLabel (NULL);
5418       if (runtimeSign)
5419         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5420       emitcode ("cpl", "a"); /* lsb 2's complement */
5421       emitcode ("inc", "a");
5422       emitLabel (lbl);
5423
5424       accuse = aopPut (result, "a", 0);
5425       if (size > 0)
5426         {
5427           /* msb is 0x00 or 0xff depending on the sign */
5428           if (runtimeSign)
5429             {
5430               if (accuse)
5431                 {
5432                   emitcode ("push", "acc");
5433                   pushedA = TRUE;
5434                 }
5435               emitcode ("mov", "c,F0");
5436               emitcode ("subb", "a,acc");
5437               while (size--)
5438                 aopPut (result, "a", offset++);
5439             }
5440           else /* compiletimeSign */
5441             {
5442               if (aopPutUsesAcc (result, "#0xFF", offset))
5443                 {
5444                   emitcode ("push", "acc");
5445                   pushedA = TRUE;
5446                 }
5447               while (size--)
5448                 aopPut (result, "#0xff", offset++);
5449             }
5450         }
5451     }
5452   else
5453     {
5454       aopPut (result, "a", 0);
5455       while (size--)
5456         aopPut (result, zero, offset++);
5457     }
5458
5459   if (pushedA)
5460     emitcode ("pop", "acc");
5461   popB (pushedB);
5462 }
5463
5464 /*-----------------------------------------------------------------*/
5465 /* genDiv - generates code for division                            */
5466 /*-----------------------------------------------------------------*/
5467 static void
5468 genDiv (iCode * ic)
5469 {
5470   operand *left = IC_LEFT (ic);
5471   operand *right = IC_RIGHT (ic);
5472   operand *result = IC_RESULT (ic);
5473
5474   D (emitcode (";", "genDiv"));
5475
5476   /* assign the asmops */
5477   aopOp (left, ic, FALSE);
5478   aopOp (right, ic, FALSE);
5479   aopOp (result, ic, TRUE);
5480
5481   /* special cases first */
5482   /* both are bits */
5483   if (AOP_TYPE (left) == AOP_CRY &&
5484       AOP_TYPE (right) == AOP_CRY)
5485     {
5486       genDivbits (left, right, result);
5487       goto release;
5488     }
5489
5490   /* if both are of size == 1 */
5491   if (AOP_SIZE (left) == 1 &&
5492       AOP_SIZE (right) == 1)
5493     {
5494       genDivOneByte (left, right, result);
5495       goto release;
5496     }
5497
5498   /* should have been converted to function call */
5499   assert (0);
5500 release:
5501   freeAsmop (result, NULL, ic, TRUE);
5502   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5503   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5504 }
5505
5506 /*-----------------------------------------------------------------*/
5507 /* genModbits :- modulus of bits                                   */
5508 /*-----------------------------------------------------------------*/
5509 static void
5510 genModbits (operand * left,
5511             operand * right,
5512             operand * result)
5513 {
5514   char *l;
5515   bool pushedB;
5516
5517   D (emitcode (";", "genModbits"));
5518
5519   pushedB = pushB ();
5520
5521   /* the result must be bit */
5522   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5523   l = aopGet (left, 0, FALSE, FALSE);
5524
5525   MOVA (l);
5526
5527   emitcode ("div", "ab");
5528   emitcode ("mov", "a,b");
5529   emitcode ("rrc", "a");
5530
5531   popB (pushedB);
5532
5533   aopPut (result, "c", 0);
5534 }
5535
5536 /*-----------------------------------------------------------------*/
5537 /* genModOneByte : 8 bit modulus                                   */
5538 /*-----------------------------------------------------------------*/
5539 static void
5540 genModOneByte (operand * left,
5541                operand * right,
5542                operand * result)
5543 {
5544   bool lUnsigned, rUnsigned, pushedB;
5545   bool runtimeSign, compiletimeSign;
5546   symbol *lbl;
5547   int size, offset;
5548
5549   D (emitcode (";", "genModOneByte"));
5550
5551   size = AOP_SIZE (result) - 1;
5552   offset = 1;
5553   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5554   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5555
5556   /* if right is a literal, check it for 2^n */
5557   if (AOP_TYPE(right) == AOP_LIT)
5558     {
5559       unsigned char val = abs((int) operandLitValue(right));
5560       symbol *lbl2 = NULL;
5561
5562       switch (val)
5563         {
5564           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5565           case 2:
5566           case 4:
5567           case 8:
5568           case 16:
5569           case 32:
5570           case 64:
5571           case 128:
5572             if (lUnsigned)
5573               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5574                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5575               /* because iCode should have been changed to genAnd  */
5576               /* see file "SDCCopt.c", function "convertToFcall()" */
5577
5578             MOVA (aopGet (left, 0, FALSE, FALSE));
5579             emitcode ("mov", "c,acc.7");
5580             emitcode ("anl", "a,#0x%02x", val - 1);
5581             lbl = newiTempLabel (NULL);
5582             emitcode ("jz", "%05d$", (lbl->key + 100));
5583             emitcode ("jnc", "%05d$", (lbl->key + 100));
5584             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5585             if (size)
5586               {
5587                 int size2 = size;
5588                 int offs2 = offset;
5589
5590                 aopPut (result, "a", 0);
5591                 while (size2--)
5592                   aopPut (result, "#0xff", offs2++);
5593                 lbl2 = newiTempLabel (NULL);
5594                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5595               }
5596             emitLabel (lbl);
5597             aopPut (result, "a", 0);
5598             while (size--)
5599               aopPut (result, zero, offset++);
5600             if (lbl2)
5601               {
5602                 emitLabel (lbl2);
5603               }
5604             return;
5605
5606           default:
5607             break;
5608         }
5609     }
5610
5611   pushedB = pushB ();
5612
5613   /* signed or unsigned */
5614   if (lUnsigned && rUnsigned)
5615     {
5616       /* unsigned is easy */
5617       MOVB (aopGet (right, 0, FALSE, FALSE));
5618       MOVA (aopGet (left, 0, FALSE, FALSE));
5619       emitcode ("div", "ab");
5620       aopPut (result, "b", 0);
5621       while (size--)
5622         aopPut (result, zero, offset++);
5623
5624       popB (pushedB);
5625       return;
5626     }
5627
5628   /* signed is a little bit more difficult */
5629
5630   /* now sign adjust for both left & right */
5631
5632   /* modulus: sign of the right operand has no influence on the result! */
5633   if (AOP_TYPE(right) == AOP_LIT)
5634     {
5635       signed char val = (char) operandLitValue(right);
5636
5637       if (!rUnsigned && val < 0)
5638         emitcode ("mov", "b,#0x%02x", -val);
5639       else
5640         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5641     }
5642   else /* not literal */
5643     {
5644       if (rUnsigned)
5645         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5646       else
5647         {
5648           MOVA (aopGet (right, 0, FALSE, FALSE));
5649           lbl = newiTempLabel (NULL);
5650           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5651           emitcode ("cpl", "a"); /* 2's complement */
5652           emitcode ("inc", "a");
5653           emitLabel (lbl);
5654           emitcode ("mov", "b,a");
5655         }
5656     }
5657
5658   /* let's see what's needed: */
5659   /* apply negative sign during runtime */
5660   runtimeSign = FALSE;
5661   /* negative sign from literals */
5662   compiletimeSign = FALSE;
5663
5664   /* sign adjust left side */
5665   if (AOP_TYPE(left) == AOP_LIT)
5666     {
5667       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5668
5669       if (!lUnsigned && val < 0)
5670         {
5671           compiletimeSign = TRUE; /* set sign flag */
5672           emitcode ("mov", "a,#0x%02x", -val);
5673         }
5674       else
5675         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5676     }
5677   else /* ! literal */
5678     {
5679       MOVA (aopGet (left, 0, FALSE, FALSE));
5680
5681       if (!lUnsigned)
5682         {
5683           runtimeSign = TRUE;
5684           emitcode ("clr", "F0"); /* clear sign flag */
5685
5686           lbl = newiTempLabel (NULL);
5687           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5688           emitcode ("setb", "F0"); /* set sign flag */
5689           emitcode ("cpl", "a");   /* 2's complement */
5690           emitcode ("inc", "a");
5691           emitLabel (lbl);
5692         }
5693     }
5694
5695   /* now the modulus */
5696   emitcode ("div", "ab");
5697
5698   if (runtimeSign || compiletimeSign)
5699     {
5700       emitcode ("mov", "a,b");
5701       lbl = newiTempLabel (NULL);
5702       if (runtimeSign)
5703         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5704       emitcode ("cpl", "a"); /* 2's complement */
5705       emitcode ("inc", "a");
5706       emitLabel (lbl);
5707
5708       aopPut (result, "a", 0);
5709       if (size > 0)
5710         {
5711           /* msb is 0x00 or 0xff depending on the sign */
5712           if (runtimeSign)
5713             {
5714               emitcode ("mov", "c,F0");
5715               emitcode ("subb", "a,acc");
5716               while (size--)
5717                 aopPut (result, "a", offset++);
5718             }
5719           else /* compiletimeSign */
5720             while (size--)
5721               aopPut (result, "#0xff", offset++);
5722         }
5723     }
5724   else
5725     {
5726       aopPut (result, "b", 0);
5727       while (size--)
5728         aopPut (result, zero, offset++);
5729     }
5730
5731   popB (pushedB);
5732 }
5733
5734 /*-----------------------------------------------------------------*/
5735 /* genMod - generates code for division                            */
5736 /*-----------------------------------------------------------------*/
5737 static void
5738 genMod (iCode * ic)
5739 {
5740   operand *left = IC_LEFT (ic);
5741   operand *right = IC_RIGHT (ic);
5742   operand *result = IC_RESULT (ic);
5743
5744   D (emitcode (";", "genMod"));
5745
5746   /* assign the asmops */
5747   aopOp (left, ic, FALSE);
5748   aopOp (right, ic, FALSE);
5749   aopOp (result, ic, TRUE);
5750
5751   /* special cases first */
5752   /* both are bits */
5753   if (AOP_TYPE (left) == AOP_CRY &&
5754       AOP_TYPE (right) == AOP_CRY)
5755     {
5756       genModbits (left, right, result);
5757       goto release;
5758     }
5759
5760   /* if both are of size == 1 */
5761   if (AOP_SIZE (left) == 1 &&
5762       AOP_SIZE (right) == 1)
5763     {
5764       genModOneByte (left, right, result);
5765       goto release;
5766     }
5767
5768   /* should have been converted to function call */
5769   assert (0);
5770
5771 release:
5772   freeAsmop (result, NULL, ic, TRUE);
5773   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5774   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5775 }
5776
5777 /*-----------------------------------------------------------------*/
5778 /* genIfxJump :- will create a jump depending on the ifx           */
5779 /*-----------------------------------------------------------------*/
5780 static void
5781 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5782 {
5783   symbol *jlbl;
5784   symbol *tlbl = newiTempLabel (NULL);
5785   char *inst;
5786
5787   D (emitcode (";", "genIfxJump"));
5788
5789   /* if true label then we jump if condition
5790      supplied is true */
5791   if (IC_TRUE (ic))
5792     {
5793       jlbl = IC_TRUE (ic);
5794       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5795                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5796     }
5797   else
5798     {
5799       /* false label is present */
5800       jlbl = IC_FALSE (ic);
5801       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5802                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5803     }
5804   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5805     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5806   else
5807     emitcode (inst, "%05d$", tlbl->key + 100);
5808   freeForBranchAsmop (result);
5809   freeForBranchAsmop (right);
5810   freeForBranchAsmop (left);
5811   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5812   emitLabel (tlbl);
5813
5814   /* mark the icode as generated */
5815   ic->generated = 1;
5816 }
5817
5818 /*-----------------------------------------------------------------*/
5819 /* genCmp :- greater or less than comparison                       */
5820 /*-----------------------------------------------------------------*/
5821 static void
5822 genCmp (operand * left, operand * right,
5823         operand * result, iCode * ifx, int sign, iCode *ic)
5824 {
5825   int size, offset = 0;
5826   unsigned long lit = 0L;
5827   bool rightInB;
5828
5829   D (emitcode (";", "genCmp"));
5830
5831   /* if left & right are bit variables */
5832   if (AOP_TYPE (left) == AOP_CRY &&
5833       AOP_TYPE (right) == AOP_CRY)
5834     {
5835       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5836       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5837     }
5838   else
5839     {
5840       /* subtract right from left if at the
5841          end the carry flag is set then we know that
5842          left is greater than right */
5843       size = max (AOP_SIZE (left), AOP_SIZE (right));
5844
5845       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5846       if ((size == 1) && !sign &&
5847           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5848         {
5849           symbol *lbl = newiTempLabel (NULL);
5850           emitcode ("cjne", "%s,%s,%05d$",
5851                     aopGet (left, offset, FALSE, FALSE),
5852                     aopGet (right, offset, FALSE, FALSE),
5853                     lbl->key + 100);
5854           emitLabel (lbl);
5855         }
5856       else
5857         {
5858           if (AOP_TYPE (right) == AOP_LIT)
5859             {
5860               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5861               /* optimize if(x < 0) or if(x >= 0) */
5862               if (lit == 0L)
5863                 {
5864                   if (!sign)
5865                     {
5866                       CLRC;
5867                     }
5868                   else
5869                     {
5870                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5871                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5872                         {
5873                           genIfxJump (ifx, "acc.7", left, right, result);
5874                           freeAsmop (right, NULL, ic, TRUE);
5875                           freeAsmop (left, NULL, ic, TRUE);
5876
5877                           return;
5878                         }
5879                       else
5880                         {
5881                           emitcode ("rlc", "a");
5882                         }
5883                     }
5884                   goto release;
5885                 }
5886               else
5887                 {//nonzero literal
5888                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5889                   while (size && (bytelit == 0))
5890                     {
5891                       offset++;
5892                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5893                       size--;
5894                     }
5895                   CLRC;
5896                   while (size--)
5897                     {
5898                       MOVA (aopGet (left, offset, FALSE, FALSE));
5899                       if (sign && size == 0)
5900                         {
5901                           emitcode ("xrl", "a,#0x80");
5902                           emitcode ("subb", "a,#0x%02x",
5903                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5904                         }
5905                       else
5906                         {
5907                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5908                         }
5909                       offset++;
5910                     }
5911                   goto release;
5912                 }
5913             }
5914           CLRC;
5915           while (size--)
5916             {
5917               bool pushedB = FALSE;
5918               rightInB = aopGetUsesAcc(right, offset);
5919               if (rightInB)
5920                 {
5921                   pushedB = pushB ();
5922                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5923                 }
5924               MOVA (aopGet (left, offset, FALSE, FALSE));
5925               if (sign && size == 0)
5926                 {
5927                   emitcode ("xrl", "a,#0x80");
5928                   if (!rightInB)
5929                     {
5930                       pushedB = pushB ();
5931                       rightInB++;
5932                       MOVB (aopGet (right, offset, FALSE, FALSE));
5933                     }
5934                   emitcode ("xrl", "b,#0x80");
5935                   emitcode ("subb", "a,b");
5936                 }
5937               else
5938                 {
5939                   if (rightInB)
5940                     emitcode ("subb", "a,b");
5941                   else
5942                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5943                 }
5944               if (rightInB)
5945                 popB (pushedB);
5946               offset++;
5947             }
5948         }
5949     }
5950
5951 release:
5952   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5953   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5954   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5955     {
5956       outBitC (result);
5957     }
5958   else
5959     {
5960       /* if the result is used in the next
5961          ifx conditional branch then generate
5962          code a little differently */
5963       if (ifx)
5964         {
5965           genIfxJump (ifx, "c", NULL, NULL, result);
5966         }
5967       else
5968         {
5969           outBitC (result);
5970         }
5971       /* leave the result in acc */
5972     }
5973 }
5974
5975 /*-----------------------------------------------------------------*/
5976 /* genCmpGt :- greater than comparison                             */
5977 /*-----------------------------------------------------------------*/
5978 static void
5979 genCmpGt (iCode * ic, iCode * ifx)
5980 {
5981   operand *left, *right, *result;
5982   sym_link *letype, *retype;
5983   int sign;
5984
5985   D (emitcode (";", "genCmpGt"));
5986
5987   left = IC_LEFT (ic);
5988   right = IC_RIGHT (ic);
5989   result = IC_RESULT (ic);
5990
5991   letype = getSpec (operandType (left));
5992   retype = getSpec (operandType (right));
5993   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5994            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5995   /* assign the asmops */
5996   aopOp (result, ic, TRUE);
5997   aopOp (left, ic, FALSE);
5998   aopOp (right, ic, FALSE);
5999
6000   genCmp (right, left, result, ifx, sign, ic);
6001
6002   freeAsmop (result, NULL, ic, TRUE);
6003 }
6004
6005 /*-----------------------------------------------------------------*/
6006 /* genCmpLt - less than comparisons                                */
6007 /*-----------------------------------------------------------------*/
6008 static void
6009 genCmpLt (iCode * ic, iCode * ifx)
6010 {
6011   operand *left, *right, *result;
6012   sym_link *letype, *retype;
6013   int sign;
6014
6015   D (emitcode (";", "genCmpLt"));
6016
6017   left = IC_LEFT (ic);
6018   right = IC_RIGHT (ic);
6019   result = IC_RESULT (ic);
6020
6021   letype = getSpec (operandType (left));
6022   retype = getSpec (operandType (right));
6023   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6024            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6025   /* assign the asmops */
6026   aopOp (result, ic, TRUE);
6027   aopOp (left, ic, FALSE);
6028   aopOp (right, ic, FALSE);
6029
6030   genCmp (left, right, result, ifx, sign, ic);
6031
6032   freeAsmop (result, NULL, ic, TRUE);
6033 }
6034
6035 /*-----------------------------------------------------------------*/
6036 /* gencjneshort - compare and jump if not equal                    */
6037 /*-----------------------------------------------------------------*/
6038 static void
6039 gencjneshort (operand * left, operand * right, symbol * lbl)
6040 {
6041   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6042   int offset = 0;
6043   unsigned long lit = 0L;
6044
6045   D (emitcode (";", "gencjneshort"));
6046
6047   /* if the left side is a literal or
6048      if the right is in a pointer register and left
6049      is not */
6050   if ((AOP_TYPE (left) == AOP_LIT)  ||
6051       (AOP_TYPE (left) == AOP_IMMD) ||
6052       (AOP_TYPE (left) == AOP_DIR)  ||
6053       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6054     {
6055       operand *t = right;
6056       right = left;
6057       left = t;
6058     }
6059
6060   if (AOP_TYPE (right) == AOP_LIT)
6061     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6062
6063   /* if the right side is a literal then anything goes */
6064   if (AOP_TYPE (right) == AOP_LIT &&
6065       AOP_TYPE (left) != AOP_DIR  &&
6066       AOP_TYPE (left) != AOP_IMMD)
6067     {
6068       while (size--)
6069         {
6070           emitcode ("cjne", "%s,%s,%05d$",
6071                     aopGet (left, offset, FALSE, FALSE),
6072                     aopGet (right, offset, FALSE, FALSE),
6073                     lbl->key + 100);
6074           offset++;
6075         }
6076     }
6077
6078   /* if the right side is in a register or in direct space or
6079      if the left is a pointer register & right is not */
6080   else if (AOP_TYPE (right) == AOP_REG ||
6081            AOP_TYPE (right) == AOP_DIR ||
6082            AOP_TYPE (right) == AOP_LIT ||
6083            AOP_TYPE (right) == AOP_IMMD ||
6084            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6085            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6086     {
6087       while (size--)
6088         {
6089           MOVA (aopGet (left, offset, FALSE, FALSE));
6090           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6091               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6092             emitcode ("jnz", "%05d$", lbl->key + 100);
6093           else
6094             emitcode ("cjne", "a,%s,%05d$",
6095                       aopGet (right, offset, FALSE, TRUE),
6096                       lbl->key + 100);
6097           offset++;
6098         }
6099     }
6100   else
6101     {
6102       /* right is a pointer reg need both a & b */
6103       while (size--)
6104         {
6105           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6106           wassertl(!BINUSE, "B was in use");
6107           MOVB (aopGet (left, offset, FALSE, FALSE));
6108           MOVA (aopGet (right, offset, FALSE, FALSE));
6109           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6110           offset++;
6111         }
6112     }
6113 }
6114
6115 /*-----------------------------------------------------------------*/
6116 /* gencjne - compare and jump if not equal                         */
6117 /*-----------------------------------------------------------------*/
6118 static void
6119 gencjne (operand * left, operand * right, symbol * lbl)
6120 {
6121   symbol *tlbl = newiTempLabel (NULL);
6122
6123   D (emitcode (";", "gencjne"));
6124
6125   gencjneshort (left, right, lbl);
6126
6127   emitcode ("mov", "a,%s", one);
6128   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6129   emitLabel (lbl);
6130   emitcode ("clr", "a");
6131   emitLabel (tlbl);
6132 }
6133
6134 /*-----------------------------------------------------------------*/
6135 /* genCmpEq - generates code for equal to                          */
6136 /*-----------------------------------------------------------------*/
6137 static void
6138 genCmpEq (iCode * ic, iCode * ifx)
6139 {
6140   bool swappedLR = FALSE;
6141   operand *left, *right, *result;
6142
6143   D (emitcode (";", "genCmpEq"));
6144
6145   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6146   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6147   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6148
6149   /* if literal, literal on the right or
6150      if the right is in a pointer register and left
6151      is not */
6152   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6153       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6154     {
6155       operand *t = IC_RIGHT (ic);
6156       IC_RIGHT (ic) = IC_LEFT (ic);
6157       IC_LEFT (ic) = t;
6158       swappedLR = TRUE;
6159     }
6160
6161   if (ifx && !AOP_SIZE (result))
6162     {
6163       symbol *tlbl;
6164       /* if they are both bit variables */
6165       if (AOP_TYPE (left) == AOP_CRY &&
6166           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6167         {
6168           if (AOP_TYPE (right) == AOP_LIT)
6169             {
6170               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6171               if (lit == 0L)
6172                 {
6173                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6174                   emitcode ("cpl", "c");
6175                 }
6176               else if (lit == 1L)
6177                 {
6178                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6179                 }
6180               else
6181                 {
6182                   emitcode ("clr", "c");
6183                 }
6184               /* AOP_TYPE(right) == AOP_CRY */
6185             }
6186           else
6187             {
6188               symbol *lbl = newiTempLabel (NULL);
6189               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6190               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6191               emitcode ("cpl", "c");
6192               emitLabel (lbl);
6193             }
6194           /* if true label then we jump if condition
6195              supplied is true */
6196           tlbl = newiTempLabel (NULL);
6197           if (IC_TRUE (ifx))
6198             {
6199               emitcode ("jnc", "%05d$", tlbl->key + 100);
6200               freeForBranchAsmop (result);
6201               freeForBranchAsmop (right);
6202               freeForBranchAsmop (left);
6203               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6204             }
6205           else
6206             {
6207               emitcode ("jc", "%05d$", tlbl->key + 100);
6208               freeForBranchAsmop (result);
6209               freeForBranchAsmop (right);
6210               freeForBranchAsmop (left);
6211               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6212             }
6213           emitLabel (tlbl);
6214         }
6215       else
6216         {
6217           tlbl = newiTempLabel (NULL);
6218           gencjneshort (left, right, tlbl);
6219           if (IC_TRUE (ifx))
6220             {
6221               freeForBranchAsmop (result);
6222               freeForBranchAsmop (right);
6223               freeForBranchAsmop (left);
6224               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6225               emitLabel (tlbl);
6226             }
6227           else
6228             {
6229               symbol *lbl = newiTempLabel (NULL);
6230               emitcode ("sjmp", "%05d$", lbl->key + 100);
6231               emitLabel (tlbl);
6232               freeForBranchAsmop (result);
6233               freeForBranchAsmop (right);
6234               freeForBranchAsmop (left);
6235               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6236               emitLabel (lbl);
6237             }
6238         }
6239       /* mark the icode as generated */
6240       ifx->generated = 1;
6241       goto release;
6242     }
6243
6244   /* if they are both bit variables */
6245   if (AOP_TYPE (left) == AOP_CRY &&
6246       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6247     {
6248       if (AOP_TYPE (right) == AOP_LIT)
6249         {
6250           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6251           if (lit == 0L)
6252             {
6253               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6254               emitcode ("cpl", "c");
6255             }
6256           else if (lit == 1L)
6257             {
6258               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6259             }
6260           else
6261             {
6262               emitcode ("clr", "c");
6263             }
6264           /* AOP_TYPE(right) == AOP_CRY */
6265         }
6266       else
6267         {
6268           symbol *lbl = newiTempLabel (NULL);
6269           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6270           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6271           emitcode ("cpl", "c");
6272           emitLabel (lbl);
6273         }
6274       /* c = 1 if egal */
6275       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6276         {
6277           outBitC (result);
6278           goto release;
6279         }
6280       if (ifx)
6281         {
6282           genIfxJump (ifx, "c", left, right, result);
6283           goto release;
6284         }
6285       /* if the result is used in an arithmetic operation
6286          then put the result in place */
6287       outBitC (result);
6288     }
6289   else
6290     {
6291       gencjne (left, right, newiTempLabel (NULL));
6292       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6293         {
6294           aopPut (result, "a", 0);
6295           goto release;
6296         }
6297       if (ifx)
6298         {
6299           genIfxJump (ifx, "a", left, right, result);
6300           goto release;
6301         }
6302       /* if the result is used in an arithmetic operation
6303          then put the result in place */
6304       if (AOP_TYPE (result) != AOP_CRY)
6305         outAcc (result);
6306       /* leave the result in acc */
6307     }
6308
6309 release:
6310   freeAsmop (result, NULL, ic, TRUE);
6311   if (!swappedLR)
6312     {
6313       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6314       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6315     }
6316   else
6317     {
6318       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6319       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6320     }
6321 }
6322
6323 /*-----------------------------------------------------------------*/
6324 /* ifxForOp - returns the icode containing the ifx for operand     */
6325 /*-----------------------------------------------------------------*/
6326 static iCode *
6327 ifxForOp (operand * op, iCode * ic)
6328 {
6329   /* if true symbol then needs to be assigned */
6330   if (IS_TRUE_SYMOP (op))
6331     return NULL;
6332
6333   /* if this has register type condition and
6334      the next instruction is ifx with the same operand
6335      and live to of the operand is upto the ifx only then */
6336   if (ic->next &&
6337       ic->next->op == IFX &&
6338       IC_COND (ic->next)->key == op->key &&
6339       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6340     return ic->next;
6341
6342   return NULL;
6343 }
6344
6345 /*-----------------------------------------------------------------*/
6346 /* hasInc - operand is incremented before any other use            */
6347 /*-----------------------------------------------------------------*/
6348 static iCode *
6349 hasInc (operand *op, iCode *ic, int osize)
6350 {
6351   sym_link *type = operandType(op);
6352   sym_link *retype = getSpec (type);
6353   iCode *lic = ic->next;
6354   int isize ;
6355
6356   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6357   if (!IS_SYMOP(op)) return NULL;
6358
6359   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6360   if (IS_AGGREGATE(type->next)) return NULL;
6361   if (osize != (isize = getSize(type->next))) return NULL;
6362
6363   while (lic) {
6364     /* if operand of the form op = op + <sizeof *op> */
6365     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6366         isOperandEqual(IC_RESULT(lic),op) &&
6367         isOperandLiteral(IC_RIGHT(lic)) &&
6368         operandLitValue(IC_RIGHT(lic)) == isize) {
6369       return lic;
6370     }
6371     /* if the operand used or deffed */
6372     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6373       return NULL;
6374     }
6375     /* if GOTO or IFX */
6376     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6377     lic = lic->next;
6378   }
6379   return NULL;
6380 }
6381
6382 /*-----------------------------------------------------------------*/
6383 /* genAndOp - for && operation                                     */
6384 /*-----------------------------------------------------------------*/
6385 static void
6386 genAndOp (iCode * ic)
6387 {
6388   operand *left, *right, *result;
6389   symbol *tlbl;
6390
6391   D (emitcode (";", "genAndOp"));
6392
6393   /* note here that && operations that are in an
6394      if statement are taken away by backPatchLabels
6395      only those used in arthmetic operations remain */
6396   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6397   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6398   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6399
6400   /* if both are bit variables */
6401   if (AOP_TYPE (left) == AOP_CRY &&
6402       AOP_TYPE (right) == AOP_CRY)
6403     {
6404       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6405       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6406       outBitC (result);
6407     }
6408   else
6409     {
6410       tlbl = newiTempLabel (NULL);
6411       toBoolean (left);
6412       emitcode ("jz", "%05d$", tlbl->key + 100);
6413       toBoolean (right);
6414       emitLabel (tlbl);
6415       outBitAcc (result);
6416     }
6417
6418   freeAsmop (result, NULL, ic, TRUE);
6419   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6420   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6421 }
6422
6423
6424 /*-----------------------------------------------------------------*/
6425 /* genOrOp - for || operation                                      */
6426 /*-----------------------------------------------------------------*/
6427 static void
6428 genOrOp (iCode * ic)
6429 {
6430   operand *left, *right, *result;
6431   symbol *tlbl;
6432
6433   D (emitcode (";", "genOrOp"));
6434
6435   /* note here that || operations that are in an
6436      if statement are taken away by backPatchLabels
6437      only those used in arthmetic operations remain */
6438   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6439   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6440   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6441
6442   /* if both are bit variables */
6443   if (AOP_TYPE (left) == AOP_CRY &&
6444       AOP_TYPE (right) == AOP_CRY)
6445     {
6446       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6447       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6448       outBitC (result);
6449     }
6450   else
6451     {
6452       tlbl = newiTempLabel (NULL);
6453       toBoolean (left);
6454       emitcode ("jnz", "%05d$", tlbl->key + 100);
6455       toBoolean (right);
6456       emitLabel (tlbl);
6457       outBitAcc (result);
6458     }
6459
6460   freeAsmop (result, NULL, ic, TRUE);
6461   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6462   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6463 }
6464
6465 /*-----------------------------------------------------------------*/
6466 /* isLiteralBit - test if lit == 2^n                               */
6467 /*-----------------------------------------------------------------*/
6468 static int
6469 isLiteralBit (unsigned long lit)
6470 {
6471   unsigned long pw[32] =
6472   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6473    0x100L, 0x200L, 0x400L, 0x800L,
6474    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6475    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6476    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6477    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6478    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6479   int idx;
6480
6481   for (idx = 0; idx < 32; idx++)
6482     if (lit == pw[idx])
6483       return idx + 1;
6484   return 0;
6485 }
6486
6487 /*-----------------------------------------------------------------*/
6488 /* continueIfTrue -                                                */
6489 /*-----------------------------------------------------------------*/
6490 static void
6491 continueIfTrue (iCode * ic)
6492 {
6493   if (IC_TRUE (ic))
6494     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6495   ic->generated = 1;
6496 }
6497
6498 /*-----------------------------------------------------------------*/
6499 /* jmpIfTrue -                                                     */
6500 /*-----------------------------------------------------------------*/
6501 static void
6502 jumpIfTrue (iCode * ic)
6503 {
6504   if (!IC_TRUE (ic))
6505     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6506   ic->generated = 1;
6507 }
6508
6509 /*-----------------------------------------------------------------*/
6510 /* jmpTrueOrFalse -                                                */
6511 /*-----------------------------------------------------------------*/
6512 static void
6513 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6514 {
6515   // ugly but optimized by peephole
6516   if (IC_TRUE (ic))
6517     {
6518       symbol *nlbl = newiTempLabel (NULL);
6519       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6520       emitLabel (tlbl);
6521       freeForBranchAsmop (result);
6522       freeForBranchAsmop (right);
6523       freeForBranchAsmop (left);
6524       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6525       emitLabel (nlbl);
6526     }
6527   else
6528     {
6529       freeForBranchAsmop (result);
6530       freeForBranchAsmop (right);
6531       freeForBranchAsmop (left);
6532       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6533       emitLabel (tlbl);
6534     }
6535   ic->generated = 1;
6536 }
6537
6538 /*-----------------------------------------------------------------*/
6539 /* genAnd  - code for and                                          */
6540 /*-----------------------------------------------------------------*/
6541 static void
6542 genAnd (iCode * ic, iCode * ifx)
6543 {
6544   operand *left, *right, *result;
6545   int size, offset = 0;
6546   unsigned long lit = 0L;
6547   int bytelit = 0;
6548   char buffer[10];
6549
6550   D (emitcode (";", "genAnd"));
6551
6552   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6553   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6554   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6555
6556 #ifdef DEBUG_TYPE
6557   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6558             AOP_TYPE (result),
6559             AOP_TYPE (left), AOP_TYPE (right));
6560   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6561             AOP_SIZE (result),
6562             AOP_SIZE (left), AOP_SIZE (right));
6563 #endif
6564
6565   /* if left is a literal & right is not then exchange them */
6566   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6567       AOP_NEEDSACC (left))
6568     {
6569       operand *tmp = right;
6570       right = left;
6571       left = tmp;
6572     }
6573
6574   /* if result = right then exchange left and right */
6575   if (sameRegs (AOP (result), AOP (right)))
6576     {
6577       operand *tmp = right;
6578       right = left;
6579       left = tmp;
6580     }
6581
6582   /* if right is bit then exchange them */
6583   if (AOP_TYPE (right) == AOP_CRY &&
6584       AOP_TYPE (left) != AOP_CRY)
6585     {
6586       operand *tmp = right;
6587       right = left;
6588       left = tmp;
6589     }
6590   if (AOP_TYPE (right) == AOP_LIT)
6591     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6592
6593   size = AOP_SIZE (result);
6594
6595   // if(bit & yy)
6596   // result = bit & yy;
6597   if (AOP_TYPE (left) == AOP_CRY)
6598     {
6599       // c = bit & literal;
6600       if (AOP_TYPE (right) == AOP_LIT)
6601         {
6602           if (lit & 1)
6603             {
6604               if (size && sameRegs (AOP (result), AOP (left)))
6605                 // no change
6606                 goto release;
6607               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6608             }
6609           else
6610             {
6611               // bit(result) = 0;
6612               if (size && (AOP_TYPE (result) == AOP_CRY))
6613                 {
6614                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6615                   goto release;
6616                 }
6617               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6618                 {
6619                   jumpIfTrue (ifx);
6620                   goto release;
6621                 }
6622               emitcode ("clr", "c");
6623             }
6624         }
6625       else
6626         {
6627           if (AOP_TYPE (right) == AOP_CRY)
6628             {
6629               // c = bit & bit;
6630               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6631               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6632             }
6633           else
6634             {
6635               // c = bit & val;
6636               MOVA (aopGet (right, 0, FALSE, FALSE));
6637               // c = lsb
6638               emitcode ("rrc", "a");
6639               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6640             }
6641         }
6642       // bit = c
6643       // val = c
6644       if (size)
6645         outBitC (result);
6646       // if(bit & ...)
6647       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6648         genIfxJump (ifx, "c", left, right, result);
6649       goto release;
6650     }
6651
6652   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6653   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6654   if ((AOP_TYPE (right) == AOP_LIT) &&
6655       (AOP_TYPE (result) == AOP_CRY) &&
6656       (AOP_TYPE (left) != AOP_CRY))
6657     {
6658       int posbit = isLiteralBit (lit);
6659       /* left &  2^n */
6660       if (posbit)
6661         {
6662           posbit--;
6663           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6664           // bit = left & 2^n
6665           if (size)
6666             {
6667               switch (posbit & 0x07)
6668                 {
6669                   case 0: emitcode ("rrc", "a");
6670                           break;
6671                   case 7: emitcode ("rlc", "a");
6672                           break;
6673                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6674                           break;
6675                 }
6676             }
6677           // if(left &  2^n)
6678           else
6679             {
6680               if (ifx)
6681                 {
6682                   SNPRINTF (buffer, sizeof(buffer),
6683                             "acc.%d", posbit & 0x07);
6684                   genIfxJump (ifx, buffer, left, right, result);
6685                 }
6686               else
6687                 {// what is this case? just found it in ds390/gen.c
6688                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6689                 }
6690               goto release;
6691             }
6692         }
6693       else
6694         {
6695           symbol *tlbl = newiTempLabel (NULL);
6696           int sizel = AOP_SIZE (left);
6697           if (size)
6698             emitcode ("setb", "c");
6699           while (sizel--)
6700             {
6701               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6702                 {
6703                   MOVA (aopGet (left, offset, FALSE, FALSE));
6704                   // byte ==  2^n ?
6705                   if ((posbit = isLiteralBit (bytelit)) != 0)
6706                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6707                   else
6708                     {
6709                       if (bytelit != 0x0FFL)
6710                         emitcode ("anl", "a,%s",
6711                                   aopGet (right, offset, FALSE, TRUE));
6712                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6713                     }
6714                 }
6715               offset++;
6716             }
6717           // bit = left & literal
6718           if (size)
6719             {
6720               emitcode ("clr", "c");
6721               emitLabel (tlbl);
6722             }
6723           // if(left & literal)
6724           else
6725             {
6726               if (ifx)
6727                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6728               else
6729                 emitLabel (tlbl);
6730               goto release;
6731             }
6732         }
6733       outBitC (result);
6734       goto release;
6735     }
6736
6737   /* if left is same as result */
6738   if (sameRegs (AOP (result), AOP (left)))
6739     {
6740       for (; size--; offset++)
6741         {
6742           if (AOP_TYPE (right) == AOP_LIT)
6743             {
6744               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6745               if (bytelit == 0x0FF)
6746                 {
6747                   /* dummy read of volatile operand */
6748                   if (isOperandVolatile (left, FALSE))
6749                     MOVA (aopGet (left, offset, FALSE, FALSE));
6750                   else
6751                     continue;
6752                 }
6753               else if (bytelit == 0)
6754                 {
6755                   aopPut (result, zero, offset);
6756                 }
6757               else if (IS_AOP_PREG (result))
6758                 {
6759                   MOVA (aopGet (left, offset, FALSE, TRUE));
6760                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6761                   aopPut (result, "a", offset);
6762                 }
6763               else
6764                 emitcode ("anl", "%s,%s",
6765                           aopGet (left, offset, FALSE, TRUE),
6766                           aopGet (right, offset, FALSE, FALSE));
6767             }
6768           else
6769             {
6770               if (AOP_TYPE (left) == AOP_ACC)
6771                 {
6772                   if (offset)
6773                     emitcode("mov", "a,b");
6774                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6775                 }
6776               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6777                 {
6778                   MOVB (aopGet (left, offset, FALSE, FALSE));
6779                   MOVA (aopGet (right, offset, FALSE, FALSE));
6780                   emitcode ("anl", "a,b");
6781                   aopPut (result, "a", offset);
6782                 }
6783               else if (aopGetUsesAcc (left, offset))
6784                 {
6785                   MOVA (aopGet (left, offset, FALSE, FALSE));
6786                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6787                   aopPut (result, "a", offset);
6788                 }
6789               else
6790                 {
6791                   MOVA (aopGet (right, offset, FALSE, FALSE));
6792                   if (IS_AOP_PREG (result))
6793                     {
6794                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6795                       aopPut (result, "a", offset);
6796                     }
6797                   else
6798                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6799                 }
6800             }
6801         }
6802     }
6803   else
6804     {
6805       // left & result in different registers
6806       if (AOP_TYPE (result) == AOP_CRY)
6807         {
6808           // result = bit
6809           // if(size), result in bit
6810           // if(!size && ifx), conditional oper: if(left & right)
6811           symbol *tlbl = newiTempLabel (NULL);
6812           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6813           if (size)
6814             emitcode ("setb", "c");
6815           while (sizer--)
6816             {
6817               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6818                   && AOP_TYPE(left)==AOP_ACC)
6819                 {
6820                   if (offset)
6821                     emitcode("mov", "a,b");
6822                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6823                 }
6824               else if (AOP_TYPE(left)==AOP_ACC)
6825                 {
6826                   if (!offset)
6827                     {
6828                       bool pushedB = pushB ();
6829                       emitcode("mov", "b,a");
6830                       MOVA (aopGet (right, offset, FALSE, FALSE));
6831                       emitcode("anl", "a,b");
6832                       popB (pushedB);
6833                     }
6834                   else
6835                     {
6836                       MOVA (aopGet (right, offset, FALSE, FALSE));
6837                       emitcode("anl", "a,b");
6838                     }
6839                 }
6840               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6841                 {
6842                   MOVB (aopGet (left, offset, FALSE, FALSE));
6843                   MOVA (aopGet (right, offset, FALSE, FALSE));
6844                   emitcode ("anl", "a,b");
6845                 }
6846               else if (aopGetUsesAcc (left, offset))
6847                 {
6848                   MOVA (aopGet (left, offset, FALSE, FALSE));
6849                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6850                     }
6851               else
6852                 {
6853                   MOVA (aopGet (right, offset, FALSE, FALSE));
6854                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6855                 }
6856
6857               emitcode ("jnz", "%05d$", tlbl->key + 100);
6858               offset++;
6859             }
6860           if (size)
6861             {
6862               CLRC;
6863               emitLabel (tlbl);
6864               outBitC (result);
6865             }
6866           else if (ifx)
6867             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6868           else
6869             emitLabel (tlbl);
6870         }
6871       else
6872         {
6873           for (; (size--); offset++)
6874             {
6875               // normal case
6876               // result = left & right
6877               if (AOP_TYPE (right) == AOP_LIT)
6878                 {
6879                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6880                   if (bytelit == 0x0FF)
6881                     {
6882                       aopPut (result,
6883                               aopGet (left, offset, FALSE, FALSE),
6884                               offset);
6885                       continue;
6886                     }
6887                   else if (bytelit == 0)
6888                     {
6889                       /* dummy read of volatile operand */
6890                       if (isOperandVolatile (left, FALSE))
6891                         MOVA (aopGet (left, offset, FALSE, FALSE));
6892                       aopPut (result, zero, offset);
6893                       continue;
6894                     }
6895                   else if (AOP_TYPE (left) == AOP_ACC)
6896                     {
6897                       if (!offset)
6898                         {
6899                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6900                           aopPut (result, "a", offset);
6901                           continue;
6902                         }
6903                       else
6904                         {
6905                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6906                           aopPut (result, "b", offset);
6907                           continue;
6908                         }
6909                     }
6910                 }
6911               // faster than result <- left, anl result,right
6912               // and better if result is SFR
6913               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6914                   && AOP_TYPE(left)==AOP_ACC)
6915                 {
6916                   if (offset)
6917                     emitcode("mov", "a,b");
6918                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6919                 }
6920               else if (AOP_TYPE(left)==AOP_ACC)
6921                 {
6922                   if (!offset)
6923                     {
6924                       bool pushedB = pushB ();
6925                       emitcode("mov", "b,a");
6926                       MOVA (aopGet (right, offset, FALSE, FALSE));
6927                       emitcode("anl", "a,b");
6928                       popB (pushedB);
6929                     }
6930                   else
6931                     {
6932                       MOVA (aopGet (right, offset, FALSE, FALSE));
6933                       emitcode("anl", "a,b");
6934                     }
6935                 }
6936               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6937                 {
6938                   MOVB (aopGet (left, offset, FALSE, FALSE));
6939                   MOVA (aopGet (right, offset, FALSE, FALSE));
6940                   emitcode ("anl", "a,b");
6941                 }
6942               else if (aopGetUsesAcc (left, offset))
6943                 {
6944                   MOVA (aopGet (left, offset, FALSE, FALSE));
6945                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6946                 }
6947               else
6948                 {
6949                   MOVA (aopGet (right, offset, FALSE, FALSE));
6950                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6951                 }
6952               aopPut (result, "a", offset);
6953             }
6954         }
6955     }
6956
6957 release:
6958   freeAsmop (result, NULL, ic, TRUE);
6959   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6960   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6961 }
6962
6963 /*-----------------------------------------------------------------*/
6964 /* genOr  - code for or                                            */
6965 /*-----------------------------------------------------------------*/
6966 static void
6967 genOr (iCode * ic, iCode * ifx)
6968 {
6969   operand *left, *right, *result;
6970   int size, offset = 0;
6971   unsigned long lit = 0L;
6972   int bytelit = 0;
6973
6974   D (emitcode (";", "genOr"));
6975
6976   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6977   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6978   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6979
6980 #ifdef DEBUG_TYPE
6981   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6982             AOP_TYPE (result),
6983             AOP_TYPE (left), AOP_TYPE (right));
6984   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6985             AOP_SIZE (result),
6986             AOP_SIZE (left), AOP_SIZE (right));
6987 #endif
6988
6989   /* if left is a literal & right is not then exchange them */
6990   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6991       AOP_NEEDSACC (left))
6992     {
6993       operand *tmp = right;
6994       right = left;
6995       left = tmp;
6996     }
6997
6998   /* if result = right then exchange them */
6999   if (sameRegs (AOP (result), AOP (right)))
7000     {
7001       operand *tmp = right;
7002       right = left;
7003       left = tmp;
7004     }
7005
7006   /* if right is bit then exchange them */
7007   if (AOP_TYPE (right) == AOP_CRY &&
7008       AOP_TYPE (left) != AOP_CRY)
7009     {
7010       operand *tmp = right;
7011       right = left;
7012       left = tmp;
7013     }
7014   if (AOP_TYPE (right) == AOP_LIT)
7015     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7016
7017   size = AOP_SIZE (result);
7018
7019   // if(bit | yy)
7020   // xx = bit | yy;
7021   if (AOP_TYPE (left) == AOP_CRY)
7022     {
7023       if (AOP_TYPE (right) == AOP_LIT)
7024         {
7025           // c = bit | literal;
7026           if (lit)
7027             {
7028               // lit != 0 => result = 1
7029               if (AOP_TYPE (result) == AOP_CRY)
7030                 {
7031                   if (size)
7032                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7033                   else if (ifx)
7034                     continueIfTrue (ifx);
7035                   goto release;
7036                 }
7037               emitcode ("setb", "c");
7038             }
7039           else
7040             {
7041               // lit == 0 => result = left
7042               if (size && sameRegs (AOP (result), AOP (left)))
7043                 goto release;
7044               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7045             }
7046         }
7047       else
7048         {
7049           if (AOP_TYPE (right) == AOP_CRY)
7050             {
7051               // c = bit | bit;
7052               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7053               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7054             }
7055           else
7056             {
7057               // c = bit | val;
7058               symbol *tlbl = newiTempLabel (NULL);
7059               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7060                 emitcode ("setb", "c");
7061               emitcode ("jb", "%s,%05d$",
7062                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7063               toBoolean (right);
7064               emitcode ("jnz", "%05d$", tlbl->key + 100);
7065               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7066                 {
7067                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7068                   goto release;
7069                 }
7070               else
7071                 {
7072                   CLRC;
7073                   emitLabel (tlbl);
7074                 }
7075             }
7076         }
7077       // bit = c
7078       // val = c
7079       if (size)
7080         outBitC (result);
7081       // if(bit | ...)
7082       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7083         genIfxJump (ifx, "c", left, right, result);
7084       goto release;
7085     }
7086
7087   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7088   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7089   if ((AOP_TYPE (right) == AOP_LIT) &&
7090       (AOP_TYPE (result) == AOP_CRY) &&
7091       (AOP_TYPE (left) != AOP_CRY))
7092     {
7093       if (lit)
7094         {
7095           // result = 1
7096           if (size)
7097             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7098           else
7099             continueIfTrue (ifx);
7100           goto release;
7101         }
7102       else
7103         {
7104           // lit = 0, result = boolean(left)
7105           if (size)
7106             emitcode ("setb", "c");
7107           toBoolean (right);
7108           if (size)
7109             {
7110               symbol *tlbl = newiTempLabel (NULL);
7111               emitcode ("jnz", "%05d$", tlbl->key + 100);
7112               CLRC;
7113               emitLabel (tlbl);
7114             }
7115           else
7116             {
7117               genIfxJump (ifx, "a", left, right, result);
7118               goto release;
7119             }
7120         }
7121       outBitC (result);
7122       goto release;
7123     }
7124
7125   /* if left is same as result */
7126   if (sameRegs (AOP (result), AOP (left)))
7127     {
7128       for (; size--; offset++)
7129         {
7130           if (AOP_TYPE (right) == AOP_LIT)
7131             {
7132               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7133               if (bytelit == 0)
7134                 {
7135                   /* dummy read of volatile operand */
7136                   if (isOperandVolatile (left, FALSE))
7137                     MOVA (aopGet (left, offset, FALSE, FALSE));
7138                   else
7139                     continue;
7140                 }
7141               else if (bytelit == 0x0FF)
7142                 {
7143                   aopPut (result, "#0xFF", offset);
7144                 }
7145               else if (IS_AOP_PREG (left))
7146                 {
7147                   MOVA (aopGet (left, offset, FALSE, TRUE));
7148                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7149                   aopPut (result, "a", offset);
7150                 }
7151               else
7152                 {
7153                   emitcode ("orl", "%s,%s",
7154                             aopGet (left, offset, FALSE, TRUE),
7155                             aopGet (right, offset, FALSE, FALSE));
7156                 }
7157             }
7158           else
7159             {
7160               if (AOP_TYPE (left) == AOP_ACC)
7161                 {
7162                   if (offset)
7163                     emitcode("mov", "a,b");
7164                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7165                 }
7166               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7167                 {
7168                   MOVB (aopGet (left, offset, FALSE, FALSE));
7169                   MOVA (aopGet (right, offset, FALSE, FALSE));
7170                   emitcode ("orl", "a,b");
7171                   aopPut (result, "a", offset);
7172                 }
7173               else if (aopGetUsesAcc (left, offset))
7174                 {
7175                   MOVA (aopGet (left, offset, FALSE, FALSE));
7176                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7177                   aopPut (result, "a", offset);
7178                 }
7179               else
7180                 {
7181                   MOVA (aopGet (right, offset, FALSE, FALSE));
7182                   if (IS_AOP_PREG (left))
7183                     {
7184                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7185                       aopPut (result, "a", offset);
7186                     }
7187                   else
7188                     {
7189                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7190                     }
7191                 }
7192             }
7193         }
7194     }
7195   else
7196     {
7197       // left & result in different registers
7198       if (AOP_TYPE (result) == AOP_CRY)
7199         {
7200           // result = bit
7201           // if(size), result in bit
7202           // if(!size && ifx), conditional oper: if(left | right)
7203           symbol *tlbl = newiTempLabel (NULL);
7204           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7205           if (size)
7206             emitcode ("setb", "c");
7207           while (sizer--)
7208             {
7209               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7210                   && AOP_TYPE(left)==AOP_ACC)
7211                 {
7212                   if (offset)
7213                     emitcode("mov", "a,b");
7214                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7215                 }
7216               else if (AOP_TYPE(left)==AOP_ACC)
7217                 {
7218                   if (!offset)
7219                     {
7220                       bool pushedB = pushB ();
7221                       emitcode("mov", "b,a");
7222                       MOVA (aopGet (right, offset, FALSE, FALSE));
7223                       emitcode("orl", "a,b");
7224                       popB (pushedB);
7225                     }
7226                   else
7227                     {
7228                       MOVA (aopGet (right, offset, FALSE, FALSE));
7229                       emitcode("orl", "a,b");
7230                     }
7231                 }
7232               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7233                 {
7234                   MOVB (aopGet (left, offset, FALSE, FALSE));
7235                   MOVA (aopGet (right, offset, FALSE, FALSE));
7236                   emitcode ("orl", "a,b");
7237                 }
7238               else if (aopGetUsesAcc (left, offset))
7239                 {
7240                   MOVA (aopGet (left, offset, FALSE, FALSE));
7241                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7242                 }
7243               else
7244                 {
7245                   MOVA (aopGet (right, offset, FALSE, FALSE));
7246                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7247               }
7248
7249               emitcode ("jnz", "%05d$", tlbl->key + 100);
7250               offset++;
7251             }
7252           if (size)
7253             {
7254               CLRC;
7255               emitLabel (tlbl);
7256               outBitC (result);
7257             }
7258           else if (ifx)
7259             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7260           else
7261             emitLabel (tlbl);
7262         }
7263       else
7264         {
7265           for (; (size--); offset++)
7266             {
7267               // normal case
7268               // result = left | right
7269               if (AOP_TYPE (right) == AOP_LIT)
7270                 {
7271                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7272                   if (bytelit == 0)
7273                     {
7274                       aopPut (result,
7275                               aopGet (left, offset, FALSE, FALSE),
7276                               offset);
7277                       continue;
7278                     }
7279                   else if (bytelit == 0x0FF)
7280                     {
7281                       /* dummy read of volatile operand */
7282                       if (isOperandVolatile (left, FALSE))
7283                         MOVA (aopGet (left, offset, FALSE, FALSE));
7284                       aopPut (result, "#0xFF", offset);
7285                       continue;
7286                     }
7287                 }
7288               // faster than result <- left, orl result,right
7289               // and better if result is SFR
7290               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7291                   && AOP_TYPE(left)==AOP_ACC)
7292                 {
7293                   if (offset)
7294                     emitcode("mov", "a,b");
7295                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7296                 }
7297               else if (AOP_TYPE(left)==AOP_ACC)
7298                 {
7299                   if (!offset)
7300                     {
7301                       bool pushedB = pushB ();
7302                       emitcode("mov", "b,a");
7303                       MOVA (aopGet (right, offset, FALSE, FALSE));
7304                       emitcode("orl", "a,b");
7305                       popB (pushedB);
7306                     }
7307                   else
7308                     {
7309                       MOVA (aopGet (right, offset, FALSE, FALSE));
7310                       emitcode("orl", "a,b");
7311                     }
7312                 }
7313               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7314                 {
7315                   MOVB (aopGet (left, offset, FALSE, FALSE));
7316                   MOVA (aopGet (right, offset, FALSE, FALSE));
7317                   emitcode ("orl", "a,b");
7318                 }
7319               else if (aopGetUsesAcc (left, offset))
7320                 {
7321                   MOVA (aopGet (left, offset, FALSE, FALSE));
7322                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7323                 }
7324               else
7325                 {
7326                   MOVA (aopGet (right, offset, FALSE, FALSE));
7327                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7328                 }
7329               aopPut (result, "a", offset);
7330             }
7331         }
7332     }
7333
7334 release:
7335   freeAsmop (result, NULL, ic, TRUE);
7336   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7337   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7338 }
7339
7340 /*-----------------------------------------------------------------*/
7341 /* genXor - code for xclusive or                                   */
7342 /*-----------------------------------------------------------------*/
7343 static void
7344 genXor (iCode * ic, iCode * ifx)
7345 {
7346   operand *left, *right, *result;
7347   int size, offset = 0;
7348   unsigned long lit = 0L;
7349   int bytelit = 0;
7350
7351   D (emitcode (";", "genXor"));
7352
7353   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7354   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7355   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7356
7357 #ifdef DEBUG_TYPE
7358   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7359             AOP_TYPE (result),
7360             AOP_TYPE (left), AOP_TYPE (right));
7361   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7362             AOP_SIZE (result),
7363             AOP_SIZE (left), AOP_SIZE (right));
7364 #endif
7365
7366   /* if left is a literal & right is not ||
7367      if left needs acc & right does not */
7368   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7369       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7370     {
7371       operand *tmp = right;
7372       right = left;
7373       left = tmp;
7374     }
7375
7376   /* if result = right then exchange them */
7377   if (sameRegs (AOP (result), AOP (right)))
7378     {
7379       operand *tmp = right;
7380       right = left;
7381       left = tmp;
7382     }
7383
7384   /* if right is bit then exchange them */
7385   if (AOP_TYPE (right) == AOP_CRY &&
7386       AOP_TYPE (left) != AOP_CRY)
7387     {
7388       operand *tmp = right;
7389       right = left;
7390       left = tmp;
7391     }
7392
7393   if (AOP_TYPE (right) == AOP_LIT)
7394     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7395
7396   size = AOP_SIZE (result);
7397
7398   // if(bit ^ yy)
7399   // xx = bit ^ yy;
7400   if (AOP_TYPE (left) == AOP_CRY)
7401     {
7402       if (AOP_TYPE (right) == AOP_LIT)
7403         {
7404           // c = bit & literal;
7405           if (lit >> 1)
7406             {
7407               // lit>>1  != 0 => result = 1
7408               if (AOP_TYPE (result) == AOP_CRY)
7409                 {
7410                   if (size)
7411                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7412                   else if (ifx)
7413                     continueIfTrue (ifx);
7414                   goto release;
7415                 }
7416               emitcode ("setb", "c");
7417             }
7418           else
7419             {
7420               // lit == (0 or 1)
7421               if (lit == 0)
7422                 {
7423                   // lit == 0, result = left
7424                   if (size && sameRegs (AOP (result), AOP (left)))
7425                     goto release;
7426                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7427                 }
7428               else
7429                 {
7430                   // lit == 1, result = not(left)
7431                   if (size && sameRegs (AOP (result), AOP (left)))
7432                     {
7433                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7434                       goto release;
7435                     }
7436                   else
7437                     {
7438                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7439                       emitcode ("cpl", "c");
7440                     }
7441                 }
7442             }
7443         }
7444       else
7445         {
7446           // right != literal
7447           symbol *tlbl = newiTempLabel (NULL);
7448           if (AOP_TYPE (right) == AOP_CRY)
7449             {
7450               // c = bit ^ bit;
7451               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7452             }
7453           else
7454             {
7455               // c = bit ^ val
7456               toCarry (right);
7457             }
7458           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7459           emitcode ("cpl", "c");
7460           emitLabel (tlbl);
7461         }
7462       // bit = c
7463       // val = c
7464       if (size)
7465         outBitC (result);
7466       // if(bit ^ ...)
7467       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7468         genIfxJump (ifx, "c", left, right, result);
7469       goto release;
7470     }
7471
7472   /* if left is same as result */
7473   if (sameRegs (AOP (result), AOP (left)))
7474     {
7475       for (; size--; offset++)
7476         {
7477           if (AOP_TYPE (right) == AOP_LIT)
7478             {
7479               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7480               if (bytelit == 0)
7481                 {
7482                   /* dummy read of volatile operand */
7483                   if (isOperandVolatile (left, FALSE))
7484                     MOVA (aopGet (left, offset, FALSE, FALSE));
7485                   else
7486                     continue;
7487                 }
7488               else if (IS_AOP_PREG (left))
7489                 {
7490                   MOVA (aopGet (left, offset, FALSE, TRUE));
7491                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7492                   aopPut (result, "a", offset);
7493                 }
7494               else
7495                 {
7496                   emitcode ("xrl", "%s,%s",
7497                             aopGet (left, offset, FALSE, TRUE),
7498                             aopGet (right, offset, FALSE, FALSE));
7499                 }
7500             }
7501           else
7502             {
7503               if (AOP_TYPE (left) == AOP_ACC)
7504                 {
7505                   if (offset)
7506                     emitcode("mov", "a,b");
7507                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7508                 }
7509               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7510                 {
7511                   MOVB (aopGet (left, offset, FALSE, FALSE));
7512                   MOVA (aopGet (right, offset, FALSE, FALSE));
7513                   emitcode ("xrl", "a,b");
7514                   aopPut (result, "a", offset);
7515                 }
7516               else if (aopGetUsesAcc (left, offset))
7517                 {
7518                   MOVA (aopGet (left, offset, FALSE, FALSE));
7519                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7520                   aopPut (result, "a", offset);
7521                 }
7522               else
7523                 {
7524                   MOVA (aopGet (right, offset, FALSE, FALSE));
7525                   if (IS_AOP_PREG (left))
7526                     {
7527                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7528                       aopPut (result, "a", offset);
7529                     }
7530                   else
7531                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7532                 }
7533             }
7534         }
7535     }
7536   else
7537     {
7538       // left & result in different registers
7539       if (AOP_TYPE (result) == AOP_CRY)
7540         {
7541           // result = bit
7542           // if(size), result in bit
7543           // if(!size && ifx), conditional oper: if(left ^ right)
7544           symbol *tlbl = newiTempLabel (NULL);
7545           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7546
7547           if (size)
7548             emitcode ("setb", "c");
7549           while (sizer--)
7550             {
7551               if ((AOP_TYPE (right) == AOP_LIT) &&
7552                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7553                 {
7554                   MOVA (aopGet (left, offset, FALSE, FALSE));
7555                 }
7556               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7557                   && AOP_TYPE(left)==AOP_ACC)
7558                 {
7559                   if (offset)
7560                     emitcode("mov", "a,b");
7561                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7562                 }
7563               else if (AOP_TYPE(left)==AOP_ACC)
7564                 {
7565                   if (!offset)
7566                     {
7567                       bool pushedB = pushB ();
7568                       emitcode("mov", "b,a");
7569                       MOVA (aopGet (right, offset, FALSE, FALSE));
7570                       emitcode("xrl", "a,b");
7571                       popB (pushedB);
7572                     }
7573                   else
7574                     {
7575                       MOVA (aopGet (right, offset, FALSE, FALSE));
7576                       emitcode("xrl", "a,b");
7577                     }
7578                 }
7579               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7580                 {
7581                   MOVB (aopGet (left, offset, FALSE, FALSE));
7582                   MOVA (aopGet (right, offset, FALSE, FALSE));
7583                   emitcode ("xrl", "a,b");
7584                 }
7585               else if (aopGetUsesAcc (left, offset))
7586                 {
7587                   MOVA (aopGet (left, offset, FALSE, FALSE));
7588                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7589                 }
7590               else
7591                 {
7592                   MOVA (aopGet (right, offset, FALSE, FALSE));
7593                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7594                 }
7595
7596               emitcode ("jnz", "%05d$", tlbl->key + 100);
7597               offset++;
7598             }
7599           if (size)
7600             {
7601               CLRC;
7602               emitLabel (tlbl);
7603               outBitC (result);
7604             }
7605           else if (ifx)
7606             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7607         }
7608       else
7609         {
7610           for (; (size--); offset++)
7611             {
7612               // normal case
7613               // result = left ^ right
7614               if (AOP_TYPE (right) == AOP_LIT)
7615                 {
7616                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7617                   if (bytelit == 0)
7618                     {
7619                       aopPut (result,
7620                               aopGet (left, offset, FALSE, FALSE),
7621                               offset);
7622                       continue;
7623                     }
7624                 }
7625               // faster than result <- left, xrl result,right
7626               // and better if result is SFR
7627               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7628                   && AOP_TYPE(left)==AOP_ACC)
7629                 {
7630                   if (offset)
7631                     emitcode("mov", "a,b");
7632                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7633                 }
7634               else if (AOP_TYPE(left)==AOP_ACC)
7635                 {
7636                   if (!offset)
7637                     {
7638                       bool pushedB = pushB ();
7639                       emitcode("mov", "b,a");
7640                       MOVA (aopGet (right, offset, FALSE, FALSE));
7641                       emitcode("xrl", "a,b");
7642                       popB (pushedB);
7643                     }
7644                   else
7645                     {
7646                       MOVA (aopGet (right, offset, FALSE, FALSE));
7647                       emitcode("xrl", "a,b");
7648                     }
7649                 }
7650               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7651                 {
7652                   MOVB (aopGet (left, offset, FALSE, FALSE));
7653                   MOVA (aopGet (right, offset, FALSE, FALSE));
7654                   emitcode ("xrl", "a,b");
7655                 }
7656               else if (aopGetUsesAcc (left, offset))
7657                 {
7658                   MOVA (aopGet (left, offset, FALSE, FALSE));
7659                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7660                 }
7661               else
7662                 {
7663                   MOVA (aopGet (right, offset, FALSE, FALSE));
7664                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7665                 }
7666               aopPut (result, "a", offset);
7667             }
7668         }
7669     }
7670
7671 release:
7672   freeAsmop (result, NULL, ic, TRUE);
7673   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7674   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7675 }
7676
7677 /*-----------------------------------------------------------------*/
7678 /* genInline - write the inline code out                           */
7679 /*-----------------------------------------------------------------*/
7680 static void
7681 genInline (iCode * ic)
7682 {
7683   char *buffer, *bp, *bp1;
7684   bool inComment = FALSE;
7685
7686   D (emitcode (";", "genInline"));
7687
7688   _G.inLine += (!options.asmpeep);
7689
7690   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7691
7692   /* emit each line as a code */
7693   while (*bp)
7694     {
7695       switch (*bp)
7696         {
7697         case ';':
7698           inComment = TRUE;
7699           ++bp;
7700           break;
7701
7702         case '\n':
7703           inComment = FALSE;
7704           *bp++ = '\0';
7705           emitcode (bp1, "");
7706           bp1 = bp;
7707           break;
7708
7709         default:
7710           /* Add \n for labels, not dirs such as c:\mydir */
7711           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7712             {
7713               ++bp;
7714               *bp = '\0';
7715               ++bp;
7716               emitcode (bp1, "");
7717               bp1 = bp;
7718             }
7719           else
7720             ++bp;
7721           break;
7722         }
7723     }
7724   if (bp1 != bp)
7725     emitcode (bp1, "");
7726
7727   Safe_free (buffer);
7728
7729   _G.inLine -= (!options.asmpeep);
7730 }
7731
7732 /*-----------------------------------------------------------------*/
7733 /* genRRC - rotate right with carry                                */
7734 /*-----------------------------------------------------------------*/
7735 static void
7736 genRRC (iCode * ic)
7737 {
7738   operand *left, *result;
7739   int size, offset;
7740   char *l;
7741
7742   D (emitcode (";", "genRRC"));
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 = size - 1;
7753   if (size == 1) { /* special case for 1 byte */
7754       l = aopGet (left, offset, FALSE, FALSE);
7755       MOVA (l);
7756       emitcode ("rr", "a");
7757       goto release;
7758   }
7759   /* no need to clear carry, bit7 will be written later */
7760   while (size--)
7761     {
7762       l = aopGet (left, offset, FALSE, FALSE);
7763       MOVA (l);
7764       emitcode ("rrc", "a");
7765       if (AOP_SIZE (result) > 1)
7766         aopPut (result, "a", offset--);
7767     }
7768   /* now we need to put the carry into the
7769      highest order byte of the result */
7770   if (AOP_SIZE (result) > 1)
7771     {
7772       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7773       MOVA (l);
7774     }
7775   emitcode ("mov", "acc.7,c");
7776  release:
7777   aopPut (result, "a", AOP_SIZE (result) - 1);
7778   freeAsmop (result, NULL, ic, TRUE);
7779   freeAsmop (left, NULL, ic, TRUE);
7780 }
7781
7782 /*-----------------------------------------------------------------*/
7783 /* genRLC - generate code for rotate left with carry               */
7784 /*-----------------------------------------------------------------*/
7785 static void
7786 genRLC (iCode * ic)
7787 {
7788   operand *left, *result;
7789   int size, offset;
7790   char *l;
7791
7792   D (emitcode (";", "genRLC"));
7793
7794   /* rotate right with carry */
7795   left = IC_LEFT (ic);
7796   result = IC_RESULT (ic);
7797   aopOp (left, ic, FALSE);
7798   aopOp (result, ic, FALSE);
7799
7800   /* move it to the result */
7801   size = AOP_SIZE (result);
7802   offset = 0;
7803   if (size--)
7804     {
7805       l = aopGet (left, offset, FALSE, FALSE);
7806       MOVA (l);
7807       if (size == 0) { /* special case for 1 byte */
7808               emitcode("rl","a");
7809               goto release;
7810       }
7811       emitcode("rlc","a"); /* bit0 will be written later */
7812       if (AOP_SIZE (result) > 1)
7813         {
7814           aopPut (result, "a", offset++);
7815         }
7816
7817       while (size--)
7818         {
7819           l = aopGet (left, offset, FALSE, FALSE);
7820           MOVA (l);
7821           emitcode ("rlc", "a");
7822           if (AOP_SIZE (result) > 1)
7823             aopPut (result, "a", offset++);
7824         }
7825     }
7826   /* now we need to put the carry into the
7827      highest order byte of the result */
7828   if (AOP_SIZE (result) > 1)
7829     {
7830       l = aopGet (result, 0, FALSE, FALSE);
7831       MOVA (l);
7832     }
7833   emitcode ("mov", "acc.0,c");
7834  release:
7835   aopPut (result, "a", 0);
7836   freeAsmop (result, NULL, ic, TRUE);
7837   freeAsmop (left, NULL, ic, TRUE);
7838 }
7839
7840 /*-----------------------------------------------------------------*/
7841 /* genGetHbit - generates code get highest order bit               */
7842 /*-----------------------------------------------------------------*/
7843 static void
7844 genGetHbit (iCode * ic)
7845 {
7846   operand *left, *result;
7847
7848   D (emitcode (";", "genGetHbit"));
7849
7850   left = IC_LEFT (ic);
7851   result = IC_RESULT (ic);
7852   aopOp (left, ic, FALSE);
7853   aopOp (result, ic, FALSE);
7854
7855   /* get the highest order byte into a */
7856   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7857   if (AOP_TYPE (result) == AOP_CRY)
7858     {
7859       emitcode ("rlc", "a");
7860       outBitC (result);
7861     }
7862   else
7863     {
7864       emitcode ("rl", "a");
7865       emitcode ("anl", "a,#0x01");
7866       outAcc (result);
7867     }
7868
7869   freeAsmop (result, NULL, ic, TRUE);
7870   freeAsmop (left, NULL, ic, TRUE);
7871 }
7872
7873 /*-----------------------------------------------------------------*/
7874 /* genGetAbit - generates code get a single bit                    */
7875 /*-----------------------------------------------------------------*/
7876 static void
7877 genGetAbit (iCode * ic)
7878 {
7879   operand *left, *right, *result;
7880   int shCount;
7881
7882   D (emitcode (";", "genGetAbit"));
7883
7884   left = IC_LEFT (ic);
7885   right = IC_RIGHT (ic);
7886   result = IC_RESULT (ic);
7887   aopOp (left, ic, FALSE);
7888   aopOp (right, ic, FALSE);
7889   aopOp (result, ic, FALSE);
7890
7891   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7892
7893   /* get the needed byte into a */
7894   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7895   shCount %= 8;
7896   if (AOP_TYPE (result) == AOP_CRY)
7897     {
7898       if ((shCount) == 7)
7899           emitcode ("rlc", "a");
7900       else if ((shCount) == 0)
7901           emitcode ("rrc", "a");
7902       else
7903           emitcode ("mov", "c,acc[%d]", shCount);
7904       outBitC (result);
7905     }
7906   else
7907     {
7908       switch (shCount)
7909         {
7910         case 2:
7911           emitcode ("rr", "a");
7912           //fallthrough
7913         case 1:
7914           emitcode ("rr", "a");
7915           //fallthrough
7916         case 0:
7917           emitcode ("anl", "a,#0x01");
7918           break;
7919         case 3:
7920         case 5:
7921           emitcode ("mov", "c,acc[%d]", shCount);
7922           emitcode ("clr", "a");
7923           emitcode ("rlc", "a");
7924           break;
7925         case 4:
7926           emitcode ("swap", "a");
7927           emitcode ("anl", "a,#0x01");
7928           break;
7929         case 6:
7930           emitcode ("rl", "a");
7931           //fallthrough
7932         case 7:
7933           emitcode ("rl", "a");
7934           emitcode ("anl", "a,#0x01");
7935           break;
7936         }
7937       outAcc (result);
7938     }
7939
7940   freeAsmop (result, NULL, ic, TRUE);
7941   freeAsmop (right, NULL, ic, TRUE);
7942   freeAsmop (left, NULL, ic, TRUE);
7943 }
7944
7945 /*-----------------------------------------------------------------*/
7946 /* genGetByte - generates code get a single byte                   */
7947 /*-----------------------------------------------------------------*/
7948 static void
7949 genGetByte (iCode * ic)
7950 {
7951   operand *left, *right, *result;
7952   int offset;
7953
7954   D (emitcode (";", "genGetByte"));
7955
7956   left = IC_LEFT (ic);
7957   right = IC_RIGHT (ic);
7958   result = IC_RESULT (ic);
7959   aopOp (left, ic, FALSE);
7960   aopOp (right, ic, FALSE);
7961   aopOp (result, ic, FALSE);
7962
7963   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7964   aopPut (result,
7965           aopGet (left, offset, FALSE, FALSE),
7966           0);
7967
7968   freeAsmop (result, NULL, ic, TRUE);
7969   freeAsmop (right, NULL, ic, TRUE);
7970   freeAsmop (left, NULL, ic, TRUE);
7971 }
7972
7973 /*-----------------------------------------------------------------*/
7974 /* genGetWord - generates code get two bytes                       */
7975 /*-----------------------------------------------------------------*/
7976 static void
7977 genGetWord (iCode * ic)
7978 {
7979   operand *left, *right, *result;
7980   int offset;
7981
7982   D (emitcode (";", "genGetWord"));
7983
7984   left = IC_LEFT (ic);
7985   right = IC_RIGHT (ic);
7986   result = IC_RESULT (ic);
7987   aopOp (left, ic, FALSE);
7988   aopOp (right, ic, FALSE);
7989   aopOp (result, ic, FALSE);
7990
7991   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7992   aopPut (result,
7993           aopGet (left, offset, FALSE, FALSE),
7994           0);
7995   aopPut (result,
7996           aopGet (left, offset+1, FALSE, FALSE),
7997           1);
7998
7999   freeAsmop (result, NULL, ic, TRUE);
8000   freeAsmop (right, NULL, ic, TRUE);
8001   freeAsmop (left, NULL, ic, TRUE);
8002 }
8003
8004 /*-----------------------------------------------------------------*/
8005 /* genSwap - generates code to swap nibbles or bytes               */
8006 /*-----------------------------------------------------------------*/
8007 static void
8008 genSwap (iCode * ic)
8009 {
8010   operand *left, *result;
8011
8012   D(emitcode (";", "genSwap"));
8013
8014   left = IC_LEFT (ic);
8015   result = IC_RESULT (ic);
8016   aopOp (left, ic, FALSE);
8017   aopOp (result, ic, FALSE);
8018
8019   switch (AOP_SIZE (left))
8020     {
8021     case 1: /* swap nibbles in byte */
8022       MOVA (aopGet (left, 0, FALSE, FALSE));
8023       emitcode ("swap", "a");
8024       aopPut (result, "a", 0);
8025       break;
8026     case 2: /* swap bytes in word */
8027       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8028         {
8029           MOVA (aopGet (left, 0, FALSE, FALSE));
8030           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8031           aopPut (result, "a", 1);
8032         }
8033       else if (operandsEqu (left, result))
8034         {
8035           char * reg = "a";
8036           bool pushedB = FALSE, leftInB = FALSE;
8037
8038           MOVA (aopGet (left, 0, FALSE, FALSE));
8039           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8040             {
8041               pushedB = pushB ();
8042               emitcode ("mov", "b,a");
8043               reg = "b";
8044               leftInB = TRUE;
8045             }
8046           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8047           aopPut (result, reg, 1);
8048
8049           if (leftInB)
8050             popB (pushedB);
8051         }
8052       else
8053         {
8054           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8055           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8056         }
8057       break;
8058     default:
8059       wassertl(FALSE, "unsupported SWAP operand size");
8060     }
8061
8062   freeAsmop (result, NULL, ic, TRUE);
8063   freeAsmop (left, NULL, ic, TRUE);
8064 }
8065
8066 /*-----------------------------------------------------------------*/
8067 /* AccRol - rotate left accumulator by known count                 */
8068 /*-----------------------------------------------------------------*/
8069 static void
8070 AccRol (int shCount)
8071 {
8072   shCount &= 0x0007;            // shCount : 0..7
8073
8074   switch (shCount)
8075     {
8076     case 0:
8077       break;
8078     case 1:
8079       emitcode ("rl", "a");
8080       break;
8081     case 2:
8082       emitcode ("rl", "a");
8083       emitcode ("rl", "a");
8084       break;
8085     case 3:
8086       emitcode ("swap", "a");
8087       emitcode ("rr", "a");
8088       break;
8089     case 4:
8090       emitcode ("swap", "a");
8091       break;
8092     case 5:
8093       emitcode ("swap", "a");
8094       emitcode ("rl", "a");
8095       break;
8096     case 6:
8097       emitcode ("rr", "a");
8098       emitcode ("rr", "a");
8099       break;
8100     case 7:
8101       emitcode ("rr", "a");
8102       break;
8103     }
8104 }
8105
8106 /*-----------------------------------------------------------------*/
8107 /* AccLsh - left shift accumulator by known count                  */
8108 /*-----------------------------------------------------------------*/
8109 static void
8110 AccLsh (int shCount)
8111 {
8112   if (shCount != 0)
8113     {
8114       if (shCount == 1)
8115         emitcode ("add", "a,acc");
8116       else if (shCount == 2)
8117         {
8118           emitcode ("add", "a,acc");
8119           emitcode ("add", "a,acc");
8120         }
8121       else
8122         {
8123           /* rotate left accumulator */
8124           AccRol (shCount);
8125           /* and kill the lower order bits */
8126           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8127         }
8128     }
8129 }
8130
8131 /*-----------------------------------------------------------------*/
8132 /* AccRsh - right shift accumulator by known count                 */
8133 /*-----------------------------------------------------------------*/
8134 static void
8135 AccRsh (int shCount)
8136 {
8137   if (shCount != 0)
8138     {
8139       if (shCount == 1)
8140         {
8141           CLRC;
8142           emitcode ("rrc", "a");
8143         }
8144       else
8145         {
8146           /* rotate right accumulator */
8147           AccRol (8 - shCount);
8148           /* and kill the higher order bits */
8149           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8150         }
8151     }
8152 }
8153
8154 /*-----------------------------------------------------------------*/
8155 /* AccSRsh - signed right shift accumulator by known count                 */
8156 /*-----------------------------------------------------------------*/
8157 static void
8158 AccSRsh (int shCount)
8159 {
8160   symbol *tlbl;
8161   if (shCount != 0)
8162     {
8163       if (shCount == 1)
8164         {
8165           emitcode ("mov", "c,acc.7");
8166           emitcode ("rrc", "a");
8167         }
8168       else if (shCount == 2)
8169         {
8170           emitcode ("mov", "c,acc.7");
8171           emitcode ("rrc", "a");
8172           emitcode ("mov", "c,acc.7");
8173           emitcode ("rrc", "a");
8174         }
8175       else
8176         {
8177           tlbl = newiTempLabel (NULL);
8178           /* rotate right accumulator */
8179           AccRol (8 - shCount);
8180           /* and kill the higher order bits */
8181           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8182           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8183           emitcode ("orl", "a,#0x%02x",
8184                     (unsigned char) ~SRMask[shCount]);
8185           emitLabel (tlbl);
8186         }
8187     }
8188 }
8189
8190 /*-----------------------------------------------------------------*/
8191 /* shiftR1Left2Result - shift right one byte from left to result   */
8192 /*-----------------------------------------------------------------*/
8193 static void
8194 shiftR1Left2Result (operand * left, int offl,
8195                     operand * result, int offr,
8196                     int shCount, int sign)
8197 {
8198   MOVA (aopGet (left, offl, FALSE, FALSE));
8199   /* shift right accumulator */
8200   if (sign)
8201     AccSRsh (shCount);
8202   else
8203     AccRsh (shCount);
8204   aopPut (result, "a", offr);
8205 }
8206
8207 /*-----------------------------------------------------------------*/
8208 /* shiftL1Left2Result - shift left one byte from left to result    */
8209 /*-----------------------------------------------------------------*/
8210 static void
8211 shiftL1Left2Result (operand * left, int offl,
8212                     operand * result, int offr, int shCount)
8213 {
8214   char *l;
8215   l = aopGet (left, offl, FALSE, FALSE);
8216   MOVA (l);
8217   /* shift left accumulator */
8218   AccLsh (shCount);
8219   aopPut (result, "a", offr);
8220 }
8221
8222 /*-----------------------------------------------------------------*/
8223 /* movLeft2Result - move byte from left to result                  */
8224 /*-----------------------------------------------------------------*/
8225 static void
8226 movLeft2Result (operand * left, int offl,
8227                 operand * result, int offr, int sign)
8228 {
8229   char *l;
8230   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8231     {
8232       l = aopGet (left, offl, FALSE, FALSE);
8233
8234       if (*l == '@' && (IS_AOP_PREG (result)))
8235         {
8236           emitcode ("mov", "a,%s", l);
8237           aopPut (result, "a", offr);
8238         }
8239       else
8240         {
8241           if (!sign)
8242             {
8243               aopPut (result, l, offr);
8244             }
8245           else
8246             {
8247               /* MSB sign in acc.7 ! */
8248               if (getDataSize (left) == offl + 1)
8249                 {
8250                   MOVA (l);
8251                   aopPut (result, "a", offr);
8252                 }
8253             }
8254         }
8255     }
8256 }
8257
8258 /*-----------------------------------------------------------------*/
8259 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8260 /*-----------------------------------------------------------------*/
8261 static void
8262 AccAXRrl1 (char *x)
8263 {
8264   emitcode ("rrc", "a");
8265   emitcode ("xch", "a,%s", x);
8266   emitcode ("rrc", "a");
8267   emitcode ("xch", "a,%s", x);
8268 }
8269
8270 /*-----------------------------------------------------------------*/
8271 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8272 /*-----------------------------------------------------------------*/
8273 static void
8274 AccAXLrl1 (char *x)
8275 {
8276   emitcode ("xch", "a,%s", x);
8277   emitcode ("rlc", "a");
8278   emitcode ("xch", "a,%s", x);
8279   emitcode ("rlc", "a");
8280 }
8281
8282 /*-----------------------------------------------------------------*/
8283 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8284 /*-----------------------------------------------------------------*/
8285 static void
8286 AccAXLsh1 (char *x)
8287 {
8288   emitcode ("xch", "a,%s", x);
8289   emitcode ("add", "a,acc");
8290   emitcode ("xch", "a,%s", x);
8291   emitcode ("rlc", "a");
8292 }
8293
8294 /*-----------------------------------------------------------------*/
8295 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8296 /*-----------------------------------------------------------------*/
8297 static void
8298 AccAXLsh (char *x, int shCount)
8299 {
8300   switch (shCount)
8301     {
8302     case 0:
8303       break;
8304     case 1:
8305       AccAXLsh1 (x);
8306       break;
8307     case 2:
8308       AccAXLsh1 (x);
8309       AccAXLsh1 (x);
8310       break;
8311     case 3:
8312     case 4:
8313     case 5:                     // AAAAABBB:CCCCCDDD
8314
8315       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8316
8317       emitcode ("anl", "a,#0x%02x",
8318                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8319
8320       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8321
8322       AccRol (shCount);         // DDDCCCCC:BBB00000
8323
8324       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8325
8326       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8327
8328       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8329
8330       emitcode ("anl", "a,#0x%02x",
8331                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8332
8333       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8334
8335       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8336
8337       break;
8338     case 6:                     // AAAAAABB:CCCCCCDD
8339       emitcode ("anl", "a,#0x%02x",
8340                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8341       emitcode ("mov", "c,acc.0");      // c = B
8342       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8343 #if 0 // REMOVE ME
8344       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8345       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8346 #else
8347       emitcode("rrc","a");
8348       emitcode("xch","a,%s", x);
8349       emitcode("rrc","a");
8350       emitcode("mov","c,acc.0"); //<< get correct bit
8351       emitcode("xch","a,%s", x);
8352
8353       emitcode("rrc","a");
8354       emitcode("xch","a,%s", x);
8355       emitcode("rrc","a");
8356       emitcode("xch","a,%s", x);
8357 #endif
8358       break;
8359     case 7:                     // a:x <<= 7
8360
8361       emitcode ("anl", "a,#0x%02x",
8362                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8363
8364       emitcode ("mov", "c,acc.0");      // c = B
8365
8366       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8367
8368       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8369
8370       break;
8371     default:
8372       break;
8373     }
8374 }
8375
8376 /*-----------------------------------------------------------------*/
8377 /* AccAXRsh - right shift a:x known count (0..7)                   */
8378 /*-----------------------------------------------------------------*/
8379 static void
8380 AccAXRsh (char *x, int shCount)
8381 {
8382   switch (shCount)
8383     {
8384     case 0:
8385       break;
8386     case 1:
8387       CLRC;
8388       AccAXRrl1 (x);            // 0->a:x
8389
8390       break;
8391     case 2:
8392       CLRC;
8393       AccAXRrl1 (x);            // 0->a:x
8394
8395       CLRC;
8396       AccAXRrl1 (x);            // 0->a:x
8397
8398       break;
8399     case 3:
8400     case 4:
8401     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8402
8403       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8404
8405       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8406
8407       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8408
8409       emitcode ("anl", "a,#0x%02x",
8410                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8411
8412       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8413
8414       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8415
8416       emitcode ("anl", "a,#0x%02x",
8417                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8418
8419       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8420
8421       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8422
8423       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8424
8425       break;
8426     case 6:                     // AABBBBBB:CCDDDDDD
8427
8428       emitcode ("mov", "c,acc.7");
8429       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8430
8431       emitcode ("mov", "c,acc.7");
8432       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8433
8434       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8435
8436       emitcode ("anl", "a,#0x%02x",
8437                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8438
8439       break;
8440     case 7:                     // ABBBBBBB:CDDDDDDD
8441
8442       emitcode ("mov", "c,acc.7");      // c = A
8443
8444       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8445
8446       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8447
8448       emitcode ("anl", "a,#0x%02x",
8449                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8450
8451       break;
8452     default:
8453       break;
8454     }
8455 }
8456
8457 /*-----------------------------------------------------------------*/
8458 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8459 /*-----------------------------------------------------------------*/
8460 static void
8461 AccAXRshS (char *x, int shCount)
8462 {
8463   symbol *tlbl;
8464   switch (shCount)
8465     {
8466     case 0:
8467       break;
8468     case 1:
8469       emitcode ("mov", "c,acc.7");
8470       AccAXRrl1 (x);            // s->a:x
8471
8472       break;
8473     case 2:
8474       emitcode ("mov", "c,acc.7");
8475       AccAXRrl1 (x);            // s->a:x
8476
8477       emitcode ("mov", "c,acc.7");
8478       AccAXRrl1 (x);            // s->a:x
8479
8480       break;
8481     case 3:
8482     case 4:
8483     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8484
8485       tlbl = newiTempLabel (NULL);
8486       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8487
8488       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8489
8490       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8491
8492       emitcode ("anl", "a,#0x%02x",
8493                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8494
8495       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8496
8497       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8498
8499       emitcode ("anl", "a,#0x%02x",
8500                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8501
8502       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8503
8504       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8505
8506       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8507
8508       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8509       emitcode ("orl", "a,#0x%02x",
8510                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8511
8512       emitLabel (tlbl);
8513       break;                    // SSSSAAAA:BBBCCCCC
8514
8515     case 6:                     // AABBBBBB:CCDDDDDD
8516
8517       tlbl = newiTempLabel (NULL);
8518       emitcode ("mov", "c,acc.7");
8519       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8520
8521       emitcode ("mov", "c,acc.7");
8522       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8523
8524       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8525
8526       emitcode ("anl", "a,#0x%02x",
8527                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8528
8529       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8530       emitcode ("orl", "a,#0x%02x",
8531                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8532
8533       emitLabel (tlbl);
8534       break;
8535     case 7:                     // ABBBBBBB:CDDDDDDD
8536
8537       tlbl = newiTempLabel (NULL);
8538       emitcode ("mov", "c,acc.7");      // c = A
8539
8540       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8541
8542       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8543
8544       emitcode ("anl", "a,#0x%02x",
8545                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8546
8547       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8548       emitcode ("orl", "a,#0x%02x",
8549                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8550
8551       emitLabel (tlbl);
8552       break;
8553     default:
8554       break;
8555     }
8556 }
8557
8558 /*-----------------------------------------------------------------*/
8559 /* shiftL2Left2Result - shift left two bytes from left to result   */
8560 /*-----------------------------------------------------------------*/
8561 static void
8562 shiftL2Left2Result (operand * left, int offl,
8563                     operand * result, int offr, int shCount)
8564 {
8565   char * x;
8566   bool pushedB = FALSE;
8567   bool usedB = FALSE;
8568
8569   if (sameRegs (AOP (result), AOP (left)) &&
8570       ((offl + MSB16) == offr))
8571     {
8572       /* don't crash result[offr] */
8573       MOVA (aopGet (left, offl, FALSE, FALSE));
8574       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8575       usedB = !strncmp(x, "b", 1);
8576     }
8577   else if (aopGetUsesAcc (result, offr))
8578     {
8579       movLeft2Result (left, offl, result, offr, 0);
8580       pushedB = pushB ();
8581       usedB = TRUE;
8582       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8583       MOVA (aopGet (result, offr, FALSE, FALSE));
8584       emitcode ("xch", "a,b");
8585       x = "b";
8586     }
8587   else
8588     {
8589       movLeft2Result (left, offl, result, offr, 0);
8590       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8591       x = aopGet (result, offr, FALSE, FALSE);
8592     }
8593   /* ax << shCount (x = lsb(result)) */
8594   AccAXLsh (x, shCount);
8595   if (usedB)
8596     {
8597       emitcode ("xch", "a,b");
8598       aopPut (result, "a", offr);
8599       aopPut (result, "b", offr + MSB16);
8600       popB (pushedB);
8601     }
8602   else
8603     {
8604       aopPut (result, "a", offr + MSB16);
8605     }
8606 }
8607
8608
8609 /*-----------------------------------------------------------------*/
8610 /* shiftR2Left2Result - shift right two bytes from left to result  */
8611 /*-----------------------------------------------------------------*/
8612 static void
8613 shiftR2Left2Result (operand * left, int offl,
8614                     operand * result, int offr,
8615                     int shCount, int sign)
8616 {
8617   char * x;
8618   bool pushedB = FALSE;
8619   bool usedB = FALSE;
8620
8621   if (sameRegs (AOP (result), AOP (left)) &&
8622       ((offl + MSB16) == offr))
8623     {
8624       /* don't crash result[offr] */
8625       MOVA (aopGet (left, offl, FALSE, FALSE));
8626       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8627       usedB = !strncmp(x, "b", 1);
8628     }
8629   else if (aopGetUsesAcc (result, offr))
8630     {
8631       movLeft2Result (left, offl, result, offr, 0);
8632       pushedB = pushB ();
8633       usedB = TRUE;
8634       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8635       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8636       x = "b";
8637     }
8638   else
8639     {
8640       movLeft2Result (left, offl, result, offr, 0);
8641       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8642       x = aopGet (result, offr, FALSE, FALSE);
8643     }
8644   /* a:x >> shCount (x = lsb(result)) */
8645   if (sign)
8646     AccAXRshS (x, shCount);
8647   else
8648     AccAXRsh (x, shCount);
8649   if (usedB)
8650     {
8651       emitcode ("xch", "a,b");
8652       aopPut (result, "a", offr);
8653       emitcode ("xch", "a,b");
8654       popB (pushedB);
8655     }
8656   if (getDataSize (result) > 1)
8657     aopPut (result, "a", offr + MSB16);
8658 }
8659
8660 /*-----------------------------------------------------------------*/
8661 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8662 /*-----------------------------------------------------------------*/
8663 static void
8664 shiftLLeftOrResult (operand * left, int offl,
8665                     operand * result, int offr, int shCount)
8666 {
8667   MOVA (aopGet (left, offl, FALSE, FALSE));
8668   /* shift left accumulator */
8669   AccLsh (shCount);
8670   /* or with result */
8671   if (aopGetUsesAcc (result, offr))
8672     {
8673       emitcode ("xch", "a,b");
8674       MOVA (aopGet (result, offr, FALSE, FALSE));
8675       emitcode ("orl", "a,b");
8676     }
8677   else
8678     {
8679       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8680     }
8681   /* back to result */
8682   aopPut (result, "a", offr);
8683 }
8684
8685 /*-----------------------------------------------------------------*/
8686 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8687 /*-----------------------------------------------------------------*/
8688 static void
8689 shiftRLeftOrResult (operand * left, int offl,
8690                     operand * result, int offr, int shCount)
8691 {
8692   MOVA (aopGet (left, offl, FALSE, FALSE));
8693   /* shift right accumulator */
8694   AccRsh (shCount);
8695   /* or with result */
8696   if (aopGetUsesAcc(result, offr))
8697     {
8698       emitcode ("xch", "a,b");
8699       MOVA (aopGet (result, offr, FALSE, FALSE));
8700       emitcode ("orl", "a,b");
8701     }
8702   else
8703     {
8704       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8705     }
8706   /* back to result */
8707   aopPut (result, "a", offr);
8708 }
8709
8710 /*-----------------------------------------------------------------*/
8711 /* genlshOne - left shift a one byte quantity by known count       */
8712 /*-----------------------------------------------------------------*/
8713 static void
8714 genlshOne (operand * result, operand * left, int shCount)
8715 {
8716   D (emitcode (";", "genlshOne"));
8717
8718   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8719 }
8720
8721 /*-----------------------------------------------------------------*/
8722 /* genlshTwo - left shift two bytes by known amount != 0           */
8723 /*-----------------------------------------------------------------*/
8724 static void
8725 genlshTwo (operand * result, operand * left, int shCount)
8726 {
8727   int size;
8728
8729   D (emitcode (";", "genlshTwo"));
8730
8731   size = getDataSize (result);
8732
8733   /* if shCount >= 8 */
8734   if (shCount >= 8)
8735     {
8736       shCount -= 8;
8737
8738       if (size > 1)
8739         {
8740           if (shCount)
8741             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8742           else
8743             movLeft2Result (left, LSB, result, MSB16, 0);
8744         }
8745       aopPut (result, zero, LSB);
8746     }
8747
8748   /*  1 <= shCount <= 7 */
8749   else
8750     {
8751       if (size == 1)
8752         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8753       else
8754         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8755     }
8756 }
8757
8758 /*-----------------------------------------------------------------*/
8759 /* shiftLLong - shift left one long from left to result            */
8760 /* offl = LSB or MSB16                                             */
8761 /*-----------------------------------------------------------------*/
8762 static void
8763 shiftLLong (operand * left, operand * result, int offr)
8764 {
8765   char *l;
8766   int size = AOP_SIZE (result);
8767
8768   if (size >= LSB + offr)
8769     {
8770       l = aopGet (left, LSB, FALSE, FALSE);
8771       MOVA (l);
8772       emitcode ("add", "a,acc");
8773       if (sameRegs (AOP (left), AOP (result)) &&
8774           size >= MSB16 + offr && offr != LSB)
8775         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8776       else
8777         aopPut (result, "a", LSB + offr);
8778     }
8779
8780   if (size >= MSB16 + offr)
8781     {
8782       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8783         {
8784           l = aopGet (left, MSB16, FALSE, FALSE);
8785           MOVA (l);
8786         }
8787       emitcode ("rlc", "a");
8788       if (sameRegs (AOP (left), AOP (result)) &&
8789           size >= MSB24 + offr && offr != LSB)
8790         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8791       else
8792         aopPut (result, "a", MSB16 + offr);
8793     }
8794
8795   if (size >= MSB24 + offr)
8796     {
8797       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8798         {
8799           l = aopGet (left, MSB24, FALSE, FALSE);
8800           MOVA (l);
8801         }
8802       emitcode ("rlc", "a");
8803       if (sameRegs (AOP (left), AOP (result)) &&
8804           size >= MSB32 + offr && offr != LSB)
8805         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8806       else
8807         aopPut (result, "a", MSB24 + offr);
8808     }
8809
8810   if (size > MSB32 + offr)
8811     {
8812       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8813         {
8814           l = aopGet (left, MSB32, FALSE, FALSE);
8815           MOVA (l);
8816         }
8817       emitcode ("rlc", "a");
8818       aopPut (result, "a", MSB32 + offr);
8819     }
8820   if (offr != LSB)
8821     aopPut (result, zero, LSB);
8822 }
8823
8824 /*-----------------------------------------------------------------*/
8825 /* genlshFour - shift four byte by a known amount != 0             */
8826 /*-----------------------------------------------------------------*/
8827 static void
8828 genlshFour (operand * result, operand * left, int shCount)
8829 {
8830   int size;
8831
8832   D (emitcode (";", "genlshFour"));
8833
8834   size = AOP_SIZE (result);
8835
8836   /* if shifting more that 3 bytes */
8837   if (shCount >= 24)
8838     {
8839       shCount -= 24;
8840       if (shCount)
8841         /* lowest order of left goes to the highest
8842            order of the destination */
8843         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8844       else
8845         movLeft2Result (left, LSB, result, MSB32, 0);
8846       aopPut (result, zero, LSB);
8847       aopPut (result, zero, MSB16);
8848       aopPut (result, zero, MSB24);
8849       return;
8850     }
8851
8852   /* more than two bytes */
8853   else if (shCount >= 16)
8854     {
8855       /* lower order two bytes goes to higher order two bytes */
8856       shCount -= 16;
8857       /* if some more remaining */
8858       if (shCount)
8859         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8860       else
8861         {
8862           movLeft2Result (left, MSB16, result, MSB32, 0);
8863           movLeft2Result (left, LSB, result, MSB24, 0);
8864         }
8865       aopPut (result, zero, MSB16);
8866       aopPut (result, zero, LSB);
8867       return;
8868     }
8869
8870   /* if more than 1 byte */
8871   else if (shCount >= 8)
8872     {
8873       /* lower order three bytes goes to higher order  three bytes */
8874       shCount -= 8;
8875       if (size == 2)
8876         {
8877           if (shCount)
8878             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8879           else
8880             movLeft2Result (left, LSB, result, MSB16, 0);
8881         }
8882       else
8883         {                       /* size = 4 */
8884           if (shCount == 0)
8885             {
8886               movLeft2Result (left, MSB24, result, MSB32, 0);
8887               movLeft2Result (left, MSB16, result, MSB24, 0);
8888               movLeft2Result (left, LSB, result, MSB16, 0);
8889               aopPut (result, zero, LSB);
8890             }
8891           else if (shCount == 1)
8892             shiftLLong (left, result, MSB16);
8893           else
8894             {
8895               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8896               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8897               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8898               aopPut (result, zero, LSB);
8899             }
8900         }
8901     }
8902
8903   /* 1 <= shCount <= 7 */
8904   else if (shCount <= 2)
8905     {
8906       shiftLLong (left, result, LSB);
8907       if (shCount == 2)
8908         shiftLLong (result, result, LSB);
8909     }
8910   /* 3 <= shCount <= 7, optimize */
8911   else
8912     {
8913       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8914       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8915       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8916     }
8917 }
8918
8919 /*-----------------------------------------------------------------*/
8920 /* genLeftShiftLiteral - left shifting by known count              */
8921 /*-----------------------------------------------------------------*/
8922 static void
8923 genLeftShiftLiteral (operand * left,
8924                      operand * right,
8925                      operand * result,
8926                      iCode * ic)
8927 {
8928   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8929   int size;
8930
8931   D (emitcode (";", "genLeftShiftLiteral"));
8932
8933   freeAsmop (right, NULL, ic, TRUE);
8934
8935   aopOp (left, ic, FALSE);
8936   aopOp (result, ic, FALSE);
8937
8938   size = getSize (operandType (result));
8939
8940 #if VIEW_SIZE
8941   emitcode ("; shift left ", "result %d, left %d", size,
8942             AOP_SIZE (left));
8943 #endif
8944
8945   /* I suppose that the left size >= result size */
8946   if (shCount == 0)
8947     {
8948       while (size--)
8949         {
8950           movLeft2Result (left, size, result, size, 0);
8951         }
8952     }
8953   else if (shCount >= (size * 8))
8954     {
8955       while (size--)
8956         {
8957           aopPut (result, zero, size);
8958         }
8959     }
8960   else
8961     {
8962       switch (size)
8963         {
8964         case 1:
8965           genlshOne (result, left, shCount);
8966           break;
8967
8968         case 2:
8969           genlshTwo (result, left, shCount);
8970           break;
8971
8972         case 4:
8973           genlshFour (result, left, shCount);
8974           break;
8975         default:
8976           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8977                   "*** ack! mystery literal shift!\n");
8978           break;
8979         }
8980     }
8981   freeAsmop (result, NULL, ic, TRUE);
8982   freeAsmop (left, NULL, ic, TRUE);
8983 }
8984
8985 /*-----------------------------------------------------------------*/
8986 /* genLeftShift - generates code for left shifting                 */
8987 /*-----------------------------------------------------------------*/
8988 static void
8989 genLeftShift (iCode * ic)
8990 {
8991   operand *left, *right, *result;
8992   int size, offset;
8993   char *l;
8994   symbol *tlbl, *tlbl1;
8995   bool pushedB;
8996
8997   D (emitcode (";", "genLeftShift"));
8998
8999   right = IC_RIGHT (ic);
9000   left = IC_LEFT (ic);
9001   result = IC_RESULT (ic);
9002
9003   aopOp (right, ic, FALSE);
9004
9005   /* if the shift count is known then do it
9006      as efficiently as possible */
9007   if (AOP_TYPE (right) == AOP_LIT)
9008     {
9009       genLeftShiftLiteral (left, right, result, ic);
9010       return;
9011     }
9012
9013   /* shift count is unknown then we have to form
9014      a loop get the loop count in B : Note: we take
9015      only the lower order byte since shifting
9016      more that 32 bits make no sense anyway, ( the
9017      largest size of an object can be only 32 bits ) */
9018
9019   pushedB = pushB ();
9020   MOVB (aopGet (right, 0, FALSE, FALSE));
9021   emitcode ("inc", "b");
9022   freeAsmop (right, NULL, ic, TRUE);
9023   aopOp (left, ic, FALSE);
9024   aopOp (result, ic, FALSE);
9025
9026   /* now move the left to the result if they are not the same */
9027   if (!sameRegs (AOP (left), AOP (result)) &&
9028       AOP_SIZE (result) > 1)
9029     {
9030
9031       size = AOP_SIZE (result);
9032       offset = 0;
9033       while (size--)
9034         {
9035           l = aopGet (left, offset, FALSE, TRUE);
9036           if (*l == '@' && (IS_AOP_PREG (result)))
9037             {
9038
9039               emitcode ("mov", "a,%s", l);
9040               aopPut (result, "a", offset);
9041             }
9042           else
9043             aopPut (result, l, offset);
9044           offset++;
9045         }
9046     }
9047
9048   tlbl = newiTempLabel (NULL);
9049   size = AOP_SIZE (result);
9050   offset = 0;
9051   tlbl1 = newiTempLabel (NULL);
9052
9053   /* if it is only one byte then */
9054   if (size == 1)
9055     {
9056       symbol *tlbl1 = newiTempLabel (NULL);
9057
9058       l = aopGet (left, 0, FALSE, FALSE);
9059       MOVA (l);
9060       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9061       emitLabel (tlbl);
9062       emitcode ("add", "a,acc");
9063       emitLabel (tlbl1);
9064       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9065       popB (pushedB);
9066       aopPut (result, "a", 0);
9067       goto release;
9068     }
9069
9070   reAdjustPreg (AOP (result));
9071
9072   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9073   emitLabel (tlbl);
9074   l = aopGet (result, offset, FALSE, FALSE);
9075   MOVA (l);
9076   emitcode ("add", "a,acc");
9077   aopPut (result, "a", offset++);
9078   while (--size)
9079     {
9080       l = aopGet (result, offset, FALSE, FALSE);
9081       MOVA (l);
9082       emitcode ("rlc", "a");
9083       aopPut (result, "a", offset++);
9084     }
9085   reAdjustPreg (AOP (result));
9086
9087   emitLabel (tlbl1);
9088   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9089   popB (pushedB);
9090 release:
9091   freeAsmop (result, NULL, ic, TRUE);
9092   freeAsmop (left, NULL, ic, TRUE);
9093 }
9094
9095 /*-----------------------------------------------------------------*/
9096 /* genrshOne - right shift a one byte quantity by known count      */
9097 /*-----------------------------------------------------------------*/
9098 static void
9099 genrshOne (operand * result, operand * left,
9100            int shCount, int sign)
9101 {
9102   D (emitcode (";", "genrshOne"));
9103
9104   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9105 }
9106
9107 /*-----------------------------------------------------------------*/
9108 /* genrshTwo - right shift two bytes by known amount != 0          */
9109 /*-----------------------------------------------------------------*/
9110 static void
9111 genrshTwo (operand * result, operand * left,
9112            int shCount, int sign)
9113 {
9114   D (emitcode (";", "genrshTwo"));
9115
9116   /* if shCount >= 8 */
9117   if (shCount >= 8)
9118     {
9119       shCount -= 8;
9120       if (shCount)
9121         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9122       else
9123         movLeft2Result (left, MSB16, result, LSB, sign);
9124       addSign (result, MSB16, sign);
9125     }
9126
9127   /*  1 <= shCount <= 7 */
9128   else
9129     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9130 }
9131
9132 /*-----------------------------------------------------------------*/
9133 /* shiftRLong - shift right one long from left to result           */
9134 /* offl = LSB or MSB16                                             */
9135 /*-----------------------------------------------------------------*/
9136 static void
9137 shiftRLong (operand * left, int offl,
9138             operand * result, int sign)
9139 {
9140   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9141
9142   if (overlapping && offl>1)
9143     {
9144       // we are in big trouble, but this shouldn't happen
9145       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9146     }
9147
9148   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9149
9150   if (offl==MSB16)
9151     {
9152       // shift is > 8
9153       if (sign)
9154         {
9155           emitcode ("rlc", "a");
9156           emitcode ("subb", "a,acc");
9157           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9158             {
9159               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9160             }
9161           else
9162             {
9163               aopPut (result, "a", MSB32);
9164               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9165             }
9166         }
9167       else
9168         {
9169           if (aopPutUsesAcc (result, zero, MSB32))
9170             {
9171               emitcode("xch", "a,b");
9172               aopPut (result, zero, MSB32);
9173               emitcode("xch", "a,b");
9174             }
9175           else
9176             {
9177               aopPut (result, zero, MSB32);
9178             }
9179         }
9180     }
9181
9182   if (!sign)
9183     {
9184       emitcode ("clr", "c");
9185     }
9186   else
9187     {
9188       emitcode ("mov", "c,acc.7");
9189     }
9190
9191   emitcode ("rrc", "a");
9192
9193   if (overlapping && offl==MSB16 &&
9194       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9195     {
9196       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9197     }
9198   else
9199     {
9200       aopPut (result, "a", MSB32 - offl);
9201       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9202     }
9203
9204   emitcode ("rrc", "a");
9205   if (overlapping && offl==MSB16 &&
9206       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9207     {
9208       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9209     }
9210   else
9211     {
9212       aopPut (result, "a", MSB24 - offl);
9213       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9214     }
9215
9216   emitcode ("rrc", "a");
9217   if (offl != LSB)
9218     {
9219       aopPut (result, "a", MSB16 - offl);
9220     }
9221   else
9222     {
9223       if (overlapping &&
9224           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9225         {
9226           xch_a_aopGet (left, LSB, FALSE, FALSE);
9227         }
9228       else
9229         {
9230           aopPut (result, "a", MSB16 - offl);
9231           MOVA (aopGet (left, LSB, FALSE, FALSE));
9232         }
9233       emitcode ("rrc", "a");
9234       aopPut (result, "a", LSB);
9235     }
9236 }
9237
9238 /*-----------------------------------------------------------------*/
9239 /* genrshFour - shift four byte by a known amount != 0             */
9240 /*-----------------------------------------------------------------*/
9241 static void
9242 genrshFour (operand * result, operand * left,
9243             int shCount, int sign)
9244 {
9245   D (emitcode (";", "genrshFour"));
9246
9247   /* if shifting more that 3 bytes */
9248   if (shCount >= 24)
9249     {
9250       shCount -= 24;
9251       if (shCount)
9252         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9253       else
9254         movLeft2Result (left, MSB32, result, LSB, sign);
9255       addSign (result, MSB16, sign);
9256     }
9257   else if (shCount >= 16)
9258     {
9259       shCount -= 16;
9260       if (shCount)
9261         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9262       else
9263         {
9264           movLeft2Result (left, MSB24, result, LSB, 0);
9265           movLeft2Result (left, MSB32, result, MSB16, sign);
9266         }
9267       addSign (result, MSB24, sign);
9268     }
9269   else if (shCount >= 8)
9270     {
9271       shCount -= 8;
9272       if (shCount == 1)
9273         {
9274           shiftRLong (left, MSB16, result, sign);
9275         }
9276       else if (shCount == 0)
9277         {
9278           movLeft2Result (left, MSB16, result, LSB, 0);
9279           movLeft2Result (left, MSB24, result, MSB16, 0);
9280           movLeft2Result (left, MSB32, result, MSB24, sign);
9281           addSign (result, MSB32, sign);
9282         }
9283       else
9284         {
9285           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9286           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9287           /* the last shift is signed */
9288           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9289           addSign (result, MSB32, sign);
9290         }
9291     }
9292   else
9293     {
9294       /* 1 <= shCount <= 7 */
9295       if (shCount <= 2)
9296         {
9297           shiftRLong (left, LSB, result, sign);
9298           if (shCount == 2)
9299             shiftRLong (result, LSB, result, sign);
9300         }
9301       else
9302         {
9303           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9304           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9305           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9306         }
9307     }
9308 }
9309
9310 /*-----------------------------------------------------------------*/
9311 /* genRightShiftLiteral - right shifting by known count            */
9312 /*-----------------------------------------------------------------*/
9313 static void
9314 genRightShiftLiteral (operand * left,
9315                       operand * right,
9316                       operand * result,
9317                       iCode * ic,
9318                       int sign)
9319 {
9320   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9321   int size;
9322
9323   D (emitcode (";", "genRightShiftLiteral"));
9324
9325   freeAsmop (right, NULL, ic, TRUE);
9326
9327   aopOp (left, ic, FALSE);
9328   aopOp (result, ic, FALSE);
9329
9330 #if VIEW_SIZE
9331   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9332             AOP_SIZE (left));
9333 #endif
9334
9335   size = getDataSize (left);
9336   /* test the LEFT size !!! */
9337
9338   /* I suppose that the left size >= result size */
9339   if (shCount == 0)
9340     {
9341       size = getDataSize (result);
9342       while (size--)
9343         movLeft2Result (left, size, result, size, 0);
9344     }
9345
9346   else if (shCount >= (size * 8))
9347     {
9348       if (sign)
9349         {
9350           /* get sign in acc.7 */
9351           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9352         }
9353       addSign (result, LSB, sign);
9354     }
9355   else
9356     {
9357       switch (size)
9358         {
9359         case 1:
9360           genrshOne (result, left, shCount, sign);
9361           break;
9362
9363         case 2:
9364           genrshTwo (result, left, shCount, sign);
9365           break;
9366
9367         case 4:
9368           genrshFour (result, left, shCount, sign);
9369           break;
9370         default:
9371           break;
9372         }
9373     }
9374   freeAsmop (result, NULL, ic, TRUE);
9375   freeAsmop (left, NULL, ic, TRUE);
9376 }
9377
9378 /*-----------------------------------------------------------------*/
9379 /* genSignedRightShift - right shift of signed number              */
9380 /*-----------------------------------------------------------------*/
9381 static void
9382 genSignedRightShift (iCode * ic)
9383 {
9384   operand *right, *left, *result;
9385   int size, offset;
9386   char *l;
9387   symbol *tlbl, *tlbl1;
9388   bool pushedB;
9389
9390   D (emitcode (";", "genSignedRightShift"));
9391
9392   /* we do it the hard way put the shift count in b
9393      and loop thru preserving the sign */
9394
9395   right = IC_RIGHT (ic);
9396   left = IC_LEFT (ic);
9397   result = IC_RESULT (ic);
9398
9399   aopOp (right, ic, FALSE);
9400
9401
9402   if (AOP_TYPE (right) == AOP_LIT)
9403     {
9404       genRightShiftLiteral (left, right, result, ic, 1);
9405       return;
9406     }
9407   /* shift count is unknown then we have to form
9408      a loop get the loop count in B : Note: we take
9409      only the lower order byte since shifting
9410      more that 32 bits make no sense anyway, ( the
9411      largest size of an object can be only 32 bits ) */
9412
9413   pushedB = pushB ();
9414   MOVB (aopGet (right, 0, FALSE, FALSE));
9415   emitcode ("inc", "b");
9416   freeAsmop (right, NULL, ic, TRUE);
9417   aopOp (left, ic, FALSE);
9418   aopOp (result, ic, FALSE);
9419
9420   /* now move the left to the result if they are not the
9421      same */
9422   if (!sameRegs (AOP (left), AOP (result)) &&
9423       AOP_SIZE (result) > 1)
9424     {
9425
9426       size = AOP_SIZE (result);
9427       offset = 0;
9428       while (size--)
9429         {
9430           l = aopGet (left, offset, FALSE, TRUE);
9431           if (*l == '@' && IS_AOP_PREG (result))
9432             {
9433
9434               emitcode ("mov", "a,%s", l);
9435               aopPut (result, "a", offset);
9436             }
9437           else
9438             aopPut (result, l, offset);
9439           offset++;
9440         }
9441     }
9442
9443   /* mov the highest order bit to OVR */
9444   tlbl = newiTempLabel (NULL);
9445   tlbl1 = newiTempLabel (NULL);
9446
9447   size = AOP_SIZE (result);
9448   offset = size - 1;
9449   MOVA (aopGet (left, offset, FALSE, FALSE));
9450   emitcode ("rlc", "a");
9451   emitcode ("mov", "ov,c");
9452   /* if it is only one byte then */
9453   if (size == 1)
9454     {
9455       l = aopGet (left, 0, FALSE, FALSE);
9456       MOVA (l);
9457       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9458       emitLabel (tlbl);
9459       emitcode ("mov", "c,ov");
9460       emitcode ("rrc", "a");
9461       emitLabel (tlbl1);
9462       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9463       popB (pushedB);
9464       aopPut (result, "a", 0);
9465       goto release;
9466     }
9467
9468   reAdjustPreg (AOP (result));
9469   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9470   emitLabel (tlbl);
9471   emitcode ("mov", "c,ov");
9472   while (size--)
9473     {
9474       l = aopGet (result, offset, FALSE, FALSE);
9475       MOVA (l);
9476       emitcode ("rrc", "a");
9477       aopPut (result, "a", offset--);
9478     }
9479   reAdjustPreg (AOP (result));
9480   emitLabel (tlbl1);
9481   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9482   popB (pushedB);
9483
9484 release:
9485   freeAsmop (result, NULL, ic, TRUE);
9486   freeAsmop (left, NULL, ic, TRUE);
9487 }
9488
9489 /*-----------------------------------------------------------------*/
9490 /* genRightShift - generate code for right shifting                */
9491 /*-----------------------------------------------------------------*/
9492 static void
9493 genRightShift (iCode * ic)
9494 {
9495   operand *right, *left, *result;
9496   sym_link *letype;
9497   int size, offset;
9498   char *l;
9499   symbol *tlbl, *tlbl1;
9500   bool pushedB;
9501
9502   D (emitcode (";", "genRightShift"));
9503
9504   /* if signed then we do it the hard way preserve the
9505      sign bit moving it inwards */
9506   letype = getSpec (operandType (IC_LEFT (ic)));
9507
9508   if (!SPEC_USIGN (letype))
9509     {
9510       genSignedRightShift (ic);
9511       return;
9512     }
9513
9514   /* signed & unsigned types are treated the same : i.e. the
9515      signed is NOT propagated inwards : quoting from the
9516      ANSI - standard : "for E1 >> E2, is equivalent to division
9517      by 2**E2 if unsigned or if it has a non-negative value,
9518      otherwise the result is implementation defined ", MY definition
9519      is that the sign does not get propagated */
9520
9521   right = IC_RIGHT (ic);
9522   left = IC_LEFT (ic);
9523   result = IC_RESULT (ic);
9524
9525   aopOp (right, ic, FALSE);
9526
9527   /* if the shift count is known then do it
9528      as efficiently as possible */
9529   if (AOP_TYPE (right) == AOP_LIT)
9530     {
9531       genRightShiftLiteral (left, right, result, ic, 0);
9532       return;
9533     }
9534
9535   /* shift count is unknown then we have to form
9536      a loop get the loop count in B : Note: we take
9537      only the lower order byte since shifting
9538      more that 32 bits make no sense anyway, ( the
9539      largest size of an object can be only 32 bits ) */
9540
9541   pushedB = pushB ();
9542   MOVB (aopGet (right, 0, FALSE, FALSE));
9543   emitcode ("inc", "b");
9544   freeAsmop (right, NULL, ic, TRUE);
9545   aopOp (left, ic, FALSE);
9546   aopOp (result, ic, FALSE);
9547
9548   /* now move the left to the result if they are not the
9549      same */
9550   if (!sameRegs (AOP (left), AOP (result)) &&
9551       AOP_SIZE (result) > 1)
9552     {
9553       size = AOP_SIZE (result);
9554       offset = 0;
9555       while (size--)
9556         {
9557           l = aopGet (left, offset, FALSE, TRUE);
9558           if (*l == '@' && IS_AOP_PREG (result))
9559             {
9560
9561               emitcode ("mov", "a,%s", l);
9562               aopPut (result, "a", offset);
9563             }
9564           else
9565             aopPut (result, l, offset);
9566           offset++;
9567         }
9568     }
9569
9570   tlbl = newiTempLabel (NULL);
9571   tlbl1 = newiTempLabel (NULL);
9572   size = AOP_SIZE (result);
9573   offset = size - 1;
9574
9575   /* if it is only one byte then */
9576   if (size == 1)
9577     {
9578       l = aopGet (left, 0, FALSE, FALSE);
9579       MOVA (l);
9580       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9581       emitLabel (tlbl);
9582       CLRC;
9583       emitcode ("rrc", "a");
9584       emitLabel (tlbl1);
9585       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9586       popB (pushedB);
9587       aopPut (result, "a", 0);
9588       goto release;
9589     }
9590
9591   reAdjustPreg (AOP (result));
9592   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9593   emitLabel (tlbl);
9594   CLRC;
9595   while (size--)
9596     {
9597       l = aopGet (result, offset, FALSE, FALSE);
9598       MOVA (l);
9599       emitcode ("rrc", "a");
9600       aopPut (result, "a", offset--);
9601     }
9602   reAdjustPreg (AOP (result));
9603
9604   emitLabel (tlbl1);
9605   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9606   popB (pushedB);
9607
9608 release:
9609   freeAsmop (result, NULL, ic, TRUE);
9610   freeAsmop (left, NULL, ic, TRUE);
9611 }
9612
9613 /*-----------------------------------------------------------------*/
9614 /* emitPtrByteGet - emits code to get a byte into A through a      */
9615 /*                  pointer register (R0, R1, or DPTR). The        */
9616 /*                  original value of A can be preserved in B.     */
9617 /*-----------------------------------------------------------------*/
9618 static void
9619 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9620 {
9621   switch (p_type)
9622     {
9623     case IPOINTER:
9624     case POINTER:
9625       if (preserveAinB)
9626         emitcode ("mov", "b,a");
9627       emitcode ("mov", "a,@%s", rname);
9628       break;
9629
9630     case PPOINTER:
9631       if (preserveAinB)
9632         emitcode ("mov", "b,a");
9633       emitcode ("movx", "a,@%s", rname);
9634       break;
9635
9636     case FPOINTER:
9637       if (preserveAinB)
9638         emitcode ("mov", "b,a");
9639       emitcode ("movx", "a,@dptr");
9640       break;
9641
9642     case CPOINTER:
9643       if (preserveAinB)
9644         emitcode ("mov", "b,a");
9645       emitcode ("clr", "a");
9646       emitcode ("movc", "a,@a+dptr");
9647       break;
9648
9649     case GPOINTER:
9650       if (preserveAinB)
9651         {
9652           emitcode ("push", "b");
9653           emitcode ("push", "acc");
9654         }
9655       emitcode ("lcall", "__gptrget");
9656       if (preserveAinB)
9657         emitcode ("pop", "b");
9658       break;
9659     }
9660 }
9661
9662 /*-----------------------------------------------------------------*/
9663 /* emitPtrByteSet - emits code to set a byte from src through a    */
9664 /*                  pointer register (R0, R1, or DPTR).            */
9665 /*-----------------------------------------------------------------*/
9666 static void
9667 emitPtrByteSet (char *rname, int p_type, char *src)
9668 {
9669   switch (p_type)
9670     {
9671     case IPOINTER:
9672     case POINTER:
9673       if (*src=='@')
9674         {
9675           MOVA (src);
9676           emitcode ("mov", "@%s,a", rname);
9677         }
9678       else
9679         emitcode ("mov", "@%s,%s", rname, src);
9680       break;
9681
9682     case PPOINTER:
9683       MOVA (src);
9684       emitcode ("movx", "@%s,a", rname);
9685       break;
9686
9687     case FPOINTER:
9688       MOVA (src);
9689       emitcode ("movx", "@dptr,a");
9690       break;
9691
9692     case GPOINTER:
9693       MOVA (src);
9694       emitcode ("lcall", "__gptrput");
9695       break;
9696     }
9697 }
9698
9699 /*-----------------------------------------------------------------*/
9700 /* genUnpackBits - generates code for unpacking bits               */
9701 /*-----------------------------------------------------------------*/
9702 static void
9703 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9704 {
9705   int offset = 0;       /* result byte offset */
9706   int rsize;            /* result size */
9707   int rlen = 0;         /* remaining bitfield length */
9708   sym_link *etype;      /* bitfield type information */
9709   int blen;             /* bitfield length */
9710   int bstr;             /* bitfield starting bit within byte */
9711   char buffer[10];
9712
9713   D(emitcode (";", "genUnpackBits"));
9714
9715   etype = getSpec (operandType (result));
9716   rsize = getSize (operandType (result));
9717   blen = SPEC_BLEN (etype);
9718   bstr = SPEC_BSTR (etype);
9719
9720   if (ifx && blen <= 8)
9721     {
9722       emitPtrByteGet (rname, ptype, FALSE);
9723       if (blen == 1)
9724         {
9725           SNPRINTF (buffer, sizeof(buffer),
9726                     "acc.%d", bstr);
9727           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9728         }
9729       else
9730         {
9731           if (blen < 8)
9732             emitcode ("anl", "a,#0x%02x",
9733                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9734           genIfxJump (ifx, "a", NULL, NULL, NULL);
9735         }
9736       return;
9737     }
9738   wassert (!ifx);
9739
9740   /* If the bitfield length is less than a byte */
9741   if (blen < 8)
9742     {
9743       emitPtrByteGet (rname, ptype, FALSE);
9744       AccRol (8 - bstr);
9745       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9746       if (!SPEC_USIGN (etype))
9747         {
9748           /* signed bitfield */
9749           symbol *tlbl = newiTempLabel (NULL);
9750
9751           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9752           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9753           emitLabel (tlbl);
9754         }
9755       aopPut (result, "a", offset++);
9756       goto finish;
9757     }
9758
9759   /* Bit field did not fit in a byte. Copy all
9760      but the partial byte at the end.  */
9761   for (rlen=blen;rlen>=8;rlen-=8)
9762     {
9763       emitPtrByteGet (rname, ptype, FALSE);
9764       aopPut (result, "a", offset++);
9765       if (rlen>8)
9766         emitcode ("inc", "%s", rname);
9767     }
9768
9769   /* Handle the partial byte at the end */
9770   if (rlen)
9771     {
9772       emitPtrByteGet (rname, ptype, FALSE);
9773       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9774       if (!SPEC_USIGN (etype))
9775         {
9776           /* signed bitfield */
9777           symbol *tlbl = newiTempLabel (NULL);
9778
9779           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9780           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9781           emitLabel (tlbl);
9782         }
9783       aopPut (result, "a", offset++);
9784     }
9785
9786 finish:
9787   if (offset < rsize)
9788     {
9789       char *source;
9790
9791       if (SPEC_USIGN (etype))
9792         source = zero;
9793       else
9794         {
9795           /* signed bitfield: sign extension with 0x00 or 0xff */
9796           emitcode ("rlc", "a");
9797           emitcode ("subb", "a,acc");
9798
9799           source = "a";
9800         }
9801       rsize -= offset;
9802       while (rsize--)
9803         aopPut (result, source, offset++);
9804     }
9805 }
9806
9807
9808 /*-----------------------------------------------------------------*/
9809 /* genDataPointerGet - generates code when ptr offset is known     */
9810 /*-----------------------------------------------------------------*/
9811 static void
9812 genDataPointerGet (operand * left,
9813                    operand * result,
9814                    iCode * ic)
9815 {
9816   char *l;
9817   char buffer[256];
9818   int size, offset = 0;
9819
9820   D (emitcode (";", "genDataPointerGet"));
9821
9822   aopOp (result, ic, TRUE);
9823
9824   /* get the string representation of the name */
9825   l = aopGet (left, 0, FALSE, TRUE);
9826   l++; // remove #
9827   size = AOP_SIZE (result);
9828   while (size--)
9829     {
9830       if (offset)
9831         {
9832           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9833         }
9834       else
9835         {
9836           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9837         }
9838       aopPut (result, buffer, offset++);
9839     }
9840
9841   freeAsmop (result, NULL, ic, TRUE);
9842   freeAsmop (left, NULL, ic, TRUE);
9843 }
9844
9845 /*-----------------------------------------------------------------*/
9846 /* genNearPointerGet - emitcode for near pointer fetch             */
9847 /*-----------------------------------------------------------------*/
9848 static void
9849 genNearPointerGet (operand * left,
9850                    operand * result,
9851                    iCode * ic,
9852                    iCode * pi,
9853                    iCode * ifx)
9854 {
9855   asmop *aop = NULL;
9856   regs *preg = NULL;
9857   char *rname;
9858   sym_link *rtype, *retype;
9859   sym_link *ltype = operandType (left);
9860   char buffer[80];
9861
9862   D (emitcode (";", "genNearPointerGet"));
9863
9864   rtype = operandType (result);
9865   retype = getSpec (rtype);
9866
9867   aopOp (left, ic, FALSE);
9868
9869   /* if left is rematerialisable and
9870      result is not bitfield variable type and
9871      the left is pointer to data space i.e
9872      lower 128 bytes of space */
9873   if (AOP_TYPE (left) == AOP_IMMD &&
9874       !IS_BITFIELD (retype) &&
9875       DCL_TYPE (ltype) == POINTER)
9876     {
9877       genDataPointerGet (left, result, ic);
9878       return;
9879     }
9880
9881  /* if the value is already in a pointer register
9882      then don't need anything more */
9883   if (!AOP_INPREG (AOP (left)))
9884     {
9885       if (IS_AOP_PREG (left))
9886         {
9887           // Aha, it is a pointer, just in disguise.
9888           rname = aopGet (left, 0, FALSE, FALSE);
9889           if (*rname != '@')
9890             {
9891               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9892                       __FILE__, __LINE__);
9893             }
9894           else
9895             {
9896               // Expected case.
9897               emitcode ("mov", "a%s,%s", rname + 1, rname);
9898               rname++;  // skip the '@'.
9899             }
9900         }
9901       else
9902         {
9903           /* otherwise get a free pointer register */
9904           aop = newAsmop (0);
9905           preg = getFreePtr (ic, &aop, FALSE);
9906           emitcode ("mov", "%s,%s",
9907                     preg->name,
9908                     aopGet (left, 0, FALSE, TRUE));
9909           rname = preg->name;
9910         }
9911     }
9912   else
9913     rname = aopGet (left, 0, FALSE, FALSE);
9914
9915   //aopOp (result, ic, FALSE);
9916   aopOp (result, ic, result?TRUE:FALSE);
9917
9918   /* if bitfield then unpack the bits */
9919   if (IS_BITFIELD (retype))
9920     genUnpackBits (result, rname, POINTER, ifx);
9921   else
9922     {
9923       /* we have can just get the values */
9924       int size = AOP_SIZE (result);
9925       int offset = 0;
9926
9927       while (size--)
9928         {
9929           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9930             {
9931
9932               emitcode ("mov", "a,@%s", rname);
9933               if (!ifx)
9934                 aopPut (result, "a", offset);
9935             }
9936           else
9937             {
9938               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9939               aopPut (result, buffer, offset);
9940             }
9941           offset++;
9942           if (size || pi)
9943             emitcode ("inc", "%s", rname);
9944         }
9945     }
9946
9947   /* now some housekeeping stuff */
9948   if (aop)       /* we had to allocate for this iCode */
9949     {
9950       if (pi) { /* post increment present */
9951         aopPut (left, rname, 0);
9952       }
9953       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9954     }
9955   else
9956     {
9957       /* we did not allocate which means left
9958          already in a pointer register, then
9959          if size > 0 && this could be used again
9960          we have to point it back to where it
9961          belongs */
9962       if ((AOP_SIZE (result) > 1 &&
9963            !OP_SYMBOL (left)->remat &&
9964            (OP_SYMBOL (left)->liveTo > ic->seq ||
9965             ic->depth)) &&
9966           !pi)
9967         {
9968           int size = AOP_SIZE (result) - 1;
9969           while (size--)
9970             emitcode ("dec", "%s", rname);
9971         }
9972     }
9973
9974   if (ifx && !ifx->generated)
9975     {
9976       genIfxJump (ifx, "a", left, NULL, result);
9977     }
9978
9979   /* done */
9980   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9981   freeAsmop (left, NULL, ic, TRUE);
9982   if (pi) pi->generated = 1;
9983 }
9984
9985 /*-----------------------------------------------------------------*/
9986 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9987 /*-----------------------------------------------------------------*/
9988 static void
9989 genPagedPointerGet (operand * left,
9990                     operand * result,
9991                     iCode * ic,
9992                     iCode *pi,
9993                     iCode *ifx)
9994 {
9995   asmop *aop = NULL;
9996   regs *preg = NULL;
9997   char *rname;
9998   sym_link *rtype, *retype;
9999
10000   D (emitcode (";", "genPagedPointerGet"));
10001
10002   rtype = operandType (result);
10003   retype = getSpec (rtype);
10004
10005   aopOp (left, ic, FALSE);
10006
10007   /* if the value is already in a pointer register
10008      then don't need anything more */
10009   if (!AOP_INPREG (AOP (left)))
10010     {
10011       /* otherwise get a free pointer register */
10012       aop = newAsmop (0);
10013       preg = getFreePtr (ic, &aop, FALSE);
10014       emitcode ("mov", "%s,%s",
10015                 preg->name,
10016                 aopGet (left, 0, FALSE, TRUE));
10017       rname = preg->name;
10018     }
10019   else
10020     rname = aopGet (left, 0, FALSE, FALSE);
10021
10022   aopOp (result, ic, FALSE);
10023
10024   /* if bitfield then unpack the bits */
10025   if (IS_BITFIELD (retype))
10026     genUnpackBits (result, rname, PPOINTER, ifx);
10027   else
10028     {
10029       /* we have can just get the values */
10030       int size = AOP_SIZE (result);
10031       int offset = 0;
10032
10033       while (size--)
10034         {
10035
10036           emitcode ("movx", "a,@%s", rname);
10037           if (!ifx)
10038             aopPut (result, "a", offset);
10039
10040           offset++;
10041
10042           if (size || pi)
10043             emitcode ("inc", "%s", rname);
10044         }
10045     }
10046
10047   /* now some housekeeping stuff */
10048   if (aop) /* we had to allocate for this iCode */
10049     {
10050       if (pi)
10051         aopPut (left, rname, 0);
10052       freeAsmop (NULL, aop, ic, TRUE);
10053     }
10054   else
10055     {
10056       /* we did not allocate which means left
10057          already in a pointer register, then
10058          if size > 0 && this could be used again
10059          we have to point it back to where it
10060          belongs */
10061       if ((AOP_SIZE (result) > 1 &&
10062            !OP_SYMBOL (left)->remat &&
10063            (OP_SYMBOL (left)->liveTo > ic->seq ||
10064             ic->depth)) &&
10065           !pi)
10066         {
10067           int size = AOP_SIZE (result) - 1;
10068           while (size--)
10069             emitcode ("dec", "%s", rname);
10070         }
10071     }
10072
10073   if (ifx && !ifx->generated)
10074     {
10075       genIfxJump (ifx, "a", left, NULL, result);
10076     }
10077
10078   /* done */
10079   freeAsmop (result, NULL, ic, TRUE);
10080   freeAsmop (left, NULL, ic, TRUE);
10081   if (pi) pi->generated = 1;
10082 }
10083
10084 /*--------------------------------------------------------------------*/
10085 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10086 /*--------------------------------------------------------------------*/
10087 static void
10088 loadDptrFromOperand (operand *op, bool loadBToo)
10089 {
10090   if (AOP_TYPE (op) != AOP_STR)
10091     {
10092       /* if this is rematerializable */
10093       if (AOP_TYPE (op) == AOP_IMMD)
10094         {
10095           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10096           if (loadBToo)
10097             {
10098               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10099                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10100               else
10101                 {
10102                   wassertl(FALSE, "need pointerCode");
10103                   emitcode (";", "mov b,???");
10104                   /* genPointerGet and genPointerSet originally did different
10105                   ** things for this case. Both seem wrong.
10106                   ** from genPointerGet:
10107                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10108                   ** from genPointerSet:
10109                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10110                   */
10111                 }
10112             }
10113         }
10114       else if (AOP_TYPE (op) == AOP_DPTR)
10115         {
10116           if (loadBToo)
10117             {
10118               MOVA (aopGet (op, 0, FALSE, FALSE));
10119               emitcode ("push", "acc");
10120               MOVA (aopGet (op, 1, FALSE, FALSE));
10121               emitcode ("push", "acc");
10122               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10123               emitcode ("pop", "dph");
10124               emitcode ("pop", "dpl");
10125             }
10126           else
10127             {
10128               MOVA (aopGet (op, 0, FALSE, FALSE));
10129               emitcode ("push", "acc");
10130               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10131               emitcode ("pop", "dpl");
10132             }
10133         }
10134       else
10135         {                       /* we need to get it byte by byte */
10136           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10137           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10138           if (loadBToo)
10139             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10140         }
10141     }
10142 }
10143
10144 /*-----------------------------------------------------------------*/
10145 /* genFarPointerGet - get value from far space                     */
10146 /*-----------------------------------------------------------------*/
10147 static void
10148 genFarPointerGet (operand * left,
10149                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10150 {
10151   int size, offset;
10152   sym_link *retype = getSpec (operandType (result));
10153
10154   D (emitcode (";", "genFarPointerGet"));
10155
10156   aopOp (left, ic, FALSE);
10157   loadDptrFromOperand (left, FALSE);
10158
10159   /* so dptr now contains the address */
10160   aopOp (result, ic, FALSE);
10161
10162   /* if bit then unpack */
10163   if (IS_BITFIELD (retype))
10164     genUnpackBits (result, "dptr", FPOINTER, ifx);
10165   else
10166     {
10167       size = AOP_SIZE (result);
10168       offset = 0;
10169
10170       while (size--)
10171         {
10172           emitcode ("movx", "a,@dptr");
10173           if (!ifx)
10174             aopPut (result, "a", offset++);
10175           if (size || pi)
10176             emitcode ("inc", "dptr");
10177         }
10178     }
10179
10180   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10181     {
10182       aopPut (left, "dpl", 0);
10183       aopPut (left, "dph", 1);
10184       pi->generated = 1;
10185     }
10186
10187   if (ifx && !ifx->generated)
10188     {
10189       genIfxJump (ifx, "a", left, NULL, result);
10190     }
10191
10192   freeAsmop (result, NULL, ic, TRUE);
10193   freeAsmop (left, NULL, ic, TRUE);
10194 }
10195
10196 /*-----------------------------------------------------------------*/
10197 /* genCodePointerGet - get value from code space                   */
10198 /*-----------------------------------------------------------------*/
10199 static void
10200 genCodePointerGet (operand * left,
10201                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10202 {
10203   int size, offset;
10204   sym_link *retype = getSpec (operandType (result));
10205
10206   D (emitcode (";", "genCodePointerGet"));
10207
10208   aopOp (left, ic, FALSE);
10209   loadDptrFromOperand (left, FALSE);
10210
10211   /* so dptr now contains the address */
10212   aopOp (result, ic, FALSE);
10213
10214   /* if bit then unpack */
10215   if (IS_BITFIELD (retype))
10216     genUnpackBits (result, "dptr", CPOINTER, ifx);
10217   else
10218     {
10219       size = AOP_SIZE (result);
10220       offset = 0;
10221
10222       while (size--)
10223         {
10224           emitcode ("clr", "a");
10225           emitcode ("movc", "a,@a+dptr");
10226           if (!ifx)
10227             aopPut (result, "a", offset++);
10228           if (size || pi)
10229             emitcode ("inc", "dptr");
10230         }
10231     }
10232
10233   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10234     {
10235       aopPut (left, "dpl", 0);
10236       aopPut (left, "dph", 1);
10237       pi->generated = 1;
10238     }
10239
10240   if (ifx && !ifx->generated)
10241     {
10242       genIfxJump (ifx, "a", left, NULL, result);
10243     }
10244
10245   freeAsmop (result, NULL, ic, TRUE);
10246   freeAsmop (left, NULL, ic, TRUE);
10247 }
10248
10249 /*-----------------------------------------------------------------*/
10250 /* genGenPointerGet - get value from generic pointer space         */
10251 /*-----------------------------------------------------------------*/
10252 static void
10253 genGenPointerGet (operand * left,
10254                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10255 {
10256   int size, offset;
10257   sym_link *retype = getSpec (operandType (result));
10258
10259   D (emitcode (";", "genGenPointerGet"));
10260
10261   aopOp (left, ic, FALSE);
10262   loadDptrFromOperand (left, TRUE);
10263
10264   /* so dptr now contains the address */
10265   aopOp (result, ic, FALSE);
10266
10267   /* if bit then unpack */
10268   if (IS_BITFIELD (retype))
10269     {
10270       genUnpackBits (result, "dptr", GPOINTER, ifx);
10271     }
10272   else
10273     {
10274       size = AOP_SIZE (result);
10275       offset = 0;
10276
10277       while (size--)
10278         {
10279           emitcode ("lcall", "__gptrget");
10280           if (!ifx)
10281             aopPut (result, "a", offset++);
10282           if (size || pi)
10283             emitcode ("inc", "dptr");
10284         }
10285     }
10286
10287   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10288     {
10289       aopPut (left, "dpl", 0);
10290       aopPut (left, "dph", 1);
10291       pi->generated = 1;
10292     }
10293
10294   if (ifx && !ifx->generated)
10295     {
10296       genIfxJump (ifx, "a", left, NULL, result);
10297     }
10298
10299   freeAsmop (result, NULL, ic, TRUE);
10300   freeAsmop (left, NULL, ic, TRUE);
10301 }
10302
10303 /*-----------------------------------------------------------------*/
10304 /* genPointerGet - generate code for pointer get                   */
10305 /*-----------------------------------------------------------------*/
10306 static void
10307 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10308 {
10309   operand *left, *result;
10310   sym_link *type, *etype;
10311   int p_type;
10312
10313   D (emitcode (";", "genPointerGet"));
10314
10315   left = IC_LEFT (ic);
10316   result = IC_RESULT (ic);
10317
10318   if (getSize (operandType (result))>1)
10319     ifx = NULL;
10320
10321   /* depending on the type of pointer we need to
10322      move it to the correct pointer register */
10323   type = operandType (left);
10324   etype = getSpec (type);
10325   /* if left is of type of pointer then it is simple */
10326   if (IS_PTR (type) && !IS_FUNC (type->next))
10327     p_type = DCL_TYPE (type);
10328   else
10329     {
10330       /* we have to go by the storage class */
10331       p_type = PTR_TYPE (SPEC_OCLS (etype));
10332     }
10333
10334   /* special case when cast remat */
10335   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10336       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10337     {
10338       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10339       type = operandType (left);
10340       p_type = DCL_TYPE (type);
10341     }
10342   /* now that we have the pointer type we assign
10343      the pointer values */
10344   switch (p_type)
10345     {
10346
10347     case POINTER:
10348     case IPOINTER:
10349       genNearPointerGet (left, result, ic, pi, ifx);
10350       break;
10351
10352     case PPOINTER:
10353       genPagedPointerGet (left, result, ic, pi, ifx);
10354       break;
10355
10356     case FPOINTER:
10357       genFarPointerGet (left, result, ic, pi, ifx);
10358       break;
10359
10360     case CPOINTER:
10361       genCodePointerGet (left, result, ic, pi, ifx);
10362       break;
10363
10364     case GPOINTER:
10365       genGenPointerGet (left, result, ic, pi, ifx);
10366       break;
10367     }
10368 }
10369
10370
10371 /*-----------------------------------------------------------------*/
10372 /* genPackBits - generates code for packed bit storage             */
10373 /*-----------------------------------------------------------------*/
10374 static void
10375 genPackBits (sym_link * etype,
10376              operand * right,
10377              char *rname, int p_type)
10378 {
10379   int offset = 0;       /* source byte offset */
10380   int rlen = 0;         /* remaining bitfield length */
10381   int blen;             /* bitfield length */
10382   int bstr;             /* bitfield starting bit within byte */
10383   int litval;           /* source literal value (if AOP_LIT) */
10384   unsigned char mask;   /* bitmask within current byte */
10385
10386   D(emitcode (";", "genPackBits"));
10387
10388   blen = SPEC_BLEN (etype);
10389   bstr = SPEC_BSTR (etype);
10390
10391   /* If the bitfield length is less than a byte */
10392   if (blen < 8)
10393     {
10394       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10395               (unsigned char) (0xFF >> (8 - bstr)));
10396
10397       if (AOP_TYPE (right) == AOP_LIT)
10398         {
10399           /* Case with a bitfield length <8 and literal source
10400           */
10401           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10402           litval <<= bstr;
10403           litval &= (~mask) & 0xff;
10404           emitPtrByteGet (rname, p_type, FALSE);
10405           if ((mask|litval)!=0xff)
10406             emitcode ("anl","a,#0x%02x", mask);
10407           if (litval)
10408             emitcode ("orl","a,#0x%02x", litval);
10409         }
10410       else
10411         {
10412           if ((blen==1) && (p_type!=GPOINTER))
10413             {
10414               /* Case with a bitfield length == 1 and no generic pointer
10415               */
10416               if (AOP_TYPE (right) == AOP_CRY)
10417                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10418               else
10419                 {
10420                   MOVA (aopGet (right, 0, FALSE, FALSE));
10421                   emitcode ("rrc","a");
10422                 }
10423               emitPtrByteGet (rname, p_type, FALSE);
10424               emitcode ("mov","acc.%d,c",bstr);
10425             }
10426           else
10427             {
10428               bool pushedB;
10429               /* Case with a bitfield length < 8 and arbitrary source
10430               */
10431               MOVA (aopGet (right, 0, FALSE, FALSE));
10432               /* shift and mask source value */
10433               AccLsh (bstr);
10434               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10435
10436               pushedB = pushB ();
10437               /* transfer A to B and get next byte */
10438               emitPtrByteGet (rname, p_type, TRUE);
10439
10440               emitcode ("anl", "a,#0x%02x", mask);
10441               emitcode ("orl", "a,b");
10442               if (p_type == GPOINTER)
10443                 emitcode ("pop", "b");
10444
10445               popB (pushedB);
10446            }
10447         }
10448
10449       emitPtrByteSet (rname, p_type, "a");
10450       return;
10451     }
10452
10453   /* Bit length is greater than 7 bits. In this case, copy  */
10454   /* all except the partial byte at the end                 */
10455   for (rlen=blen;rlen>=8;rlen-=8)
10456     {
10457       emitPtrByteSet (rname, p_type,
10458                       aopGet (right, offset++, FALSE, TRUE) );
10459       if (rlen>8)
10460         emitcode ("inc", "%s", rname);
10461     }
10462
10463   /* If there was a partial byte at the end */
10464   if (rlen)
10465     {
10466       mask = (((unsigned char) -1 << rlen) & 0xff);
10467
10468       if (AOP_TYPE (right) == AOP_LIT)
10469         {
10470           /* Case with partial byte and literal source
10471           */
10472           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10473           litval >>= (blen-rlen);
10474           litval &= (~mask) & 0xff;
10475           emitPtrByteGet (rname, p_type, FALSE);
10476           if ((mask|litval)!=0xff)
10477             emitcode ("anl","a,#0x%02x", mask);
10478           if (litval)
10479             emitcode ("orl","a,#0x%02x", litval);
10480         }
10481       else
10482         {
10483           bool pushedB;
10484           /* Case with partial byte and arbitrary source
10485           */
10486           MOVA (aopGet (right, offset++, FALSE, FALSE));
10487           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10488
10489           pushedB = pushB ();
10490           /* transfer A to B and get next byte */
10491           emitPtrByteGet (rname, p_type, TRUE);
10492
10493           emitcode ("anl", "a,#0x%02x", mask);
10494           emitcode ("orl", "a,b");
10495           if (p_type == GPOINTER)
10496             emitcode ("pop", "b");
10497
10498           popB (pushedB);
10499         }
10500       emitPtrByteSet (rname, p_type, "a");
10501     }
10502 }
10503
10504
10505 /*-----------------------------------------------------------------*/
10506 /* genDataPointerSet - remat pointer to data space                 */
10507 /*-----------------------------------------------------------------*/
10508 static void
10509 genDataPointerSet (operand * right,
10510                    operand * result,
10511                    iCode * ic)
10512 {
10513   int size, offset = 0;
10514   char *l, buffer[256];
10515
10516   D (emitcode (";", "genDataPointerSet"));
10517
10518   aopOp (right, ic, FALSE);
10519
10520   l = aopGet (result, 0, FALSE, TRUE);
10521   l++; //remove #
10522   size = AOP_SIZE (right);
10523   while (size--)
10524     {
10525       if (offset)
10526         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10527       else
10528         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10529       emitcode ("mov", "%s,%s", buffer,
10530                 aopGet (right, offset++, FALSE, FALSE));
10531     }
10532
10533   freeAsmop (result, NULL, ic, TRUE);
10534   freeAsmop (right, NULL, ic, TRUE);
10535 }
10536
10537 /*-----------------------------------------------------------------*/
10538 /* genNearPointerSet - emitcode for near pointer put                */
10539 /*-----------------------------------------------------------------*/
10540 static void
10541 genNearPointerSet (operand * right,
10542                    operand * result,
10543                    iCode * ic,
10544                    iCode * pi)
10545 {
10546   asmop *aop = NULL;
10547   regs *preg = NULL;
10548   char *rname, *l;
10549   sym_link *retype, *letype;
10550   sym_link *ptype = operandType (result);
10551
10552   D (emitcode (";", "genNearPointerSet"));
10553
10554   retype = getSpec (operandType (right));
10555   letype = getSpec (ptype);
10556
10557   aopOp (result, ic, FALSE);
10558
10559   /* if the result is rematerializable &
10560      in data space & not a bit variable */
10561   if (AOP_TYPE (result) == AOP_IMMD &&
10562       DCL_TYPE (ptype) == POINTER &&
10563       !IS_BITVAR (retype) &&
10564       !IS_BITVAR (letype))
10565     {
10566       genDataPointerSet (right, result, ic);
10567       return;
10568     }
10569
10570   /* if the value is already in a pointer register
10571      then don't need anything more */
10572   if (!AOP_INPREG (AOP (result)))
10573     {
10574         if (
10575             //AOP_TYPE (result) == AOP_STK
10576             IS_AOP_PREG(result)
10577             )
10578         {
10579             // Aha, it is a pointer, just in disguise.
10580             rname = aopGet (result, 0, FALSE, FALSE);
10581             if (*rname != '@')
10582             {
10583                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10584                         __FILE__, __LINE__);
10585             }
10586             else
10587             {
10588                 // Expected case.
10589                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10590                 rname++;  // skip the '@'.
10591             }
10592         }
10593         else
10594         {
10595             /* otherwise get a free pointer register */
10596             aop = newAsmop (0);
10597             preg = getFreePtr (ic, &aop, FALSE);
10598             emitcode ("mov", "%s,%s",
10599                       preg->name,
10600                       aopGet (result, 0, FALSE, TRUE));
10601             rname = preg->name;
10602         }
10603     }
10604     else
10605     {
10606         rname = aopGet (result, 0, FALSE, FALSE);
10607     }
10608
10609   aopOp (right, ic, FALSE);
10610
10611   /* if bitfield then unpack the bits */
10612   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10613     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10614   else
10615     {
10616       /* we can just get the values */
10617       int size = AOP_SIZE (right);
10618       int offset = 0;
10619
10620       while (size--)
10621         {
10622           l = aopGet (right, offset, FALSE, TRUE);
10623           if ((*l == '@') || (strcmp (l, "acc") == 0))
10624             {
10625               MOVA (l);
10626               emitcode ("mov", "@%s,a", rname);
10627             }
10628           else
10629             emitcode ("mov", "@%s,%s", rname, l);
10630           if (size || pi)
10631             emitcode ("inc", "%s", rname);
10632           offset++;
10633         }
10634     }
10635
10636   /* now some housekeeping stuff */
10637   if (aop) /* we had to allocate for this iCode */
10638     {
10639       if (pi)
10640         aopPut (result, rname, 0);
10641       freeAsmop (NULL, aop, ic, TRUE);
10642     }
10643   else
10644     {
10645       /* we did not allocate which means left
10646          already in a pointer register, then
10647          if size > 0 && this could be used again
10648          we have to point it back to where it
10649          belongs */
10650       if ((AOP_SIZE (right) > 1 &&
10651            !OP_SYMBOL (result)->remat &&
10652            (OP_SYMBOL (result)->liveTo > ic->seq ||
10653             ic->depth)) &&
10654           !pi)
10655         {
10656           int size = AOP_SIZE (right) - 1;
10657           while (size--)
10658             emitcode ("dec", "%s", rname);
10659         }
10660     }
10661
10662   /* done */
10663   if (pi) pi->generated = 1;
10664   freeAsmop (result, NULL, ic, TRUE);
10665   freeAsmop (right, NULL, ic, TRUE);
10666 }
10667
10668 /*-----------------------------------------------------------------*/
10669 /* genPagedPointerSet - emitcode for Paged pointer put             */
10670 /*-----------------------------------------------------------------*/
10671 static void
10672 genPagedPointerSet (operand * right,
10673                     operand * result,
10674                     iCode * ic,
10675                     iCode * pi)
10676 {
10677   asmop *aop = NULL;
10678   regs *preg = NULL;
10679   char *rname, *l;
10680   sym_link *retype, *letype;
10681
10682   D (emitcode (";", "genPagedPointerSet"));
10683
10684   retype = getSpec (operandType (right));
10685   letype = getSpec (operandType (result));
10686
10687   aopOp (result, ic, FALSE);
10688
10689   /* if the value is already in a pointer register
10690      then don't need anything more */
10691   if (!AOP_INPREG (AOP (result)))
10692     {
10693       /* otherwise get a free pointer register */
10694       aop = newAsmop (0);
10695       preg = getFreePtr (ic, &aop, FALSE);
10696       emitcode ("mov", "%s,%s",
10697                 preg->name,
10698                 aopGet (result, 0, FALSE, TRUE));
10699       rname = preg->name;
10700     }
10701   else
10702     rname = aopGet (result, 0, FALSE, FALSE);
10703
10704   aopOp (right, ic, FALSE);
10705
10706   /* if bitfield then unpack the bits */
10707   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10708     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10709   else
10710     {
10711       /* we have can just get the values */
10712       int size = AOP_SIZE (right);
10713       int offset = 0;
10714
10715       while (size--)
10716         {
10717           l = aopGet (right, offset, FALSE, TRUE);
10718           MOVA (l);
10719           emitcode ("movx", "@%s,a", rname);
10720
10721           if (size || pi)
10722             emitcode ("inc", "%s", rname);
10723
10724           offset++;
10725         }
10726     }
10727
10728   /* now some housekeeping stuff */
10729   if (aop) /* we had to allocate for this iCode */
10730     {
10731       if (pi)
10732         aopPut (result, rname, 0);
10733       freeAsmop (NULL, aop, ic, TRUE);
10734     }
10735   else
10736     {
10737       /* we did not allocate which means left
10738          already in a pointer register, then
10739          if size > 0 && this could be used again
10740          we have to point it back to where it
10741          belongs */
10742       if (AOP_SIZE (right) > 1 &&
10743           !OP_SYMBOL (result)->remat &&
10744           (OP_SYMBOL (result)->liveTo > ic->seq ||
10745            ic->depth))
10746         {
10747           int size = AOP_SIZE (right) - 1;
10748           while (size--)
10749             emitcode ("dec", "%s", rname);
10750         }
10751     }
10752
10753   /* done */
10754   if (pi) pi->generated = 1;
10755   freeAsmop (result, NULL, ic, TRUE);
10756   freeAsmop (right, NULL, ic, TRUE);
10757 }
10758
10759 /*-----------------------------------------------------------------*/
10760 /* genFarPointerSet - set value from far space                     */
10761 /*-----------------------------------------------------------------*/
10762 static void
10763 genFarPointerSet (operand * right,
10764                   operand * result, iCode * ic, iCode * pi)
10765 {
10766   int size, offset;
10767   sym_link *retype = getSpec (operandType (right));
10768   sym_link *letype = getSpec (operandType (result));
10769
10770   D(emitcode (";", "genFarPointerSet"));
10771
10772   aopOp (result, ic, FALSE);
10773   loadDptrFromOperand (result, FALSE);
10774
10775   /* so dptr now contains the address */
10776   aopOp (right, ic, FALSE);
10777
10778   /* if bit then unpack */
10779   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10780     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10781   else
10782     {
10783       size = AOP_SIZE (right);
10784       offset = 0;
10785
10786       while (size--)
10787         {
10788           char *l = aopGet (right, offset++, FALSE, FALSE);
10789           MOVA (l);
10790           emitcode ("movx", "@dptr,a");
10791           if (size || pi)
10792             emitcode ("inc", "dptr");
10793         }
10794     }
10795   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10796     aopPut (result, "dpl", 0);
10797     aopPut (result, "dph", 1);
10798     pi->generated=1;
10799   }
10800   freeAsmop (result, NULL, ic, TRUE);
10801   freeAsmop (right, NULL, ic, TRUE);
10802 }
10803
10804 /*-----------------------------------------------------------------*/
10805 /* genGenPointerSet - set value from generic pointer space         */
10806 /*-----------------------------------------------------------------*/
10807 static void
10808 genGenPointerSet (operand * right,
10809                   operand * result, iCode * ic, iCode * pi)
10810 {
10811   int size, offset;
10812   sym_link *retype = getSpec (operandType (right));
10813   sym_link *letype = getSpec (operandType (result));
10814
10815   D (emitcode (";", "genGenPointerSet"));
10816
10817   aopOp (result, ic, FALSE);
10818   loadDptrFromOperand (result, TRUE);
10819
10820   /* so dptr now contains the address */
10821   aopOp (right, ic, FALSE);
10822
10823   /* if bit then unpack */
10824   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10825     {
10826       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10827     }
10828   else
10829     {
10830       size = AOP_SIZE (right);
10831       offset = 0;
10832
10833       while (size--)
10834         {
10835           char *l = aopGet (right, offset++, FALSE, FALSE);
10836           MOVA (l);
10837           emitcode ("lcall", "__gptrput");
10838           if (size || pi)
10839             emitcode ("inc", "dptr");
10840         }
10841     }
10842
10843   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10844     aopPut (result, "dpl", 0);
10845     aopPut (result, "dph", 1);
10846     pi->generated=1;
10847   }
10848   freeAsmop (result, NULL, ic, TRUE);
10849   freeAsmop (right, NULL, ic, TRUE);
10850 }
10851
10852 /*-----------------------------------------------------------------*/
10853 /* genPointerSet - stores the value into a pointer location        */
10854 /*-----------------------------------------------------------------*/
10855 static void
10856 genPointerSet (iCode * ic, iCode *pi)
10857 {
10858   operand *right, *result;
10859   sym_link *type, *etype;
10860   int p_type;
10861
10862   D (emitcode (";", "genPointerSet"));
10863
10864   right = IC_RIGHT (ic);
10865   result = IC_RESULT (ic);
10866
10867   /* depending on the type of pointer we need to
10868      move it to the correct pointer register */
10869   type = operandType (result);
10870   etype = getSpec (type);
10871   /* if left is of type of pointer then it is simple */
10872   if (IS_PTR (type) && !IS_FUNC (type->next))
10873     {
10874       p_type = DCL_TYPE (type);
10875     }
10876   else
10877     {
10878       /* we have to go by the storage class */
10879       p_type = PTR_TYPE (SPEC_OCLS (etype));
10880     }
10881
10882   /* special case when cast remat */
10883   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10884       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10885           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10886           type = operandType (result);
10887           p_type = DCL_TYPE (type);
10888   }
10889
10890   /* now that we have the pointer type we assign
10891      the pointer values */
10892   switch (p_type)
10893     {
10894
10895     case POINTER:
10896     case IPOINTER:
10897       genNearPointerSet (right, result, ic, pi);
10898       break;
10899
10900     case PPOINTER:
10901       genPagedPointerSet (right, result, ic, pi);
10902       break;
10903
10904     case FPOINTER:
10905       genFarPointerSet (right, result, ic, pi);
10906       break;
10907
10908     case GPOINTER:
10909       genGenPointerSet (right, result, ic, pi);
10910       break;
10911
10912     default:
10913       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10914               "genPointerSet: illegal pointer type");
10915     }
10916 }
10917
10918 /*-----------------------------------------------------------------*/
10919 /* genIfx - generate code for Ifx statement                        */
10920 /*-----------------------------------------------------------------*/
10921 static void
10922 genIfx (iCode * ic, iCode * popIc)
10923 {
10924   operand *cond = IC_COND (ic);
10925   int isbit = 0;
10926   char *dup = NULL;
10927
10928   D (emitcode (";", "genIfx"));
10929
10930   aopOp (cond, ic, FALSE);
10931
10932   /* get the value into acc */
10933   if (AOP_TYPE (cond) != AOP_CRY)
10934     {
10935       toBoolean (cond);
10936     }
10937   else
10938     {
10939       isbit = 1;
10940       if (AOP(cond)->aopu.aop_dir)
10941         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10942     }
10943
10944   /* the result is now in the accumulator or a directly addressable bit */
10945   freeAsmop (cond, NULL, ic, TRUE);
10946
10947   /* if there was something to be popped then do it */
10948   if (popIc)
10949     genIpop (popIc);
10950
10951   /* if the condition is a bit variable */
10952   if (isbit && dup)
10953     genIfxJump(ic, dup, NULL, NULL, NULL);
10954   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10955     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10956   else if (isbit && !IS_ITEMP (cond))
10957     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10958   else
10959     genIfxJump (ic, "a", NULL, NULL, NULL);
10960
10961   ic->generated = 1;
10962 }
10963
10964 /*-----------------------------------------------------------------*/
10965 /* genAddrOf - generates code for address of                       */
10966 /*-----------------------------------------------------------------*/
10967 static void
10968 genAddrOf (iCode * ic)
10969 {
10970   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10971   int size, offset;
10972
10973   D (emitcode (";", "genAddrOf"));
10974
10975   aopOp (IC_RESULT (ic), ic, FALSE);
10976
10977   /* if the operand is on the stack then we
10978      need to get the stack offset of this
10979      variable */
10980   if (sym->onStack)
10981     {
10982       /* if it has an offset then we need to compute it */
10983       if (sym->stack)
10984         {
10985           int stack_offset = ((sym->stack < 0) ?
10986                               ((char) (sym->stack - _G.nRegsSaved)) :
10987                               ((char) sym->stack)) & 0xff;
10988           if ((abs(stack_offset) == 1) &&
10989               !AOP_NEEDSACC(IC_RESULT (ic)) &&
10990               !isOperandVolatile (IC_RESULT (ic), FALSE))
10991             {
10992               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10993               if (stack_offset > 0)
10994                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10995               else
10996                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10997             }
10998           else
10999             {
11000               emitcode ("mov", "a,%s", SYM_BP (sym));
11001               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11002               aopPut (IC_RESULT (ic), "a", 0);
11003             }
11004         }
11005       else
11006         {
11007           /* we can just move _bp */
11008           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11009         }
11010       /* fill the result with zero */
11011       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11012
11013       offset = 1;
11014       while (size--)
11015         {
11016           aopPut (IC_RESULT (ic), zero, offset++);
11017         }
11018       goto release;
11019     }
11020
11021   /* object not on stack then we need the name */
11022   size = AOP_SIZE (IC_RESULT (ic));
11023   offset = 0;
11024
11025   while (size--)
11026     {
11027       char s[SDCC_NAME_MAX];
11028       if (offset)
11029         sprintf (s, "#(%s >> %d)",
11030                  sym->rname,
11031                  offset * 8);
11032       else
11033         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11034       aopPut (IC_RESULT (ic), s, offset++);
11035     }
11036
11037 release:
11038   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11039
11040 }
11041
11042 /*-----------------------------------------------------------------*/
11043 /* genFarFarAssign - assignment when both are in far space         */
11044 /*-----------------------------------------------------------------*/
11045 static void
11046 genFarFarAssign (operand * result, operand * right, iCode * ic)
11047 {
11048   int size = AOP_SIZE (right);
11049   int offset = 0;
11050   char *l;
11051
11052   D (emitcode (";", "genFarFarAssign"));
11053
11054   /* first push the right side on to the stack */
11055   while (size--)
11056     {
11057       l = aopGet (right, offset++, FALSE, FALSE);
11058       MOVA (l);
11059       emitcode ("push", "acc");
11060     }
11061
11062   freeAsmop (right, NULL, ic, FALSE);
11063   /* now assign DPTR to result */
11064   aopOp (result, ic, FALSE);
11065   size = AOP_SIZE (result);
11066   while (size--)
11067     {
11068       emitcode ("pop", "acc");
11069       aopPut (result, "a", --offset);
11070     }
11071   freeAsmop (result, NULL, ic, FALSE);
11072 }
11073
11074 /*-----------------------------------------------------------------*/
11075 /* genAssign - generate code for assignment                        */
11076 /*-----------------------------------------------------------------*/
11077 static void
11078 genAssign (iCode * ic)
11079 {
11080   operand *result, *right;
11081   int size, offset;
11082   unsigned long lit = 0L;
11083
11084   D (emitcode (";", "genAssign"));
11085
11086   result = IC_RESULT (ic);
11087   right = IC_RIGHT (ic);
11088
11089   /* if they are the same */
11090   if (operandsEqu (result, right) &&
11091       !isOperandVolatile (result, FALSE) &&
11092       !isOperandVolatile (right, FALSE))
11093     return;
11094
11095   aopOp (right, ic, FALSE);
11096
11097   /* special case both in far space */
11098   if (AOP_TYPE (right) == AOP_DPTR &&
11099       IS_TRUE_SYMOP (result) &&
11100       isOperandInFarSpace (result))
11101     {
11102       genFarFarAssign (result, right, ic);
11103       return;
11104     }
11105
11106   aopOp (result, ic, TRUE);
11107
11108   /* if they are the same registers */
11109   if (sameRegs (AOP (right), AOP (result)) &&
11110       !isOperandVolatile (result, FALSE) &&
11111       !isOperandVolatile (right, FALSE))
11112     goto release;
11113
11114   /* if the result is a bit */
11115   if (AOP_TYPE (result) == AOP_CRY)
11116     {
11117       assignBit (result, right);
11118       goto release;
11119     }
11120
11121   /* bit variables done */
11122   /* general case */
11123   size = AOP_SIZE (result);
11124   offset = 0;
11125   if (AOP_TYPE (right) == AOP_LIT)
11126     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11127
11128   if ((size > 1) &&
11129       (AOP_TYPE (result) != AOP_REG) &&
11130       (AOP_TYPE (right) == AOP_LIT) &&
11131       !IS_FLOAT (operandType (right)) &&
11132       (lit < 256L))
11133     {
11134       while ((size) && (lit))
11135         {
11136           aopPut (result,
11137                   aopGet (right, offset, FALSE, FALSE),
11138                   offset);
11139           lit >>= 8;
11140           offset++;
11141           size--;
11142         }
11143       /* And now fill the rest with zeros. */
11144       if (size)
11145         {
11146           emitcode ("clr", "a");
11147         }
11148       while (size--)
11149         {
11150           aopPut (result, "a", offset);
11151           offset++;
11152         }
11153     }
11154   else
11155     {
11156       while (size--)
11157         {
11158           aopPut (result,
11159                   aopGet (right, offset, FALSE, FALSE),
11160                   offset);
11161           offset++;
11162         }
11163     }
11164
11165 release:
11166   freeAsmop (result, NULL, ic, TRUE);
11167   freeAsmop (right, NULL, ic, TRUE);
11168 }
11169
11170 /*-----------------------------------------------------------------*/
11171 /* genJumpTab - generates code for jump table                      */
11172 /*-----------------------------------------------------------------*/
11173 static void
11174 genJumpTab (iCode * ic)
11175 {
11176   symbol *jtab,*jtablo,*jtabhi;
11177   char *l;
11178   unsigned int count;
11179
11180   D (emitcode (";", "genJumpTab"));
11181
11182   count = elementsInSet( IC_JTLABELS (ic) );
11183
11184   if( count <= 16 )
11185     {
11186       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11187          if the switch argument is in a register.
11188          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11189       /* Peephole may not convert ljmp to sjmp or ret
11190          labelIsReturnOnly & labelInRange must check
11191          currPl->ic->op != JUMPTABLE */
11192       aopOp (IC_JTCOND (ic), ic, FALSE);
11193       /* get the condition into accumulator */
11194       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11195       MOVA (l);
11196       /* multiply by three */
11197       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11198         {
11199           emitcode ("mov", "b,#3");
11200           emitcode ("mul", "ab");
11201         }
11202       else
11203         {
11204           emitcode ("add", "a,acc");
11205           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11206         }
11207       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11208
11209       jtab = newiTempLabel (NULL);
11210       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11211       emitcode ("jmp", "@a+dptr");
11212       emitLabel (jtab);
11213       /* now generate the jump labels */
11214       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11215            jtab = setNextItem (IC_JTLABELS (ic)))
11216         emitcode ("ljmp", "%05d$", jtab->key + 100);
11217     }
11218   else
11219     {
11220       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11221          if the switch argument is in a register.
11222          For n>6 this algorithm may be more compact */
11223       jtablo = newiTempLabel (NULL);
11224       jtabhi = newiTempLabel (NULL);
11225
11226       /* get the condition into accumulator.
11227          Using b as temporary storage, if register push/pop is needed */
11228       aopOp (IC_JTCOND (ic), ic, FALSE);
11229       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11230       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11231           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11232         {
11233           // (MB) what if B is in use???
11234           wassertl(!BINUSE, "B was in use");
11235           emitcode ("mov", "b,%s", l);
11236           l = "b";
11237         }
11238       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11239       MOVA (l);
11240       if( count <= 112 )
11241         {
11242           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11243           emitcode ("movc", "a,@a+pc");
11244           emitcode ("push", "acc");
11245
11246           MOVA (l);
11247           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11248           emitcode ("movc", "a,@a+pc");
11249           emitcode ("push", "acc");
11250         }
11251       else
11252         {
11253           /* this scales up to n<=255, but needs two more bytes
11254              and changes dptr */
11255           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11256           emitcode ("movc", "a,@a+dptr");
11257           emitcode ("push", "acc");
11258
11259           MOVA (l);
11260           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11261           emitcode ("movc", "a,@a+dptr");
11262           emitcode ("push", "acc");
11263         }
11264
11265       emitcode ("ret", "");
11266
11267       /* now generate jump table, LSB */
11268       emitLabel (jtablo);
11269       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11270            jtab = setNextItem (IC_JTLABELS (ic)))
11271         emitcode (".db", "%05d$", jtab->key + 100);
11272
11273       /* now generate jump table, MSB */
11274       emitLabel (jtabhi);
11275       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11276            jtab = setNextItem (IC_JTLABELS (ic)))
11277          emitcode (".db", "%05d$>>8", jtab->key + 100);
11278     }
11279 }
11280
11281 /*-----------------------------------------------------------------*/
11282 /* genCast - gen code for casting                                  */
11283 /*-----------------------------------------------------------------*/
11284 static void
11285 genCast (iCode * ic)
11286 {
11287   operand *result = IC_RESULT (ic);
11288   sym_link *ctype = operandType (IC_LEFT (ic));
11289   sym_link *rtype = operandType (IC_RIGHT (ic));
11290   operand *right = IC_RIGHT (ic);
11291   int size, offset;
11292
11293   D (emitcode (";", "genCast"));
11294
11295   /* if they are equivalent then do nothing */
11296   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11297     return;
11298
11299   aopOp (right, ic, FALSE);
11300   aopOp (result, ic, FALSE);
11301
11302   /* if the result is a bit (and not a bitfield) */
11303   if (IS_BIT (OP_SYMBOL (result)->type))
11304     {
11305       assignBit (result, right);
11306       goto release;
11307     }
11308
11309   /* if they are the same size : or less */
11310   if (AOP_SIZE (result) <= AOP_SIZE (right))
11311     {
11312
11313       /* if they are in the same place */
11314       if (sameRegs (AOP (right), AOP (result)))
11315         goto release;
11316
11317       /* if they in different places then copy */
11318       size = AOP_SIZE (result);
11319       offset = 0;
11320       while (size--)
11321         {
11322           aopPut (result,
11323                   aopGet (right, offset, FALSE, FALSE),
11324                   offset);
11325           offset++;
11326         }
11327       goto release;
11328     }
11329
11330   /* if the result is of type pointer */
11331   if (IS_PTR (ctype))
11332     {
11333
11334       int p_type;
11335       sym_link *type = operandType (right);
11336       sym_link *etype = getSpec (type);
11337
11338       /* pointer to generic pointer */
11339       if (IS_GENPTR (ctype))
11340         {
11341           if (IS_PTR (type))
11342             {
11343               p_type = DCL_TYPE (type);
11344             }
11345           else
11346             {
11347               if (SPEC_SCLS(etype)==S_REGISTER) {
11348                 // let's assume it is a generic pointer
11349                 p_type=GPOINTER;
11350               } else {
11351                 /* we have to go by the storage class */
11352                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11353               }
11354             }
11355
11356           /* the first two bytes are known */
11357           size = GPTRSIZE - 1;
11358           offset = 0;
11359           while (size--)
11360             {
11361               aopPut (result,
11362                       aopGet (right, offset, FALSE, FALSE),
11363                       offset);
11364               offset++;
11365             }
11366           /* the last byte depending on type */
11367             {
11368                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11369                 char gpValStr[10];
11370
11371                 if (gpVal == -1)
11372                 {
11373                     // pointerTypeToGPByte will have bitched.
11374                     exit(1);
11375                 }
11376
11377                 sprintf(gpValStr, "#0x%x", gpVal);
11378                 aopPut (result, gpValStr, GPTRSIZE - 1);
11379             }
11380           goto release;
11381         }
11382
11383       /* just copy the pointers */
11384       size = AOP_SIZE (result);
11385       offset = 0;
11386       while (size--)
11387         {
11388           aopPut (result,
11389                   aopGet (right, offset, FALSE, FALSE),
11390                   offset);
11391           offset++;
11392         }
11393       goto release;
11394     }
11395
11396   /* so we now know that the size of destination is greater
11397      than the size of the source */
11398   /* we move to result for the size of source */
11399   size = AOP_SIZE (right);
11400   offset = 0;
11401   while (size--)
11402     {
11403       aopPut (result,
11404               aopGet (right, offset, FALSE, FALSE),
11405               offset);
11406       offset++;
11407     }
11408
11409   /* now depending on the sign of the source && destination */
11410   size = AOP_SIZE (result) - AOP_SIZE (right);
11411   /* if unsigned or not an integral type */
11412   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11413     {
11414       while (size--)
11415         aopPut (result, zero, offset++);
11416     }
11417   else
11418     {
11419       /* we need to extend the sign :{ */
11420       char *l = aopGet (right, AOP_SIZE (right) - 1,
11421                         FALSE, FALSE);
11422       MOVA (l);
11423       emitcode ("rlc", "a");
11424       emitcode ("subb", "a,acc");
11425       while (size--)
11426         aopPut (result, "a", offset++);
11427     }
11428
11429   /* we are done hurray !!!! */
11430
11431 release:
11432   freeAsmop (result, NULL, ic, TRUE);
11433   freeAsmop (right, NULL, ic, TRUE);
11434 }
11435
11436 /*-----------------------------------------------------------------*/
11437 /* genDjnz - generate decrement & jump if not zero instrucion      */
11438 /*-----------------------------------------------------------------*/
11439 static int
11440 genDjnz (iCode * ic, iCode * ifx)
11441 {
11442   symbol *lbl, *lbl1;
11443   if (!ifx)
11444     return 0;
11445
11446   /* if the if condition has a false label
11447      then we cannot save */
11448   if (IC_FALSE (ifx))
11449     return 0;
11450
11451   /* if the minus is not of the form a = a - 1 */
11452   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11453       !IS_OP_LITERAL (IC_RIGHT (ic)))
11454     return 0;
11455
11456   if (operandLitValue (IC_RIGHT (ic)) != 1)
11457     return 0;
11458
11459   /* if the size of this greater than one then no
11460      saving */
11461   if (getSize (operandType (IC_RESULT (ic))) > 1)
11462     return 0;
11463
11464   /* otherwise we can save BIG */
11465
11466   D (emitcode (";", "genDjnz"));
11467
11468   lbl = newiTempLabel (NULL);
11469   lbl1 = newiTempLabel (NULL);
11470
11471   aopOp (IC_RESULT (ic), ic, FALSE);
11472
11473   if (AOP_NEEDSACC(IC_RESULT(ic)))
11474   {
11475       /* If the result is accessed indirectly via
11476        * the accumulator, we must explicitly write
11477        * it back after the decrement.
11478        */
11479       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11480
11481       if (strcmp(rByte, "a"))
11482       {
11483            /* Something is hopelessly wrong */
11484            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11485                    __FILE__, __LINE__);
11486            /* We can just give up; the generated code will be inefficient,
11487             * but what the hey.
11488             */
11489            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11490            return 0;
11491       }
11492       emitcode ("dec", "%s", rByte);
11493       aopPut (IC_RESULT (ic), rByte, 0);
11494       emitcode ("jnz", "%05d$", lbl->key + 100);
11495   }
11496   else if (IS_AOP_PREG (IC_RESULT (ic)))
11497     {
11498       emitcode ("dec", "%s",
11499                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11500       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11501       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11502       ifx->generated = 1;
11503       emitcode ("jnz", "%05d$", lbl->key + 100);
11504     }
11505   else
11506     {
11507       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11508                 lbl->key + 100);
11509     }
11510   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11511   emitLabel (lbl);
11512   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11513   emitLabel (lbl1);
11514
11515   if (!ifx->generated)
11516       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11517   ifx->generated = 1;
11518   return 1;
11519 }
11520
11521 /*-----------------------------------------------------------------*/
11522 /* genReceive - generate code for a receive iCode                  */
11523 /*-----------------------------------------------------------------*/
11524 static void
11525 genReceive (iCode * ic)
11526 {
11527   int size = getSize (operandType (IC_RESULT (ic)));
11528   int offset = 0;
11529
11530   D (emitcode (";", "genReceive"));
11531
11532   if (ic->argreg == 1)
11533     { /* first parameter */
11534       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11535            isOperandInPagedSpace (IC_RESULT (ic))) &&
11536           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11537            IS_TRUE_SYMOP (IC_RESULT (ic))))
11538         {
11539           regs *tempRegs[4];
11540           int receivingA = 0;
11541           int roffset = 0;
11542
11543           for (offset = 0; offset<size; offset++)
11544             if (!strcmp (fReturn[offset], "a"))
11545               receivingA = 1;
11546
11547           if (!receivingA)
11548             {
11549               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11550                 {
11551                   for (offset = size-1; offset>0; offset--)
11552                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11553                   emitcode("mov","a,%s", fReturn[0]);
11554                   _G.accInUse++;
11555                   aopOp (IC_RESULT (ic), ic, FALSE);
11556                   _G.accInUse--;
11557                   aopPut (IC_RESULT (ic), "a", offset);
11558                   for (offset = 1; offset<size; offset++)
11559                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11560                   goto release;
11561                 }
11562             }
11563           else
11564             {
11565               if (getTempRegs(tempRegs, size, ic))
11566                 {
11567                   for (offset = 0; offset<size; offset++)
11568                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11569                   aopOp (IC_RESULT (ic), ic, FALSE);
11570                   for (offset = 0; offset<size; offset++)
11571                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11572                   goto release;
11573                 }
11574             }
11575
11576           offset = fReturnSizeMCS51 - size;
11577           while (size--)
11578             {
11579               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11580                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11581               offset++;
11582             }
11583           aopOp (IC_RESULT (ic), ic, FALSE);
11584           size = AOP_SIZE (IC_RESULT (ic));
11585           offset = 0;
11586           while (size--)
11587             {
11588               emitcode ("pop", "acc");
11589               aopPut (IC_RESULT (ic), "a", offset++);
11590             }
11591         }
11592       else
11593         {
11594           _G.accInUse++;
11595           aopOp (IC_RESULT (ic), ic, FALSE);
11596           _G.accInUse--;
11597           assignResultValue (IC_RESULT (ic), NULL);
11598         }
11599     }
11600   else if (ic->argreg > 12)
11601     { /* bit parameters */
11602       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11603         {
11604           aopOp (IC_RESULT (ic), ic, FALSE);
11605           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11606           outBitC(IC_RESULT (ic));
11607         }
11608     }
11609   else
11610     { /* other parameters */
11611       int rb1off ;
11612       aopOp (IC_RESULT (ic), ic, FALSE);
11613       rb1off = ic->argreg;
11614       while (size--)
11615         {
11616           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11617         }
11618     }
11619
11620 release:
11621   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11622 }
11623
11624 /*-----------------------------------------------------------------*/
11625 /* genDummyRead - generate code for dummy read of volatiles        */
11626 /*-----------------------------------------------------------------*/
11627 static void
11628 genDummyRead (iCode * ic)
11629 {
11630   operand *op;
11631   int size, offset;
11632
11633   D (emitcode(";", "genDummyRead"));
11634
11635   op = IC_RIGHT (ic);
11636   if (op && IS_SYMOP (op))
11637     {
11638       aopOp (op, ic, FALSE);
11639
11640       /* if the result is a bit */
11641       if (AOP_TYPE (op) == AOP_CRY)
11642         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11643       else
11644         {
11645           /* bit variables done */
11646           /* general case */
11647           size = AOP_SIZE (op);
11648           offset = 0;
11649           while (size--)
11650           {
11651             MOVA (aopGet (op, offset, FALSE, FALSE));
11652             offset++;
11653           }
11654         }
11655
11656       freeAsmop (op, NULL, ic, TRUE);
11657     }
11658
11659   op = IC_LEFT (ic);
11660   if (op && IS_SYMOP (op))
11661     {
11662       aopOp (op, ic, FALSE);
11663
11664       /* if the result is a bit */
11665       if (AOP_TYPE (op) == AOP_CRY)
11666         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11667       else
11668         {
11669           /* bit variables done */
11670           /* general case */
11671           size = AOP_SIZE (op);
11672           offset = 0;
11673           while (size--)
11674           {
11675             MOVA (aopGet (op, offset, FALSE, FALSE));
11676             offset++;
11677           }
11678         }
11679
11680       freeAsmop (op, NULL, ic, TRUE);
11681     }
11682 }
11683
11684 /*-----------------------------------------------------------------*/
11685 /* genCritical - generate code for start of a critical sequence    */
11686 /*-----------------------------------------------------------------*/
11687 static void
11688 genCritical (iCode *ic)
11689 {
11690   symbol *tlbl = newiTempLabel (NULL);
11691
11692   D (emitcode(";", "genCritical"));
11693
11694   if (IC_RESULT (ic))
11695     {
11696       aopOp (IC_RESULT (ic), ic, TRUE);
11697       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11698       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11699       aopPut (IC_RESULT (ic), zero, 0);
11700       emitLabel (tlbl);
11701       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11702     }
11703   else
11704     {
11705       emitcode ("setb", "c");
11706       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11707       emitcode ("clr", "c");
11708       emitLabel (tlbl);
11709       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11710     }
11711 }
11712
11713 /*-----------------------------------------------------------------*/
11714 /* genEndCritical - generate code for end of a critical sequence   */
11715 /*-----------------------------------------------------------------*/
11716 static void
11717 genEndCritical (iCode *ic)
11718 {
11719   D(emitcode(";", "genEndCritical"));
11720
11721   if (IC_RIGHT (ic))
11722     {
11723       aopOp (IC_RIGHT (ic), ic, FALSE);
11724       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11725         {
11726           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11727           emitcode ("mov", "ea,c");
11728         }
11729       else
11730         {
11731           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11732             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11733           emitcode ("rrc", "a");
11734           emitcode ("mov", "ea,c");
11735         }
11736       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11737     }
11738   else
11739     {
11740       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11741       emitcode ("mov", "ea,c");
11742     }
11743 }
11744
11745 /*-----------------------------------------------------------------*/
11746 /* gen51Code - generate code for 8051 based controllers            */
11747 /*-----------------------------------------------------------------*/
11748 void
11749 gen51Code (iCode * lic)
11750 {
11751   iCode *ic;
11752   int cln = 0;
11753   /* int cseq = 0; */
11754
11755   _G.currentFunc = NULL;
11756   lineHead = lineCurr = NULL;
11757
11758   /* print the allocation information */
11759   if (allocInfo && currFunc)
11760     printAllocInfo (currFunc, codeOutBuf);
11761   /* if debug information required */
11762   if (options.debug && currFunc)
11763     {
11764       debugFile->writeFunction (currFunc, lic);
11765     }
11766   /* stack pointer name */
11767   if (options.useXstack)
11768     spname = "_spx";
11769   else
11770     spname = "sp";
11771
11772
11773   for (ic = lic; ic; ic = ic->next)
11774     {
11775       _G.current_iCode = ic;
11776
11777       if (ic->lineno && cln != ic->lineno)
11778         {
11779           if (options.debug)
11780             {
11781               debugFile->writeCLine (ic);
11782             }
11783           if (!options.noCcodeInAsm) {
11784             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11785                       printCLine(ic->filename, ic->lineno));
11786           }
11787           cln = ic->lineno;
11788         }
11789       #if 0
11790       if (ic->seqPoint && ic->seqPoint != cseq)
11791         {
11792           emitcode (";", "sequence point %d", ic->seqPoint);
11793           cseq = ic->seqPoint;
11794         }
11795       #endif
11796       if (options.iCodeInAsm) {
11797         char regsInUse[80];
11798         int i;
11799         char *iLine;
11800
11801         #if 0
11802         for (i=0; i<8; i++) {
11803           sprintf (&regsInUse[i],
11804                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11805         regsInUse[i]=0;
11806         #else
11807         strcpy (regsInUse, "--------");
11808         for (i=0; i < 8; i++) {
11809           if (bitVectBitValue (ic->rMask, i))
11810             {
11811               int offset = regs8051[i].offset;
11812               regsInUse[offset] = offset + '0'; /* show rMask */
11813             }
11814         #endif
11815         }
11816         iLine = printILine(ic);
11817         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11818         dbuf_free(iLine);
11819       }
11820       /* if the result is marked as
11821          spilt and rematerializable or code for
11822          this has already been generated then
11823          do nothing */
11824       if (resultRemat (ic) || ic->generated)
11825         continue;
11826
11827       /* depending on the operation */
11828       switch (ic->op)
11829         {
11830         case '!':
11831           genNot (ic);
11832           break;
11833
11834         case '~':
11835           genCpl (ic);
11836           break;
11837
11838         case UNARYMINUS:
11839           genUminus (ic);
11840           break;
11841
11842         case IPUSH:
11843           genIpush (ic);
11844           break;
11845
11846         case IPOP:
11847           /* IPOP happens only when trying to restore a
11848              spilt live range, if there is an ifx statement
11849              following this pop then the if statement might
11850              be using some of the registers being popped which
11851              would destory the contents of the register so
11852              we need to check for this condition and handle it */
11853           if (ic->next &&
11854               ic->next->op == IFX &&
11855               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11856             genIfx (ic->next, ic);
11857           else
11858             genIpop (ic);
11859           break;
11860
11861         case CALL:
11862           genCall (ic);
11863           break;
11864
11865         case PCALL:
11866           genPcall (ic);
11867           break;
11868
11869         case FUNCTION:
11870           genFunction (ic);
11871           break;
11872
11873         case ENDFUNCTION:
11874           genEndFunction (ic);
11875           break;
11876
11877         case RETURN:
11878           genRet (ic);
11879           break;
11880
11881         case LABEL:
11882           genLabel (ic);
11883           break;
11884
11885         case GOTO:
11886           genGoto (ic);
11887           break;
11888
11889         case '+':
11890           genPlus (ic);
11891           break;
11892
11893         case '-':
11894           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11895             genMinus (ic);
11896           break;
11897
11898         case '*':
11899           genMult (ic);
11900           break;
11901
11902         case '/':
11903           genDiv (ic);
11904           break;
11905
11906         case '%':
11907           genMod (ic);
11908           break;
11909
11910         case '>':
11911           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11912           break;
11913
11914         case '<':
11915           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11916           break;
11917
11918         case LE_OP:
11919         case GE_OP:
11920         case NE_OP:
11921
11922           /* note these two are xlated by algebraic equivalence
11923              in decorateType() in SDCCast.c */
11924           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11925                   "got '>=' or '<=' shouldn't have come here");
11926           break;
11927
11928         case EQ_OP:
11929           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11930           break;
11931
11932         case AND_OP:
11933           genAndOp (ic);
11934           break;
11935
11936         case OR_OP:
11937           genOrOp (ic);
11938           break;
11939
11940         case '^':
11941           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11942           break;
11943
11944         case '|':
11945           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11946           break;
11947
11948         case BITWISEAND:
11949           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11950           break;
11951
11952         case INLINEASM:
11953           genInline (ic);
11954           break;
11955
11956         case RRC:
11957           genRRC (ic);
11958           break;
11959
11960         case RLC:
11961           genRLC (ic);
11962           break;
11963
11964         case GETHBIT:
11965           genGetHbit (ic);
11966           break;
11967
11968         case GETABIT:
11969           genGetAbit (ic);
11970           break;
11971
11972         case GETBYTE:
11973           genGetByte (ic);
11974           break;
11975
11976         case GETWORD:
11977           genGetWord (ic);
11978           break;
11979
11980         case LEFT_OP:
11981           genLeftShift (ic);
11982           break;
11983
11984         case RIGHT_OP:
11985           genRightShift (ic);
11986           break;
11987
11988         case GET_VALUE_AT_ADDRESS:
11989           genPointerGet (ic,
11990                          hasInc (IC_LEFT (ic), ic,
11991                                  getSize (operandType (IC_RESULT (ic)))),
11992                          ifxForOp (IC_RESULT (ic), ic) );
11993           break;
11994
11995         case '=':
11996           if (POINTER_SET (ic))
11997             genPointerSet (ic,
11998                            hasInc (IC_RESULT (ic), ic,
11999                                    getSize (operandType (IC_RIGHT (ic)))));
12000           else
12001             genAssign (ic);
12002           break;
12003
12004         case IFX:
12005           genIfx (ic, NULL);
12006           break;
12007
12008         case ADDRESS_OF:
12009           genAddrOf (ic);
12010           break;
12011
12012         case JUMPTABLE:
12013           genJumpTab (ic);
12014           break;
12015
12016         case CAST:
12017           genCast (ic);
12018           break;
12019
12020         case RECEIVE:
12021           genReceive (ic);
12022           break;
12023
12024         case SEND:
12025           addSet (&_G.sendSet, ic);
12026           break;
12027
12028         case DUMMY_READ_VOLATILE:
12029           genDummyRead (ic);
12030           break;
12031
12032         case CRITICAL:
12033           genCritical (ic);
12034           break;
12035
12036         case ENDCRITICAL:
12037           genEndCritical (ic);
12038           break;
12039
12040         case SWAP:
12041           genSwap (ic);
12042           break;
12043
12044         default:
12045           ic = ic;
12046         }
12047     }
12048
12049   _G.current_iCode = NULL;
12050
12051   /* now we are ready to call the
12052      peep hole optimizer */
12053   if (!options.nopeep)
12054     peepHole (&lineHead);
12055
12056   /* now do the actual printing */
12057   printLine (lineHead, codeOutBuf);
12058   return;
12059 }