* src/SDCCglobl.h,
[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.noGenComments) {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 static void saveRBank (int, iCode *, bool);
123
124 #define RESULTONSTACK(x) \
125                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
126                          IC_RESULT(x)->aop->type == AOP_STK )
127
128 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
129 #define MOVB(x)  movb(x)
130
131 #define CLRC     emitcode("clr","c")
132 #define SETC     emitcode("setb","c")
133
134 static lineNode *lineHead = NULL;
135 static lineNode *lineCurr = NULL;
136
137 static unsigned char SLMask[] =
138 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
139  0xE0, 0xC0, 0x80, 0x00};
140 static unsigned char SRMask[] =
141 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
142  0x07, 0x03, 0x01, 0x00};
143
144 #define LSB     0
145 #define MSB16   1
146 #define MSB24   2
147 #define MSB32   3
148
149 /*-----------------------------------------------------------------*/
150 /* emitcode - writes the code into a file : for now it is simple    */
151 /*-----------------------------------------------------------------*/
152 void
153 emitcode (const char *inst, const char *fmt,...)
154 {
155   va_list ap;
156   struct dbuf_s dbuf;
157   const char *lbp, *lb;
158
159   dbuf_init (&dbuf, INITIAL_INLINEASM);
160
161   va_start (ap, fmt);
162
163   if (inst && *inst)
164     {
165       dbuf_append_str (&dbuf, inst);
166
167       if (fmt && *fmt)
168         {
169           dbuf_append_char (&dbuf, '\t');
170           dbuf_tvprintf (&dbuf, fmt, ap);
171         }
172     }
173   else
174     {
175       dbuf_tvprintf (&dbuf, fmt, ap);
176     }
177
178   lbp = lb = dbuf_c_str(&dbuf);
179
180   while (isspace ((unsigned char)*lbp))
181     {
182       lbp++;
183     }
184
185   if (lbp && *lbp)
186     {
187       rtrackUpdate (lbp);
188
189       lineCurr = (lineCurr ?
190                   connectLine (lineCurr, newLineNode (lb)) :
191                   (lineHead = newLineNode (lb)));
192     }
193
194   lineCurr->isInline = _G.inLine;
195   lineCurr->isDebug = _G.debugLine;
196   lineCurr->ic = _G.current_iCode;
197   lineCurr->isComment = (*lbp==';');
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       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
958       aop->size = 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           aop = op->aop = sym->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           aop = op->aop = sym->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
1496   if (aop->size && offset > (aop->size - 1))
1497     {
1498       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1499               "aopPut got offset > aop->size");
1500       exit (1);
1501     }
1502
1503   /* will assign value to value */
1504   /* depending on where it is ofcourse */
1505   switch (aop->type)
1506     {
1507     case AOP_DUMMY:
1508       MOVA (s);         /* read s in case it was volatile */
1509       accuse = TRUE;
1510       break;
1511
1512     case AOP_DIR:
1513       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1514         {
1515           SNPRINTF (buffer, sizeof(buffer),
1516                     "(%s >> %d)",
1517                     aop->aopu.aop_dir, offset * 8);
1518         }
1519       else if (offset)
1520         {
1521           SNPRINTF (buffer, sizeof(buffer),
1522                     "(%s + %d)",
1523                     aop->aopu.aop_dir, offset);
1524         }
1525       else
1526         {
1527           SNPRINTF (buffer, sizeof(buffer),
1528                     "%s",
1529                     aop->aopu.aop_dir);
1530         }
1531
1532       if (strcmp (buffer, s) || bvolatile)
1533         {
1534           emitcode ("mov", "%s,%s", buffer, s);
1535         }
1536       if (!strcmp (buffer, "acc"))
1537         {
1538           accuse = TRUE;
1539         }
1540       break;
1541
1542     case AOP_REG:
1543       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1544           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1545         {
1546           if (*s == '@' ||
1547               strcmp (s, "r0") == 0 ||
1548               strcmp (s, "r1") == 0 ||
1549               strcmp (s, "r2") == 0 ||
1550               strcmp (s, "r3") == 0 ||
1551               strcmp (s, "r4") == 0 ||
1552               strcmp (s, "r5") == 0 ||
1553               strcmp (s, "r6") == 0 ||
1554               strcmp (s, "r7") == 0)
1555             {
1556               emitcode ("mov", "%s,%s",
1557                         aop->aopu.aop_reg[offset]->dname, s);
1558             }
1559           else
1560             {
1561               emitcode ("mov", "%s,%s",
1562                         aop->aopu.aop_reg[offset]->name, s);
1563             }
1564         }
1565       break;
1566
1567     case AOP_DPTR:
1568       if (aop->code)
1569         {
1570           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1571                   "aopPut writing to code space");
1572           exit (1);
1573         }
1574
1575       while (offset > aop->coff)
1576         {
1577           aop->coff++;
1578           emitcode ("inc", "dptr");
1579         }
1580
1581       while (offset < aop->coff)
1582         {
1583           aop->coff--;
1584           emitcode ("lcall", "__decdptr");
1585         }
1586
1587       aop->coff = offset;
1588
1589       /* if not in accumulator */
1590       MOVA (s);
1591
1592       emitcode ("movx", "@dptr,a");
1593       break;
1594
1595     case AOP_R0:
1596     case AOP_R1:
1597       while (offset > aop->coff)
1598         {
1599           aop->coff++;
1600           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1601         }
1602       while (offset < aop->coff)
1603         {
1604           aop->coff--;
1605           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1606         }
1607       aop->coff = offset;
1608
1609       if (aop->paged)
1610         {
1611           MOVA (s);
1612           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1613         }
1614       else if (*s == '@')
1615         {
1616           MOVA (s);
1617           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1618         }
1619       else if (strcmp (s, "r0") == 0 ||
1620                strcmp (s, "r1") == 0 ||
1621                strcmp (s, "r2") == 0 ||
1622                strcmp (s, "r3") == 0 ||
1623                strcmp (s, "r4") == 0 ||
1624                strcmp (s, "r5") == 0 ||
1625                strcmp (s, "r6") == 0 ||
1626                strcmp (s, "r7") == 0)
1627         {
1628           char buffer[10];
1629           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1630           emitcode ("mov", "@%s,%s",
1631                     aop->aopu.aop_ptr->name, buffer);
1632         }
1633       else
1634         {
1635           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1636         }
1637       break;
1638
1639     case AOP_STK:
1640       if (strcmp (s, "a") == 0)
1641         {
1642           emitcode ("push", "acc");
1643         }
1644       else if (*s=='@')
1645         {
1646           MOVA(s);
1647           emitcode ("push", "acc");
1648         }
1649       else if (strcmp (s, "r0") == 0 ||
1650                strcmp (s, "r1") == 0 ||
1651                strcmp (s, "r2") == 0 ||
1652                strcmp (s, "r3") == 0 ||
1653                strcmp (s, "r4") == 0 ||
1654                strcmp (s, "r5") == 0 ||
1655                strcmp (s, "r6") == 0 ||
1656                strcmp (s, "r7") == 0)
1657         {
1658           char buffer[10];
1659           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1660           emitcode ("push", buffer);
1661         }
1662       else
1663         {
1664           emitcode ("push", s);
1665         }
1666
1667       break;
1668
1669     case AOP_CRY:
1670       /* if result no bit variable */
1671       if (!aop->aopu.aop_dir)
1672         {
1673           assert (!strcmp (s, "c"));
1674           /* inefficient: move carry into A and use jz/jnz */
1675           emitcode ("clr", "a");
1676           emitcode ("rlc", "a");
1677           accuse = TRUE;
1678         }
1679       else if (s == zero)
1680           emitcode ("clr", "%s", aop->aopu.aop_dir);
1681       else if (s == one)
1682           emitcode ("setb", "%s", aop->aopu.aop_dir);
1683       else if (!strcmp (s, "c"))
1684           emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1685       else if (strcmp (s, aop->aopu.aop_dir))
1686         {
1687           MOVA (s);
1688           /* set C, if a >= 1 */
1689           emitcode ("add", "a,#0xff");
1690           emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1691         }
1692       break;
1693
1694     case AOP_STR:
1695       aop->coff = offset;
1696       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1697         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1698       break;
1699
1700     case AOP_ACC:
1701       accuse = TRUE;
1702       aop->coff = offset;
1703       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1704         break;
1705
1706       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1707         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1708       break;
1709
1710     default:
1711       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1712               "aopPut got unsupported aop->type");
1713       exit (1);
1714     }
1715
1716     return accuse;
1717 }
1718
1719
1720 #if 0
1721 /*-----------------------------------------------------------------*/
1722 /* pointToEnd :- points to the last byte of the operand            */
1723 /*-----------------------------------------------------------------*/
1724 static void
1725 pointToEnd (asmop * aop)
1726 {
1727   int count;
1728   if (!aop)
1729     return;
1730
1731   aop->coff = count = (aop->size - 1);
1732   switch (aop->type)
1733     {
1734     case AOP_R0:
1735     case AOP_R1:
1736       while (count--)
1737         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1738       break;
1739     case AOP_DPTR:
1740       while (count--)
1741         emitcode ("inc", "dptr");
1742       break;
1743     }
1744
1745 }
1746 #endif
1747
1748 /*-----------------------------------------------------------------*/
1749 /* reAdjustPreg - points a register back to where it should        */
1750 /*-----------------------------------------------------------------*/
1751 static void
1752 reAdjustPreg (asmop * aop)
1753 {
1754   if ((aop->coff==0) || (aop->size <= 1))
1755     return;
1756
1757   switch (aop->type)
1758     {
1759     case AOP_R0:
1760     case AOP_R1:
1761       while (aop->coff--)
1762         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1763       break;
1764     case AOP_DPTR:
1765       while (aop->coff--)
1766         {
1767           emitcode ("lcall", "__decdptr");
1768         }
1769       break;
1770     }
1771   aop->coff = 0;
1772 }
1773
1774 /*-----------------------------------------------------------------*/
1775 /* opIsGptr: returns non-zero if the passed operand is       */
1776 /* a generic pointer type.             */
1777 /*-----------------------------------------------------------------*/
1778 static int
1779 opIsGptr (operand * op)
1780 {
1781   sym_link *type = operandType (op);
1782
1783   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1784     {
1785       return 1;
1786     }
1787   return 0;
1788 }
1789
1790 /*-----------------------------------------------------------------*/
1791 /* getDataSize - get the operand data size                         */
1792 /*-----------------------------------------------------------------*/
1793 static int
1794 getDataSize (operand * op)
1795 {
1796   int size;
1797   size = AOP_SIZE (op);
1798   if (size == GPTRSIZE)
1799     {
1800       sym_link *type = operandType (op);
1801       if (IS_GENPTR (type))
1802         {
1803           /* generic pointer; arithmetic operations
1804            * should ignore the high byte (pointer type).
1805            */
1806           size--;
1807         }
1808     }
1809   return size;
1810 }
1811
1812 /*-----------------------------------------------------------------*/
1813 /* outAcc - output Acc                                             */
1814 /*-----------------------------------------------------------------*/
1815 static void
1816 outAcc (operand * result)
1817 {
1818   int size, offset;
1819   size = getDataSize (result);
1820   if (size)
1821     {
1822       aopPut (result, "a", 0);
1823       size--;
1824       offset = 1;
1825       /* unsigned or positive */
1826       while (size--)
1827         {
1828           aopPut (result, zero, offset++);
1829         }
1830     }
1831 }
1832
1833 /*-----------------------------------------------------------------*/
1834 /* outBitC - output a bit C                                        */
1835 /*-----------------------------------------------------------------*/
1836 static void
1837 outBitC (operand * result)
1838 {
1839   /* if the result is bit */
1840   if (AOP_TYPE (result) == AOP_CRY)
1841     {
1842       aopPut (result, "c", 0);
1843     }
1844   else
1845     {
1846       emitcode ("clr", "a");
1847       emitcode ("rlc", "a");
1848       outAcc (result);
1849     }
1850 }
1851
1852 /*-----------------------------------------------------------------*/
1853 /* toBoolean - emit code for orl a,operator(sizeop)                */
1854 /*-----------------------------------------------------------------*/
1855 static void
1856 toBoolean (operand * oper)
1857 {
1858   int size = AOP_SIZE (oper) - 1;
1859   int offset = 1;
1860   bool AccUsed = FALSE;
1861   bool pushedB;
1862
1863   while (!AccUsed && size--)
1864     {
1865       AccUsed |= aopGetUsesAcc(oper, offset++);
1866     }
1867
1868   size = AOP_SIZE (oper) - 1;
1869   offset = 1;
1870   MOVA (aopGet (oper, 0, FALSE, FALSE));
1871   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1872     {
1873       pushedB = pushB ();
1874       emitcode("mov", "b,a");
1875       while (--size)
1876         {
1877           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1878           emitcode ("orl", "b,a");
1879         }
1880       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1881       emitcode ("orl", "a,b");
1882       popB (pushedB);
1883     }
1884   else
1885     {
1886       while (size--)
1887         {
1888           emitcode ("orl", "a,%s",
1889                     aopGet (oper, offset++, FALSE, FALSE));
1890         }
1891     }
1892 }
1893
1894 /*-----------------------------------------------------------------*/
1895 /* toCarry - make boolean and move into carry                      */
1896 /*-----------------------------------------------------------------*/
1897 static void
1898 toCarry (operand * oper)
1899 {
1900   /* if the operand is a literal then
1901      we know what the value is */
1902   if (AOP_TYPE (oper) == AOP_LIT)
1903     {
1904       if ((int) operandLitValue (oper))
1905         SETC;
1906       else
1907         CLRC;
1908     }
1909   else if (AOP_TYPE (oper) == AOP_CRY)
1910     {
1911       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1912     }
1913   else
1914     {
1915       /* or the operand into a */
1916       toBoolean (oper);
1917       /* set C, if a >= 1 */
1918       emitcode ("add", "a,#0xff");
1919     }
1920 }
1921
1922 /*-----------------------------------------------------------------*/
1923 /* assignBit - assign operand to bit operand                       */
1924 /*-----------------------------------------------------------------*/
1925 static void
1926 assignBit (operand * result, operand * right)
1927 {
1928   /* if the right side is a literal then
1929      we know what the value is */
1930   if (AOP_TYPE (right) == AOP_LIT)
1931     {
1932       if ((int) operandLitValue (right))
1933         aopPut (result, one, 0);
1934       else
1935         aopPut (result, zero, 0);
1936     }
1937   else
1938     {
1939       toCarry (right);
1940       aopPut (result, "c", 0);
1941     }
1942 }
1943
1944
1945 /*-------------------------------------------------------------------*/
1946 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1947 /*-------------------------------------------------------------------*/
1948 static char *
1949 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1950 {
1951   char * l;
1952
1953   if (aopGetUsesAcc (oper, offset))
1954     {
1955       emitcode("mov", "b,a");
1956       MOVA (aopGet (oper, offset, bit16, dname));
1957       emitcode("xch", "a,b");
1958       aopPut (oper, "a", offset);
1959       emitcode("xch", "a,b");
1960       l = "b";
1961     }
1962   else
1963     {
1964       l = aopGet (oper, offset, bit16, dname);
1965       emitcode("xch", "a,%s", l);
1966     }
1967   return l;
1968 }
1969
1970
1971 /*-----------------------------------------------------------------*/
1972 /* genNot - generate code for ! operation                          */
1973 /*-----------------------------------------------------------------*/
1974 static void
1975 genNot (iCode * ic)
1976 {
1977   symbol *tlbl;
1978
1979   D (emitcode (";", "genNot"));
1980
1981   /* assign asmOps to operand & result */
1982   aopOp (IC_LEFT (ic), ic, FALSE);
1983   aopOp (IC_RESULT (ic), ic, TRUE);
1984
1985   /* if in bit space then a special case */
1986   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1987     {
1988       /* if left==result then cpl bit */
1989       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
1990         {
1991           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1992         }
1993       else
1994         {
1995           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1996           emitcode ("cpl", "c");
1997           outBitC (IC_RESULT (ic));
1998         }
1999       goto release;
2000     }
2001
2002   toBoolean (IC_LEFT (ic));
2003
2004   /* set C, if a == 0 */
2005   tlbl = newiTempLabel (NULL);
2006   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2007   emitLabel (tlbl);
2008   outBitC (IC_RESULT (ic));
2009
2010 release:
2011   /* release the aops */
2012   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2013   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2014 }
2015
2016
2017 /*-----------------------------------------------------------------*/
2018 /* genCpl - generate code for complement                           */
2019 /*-----------------------------------------------------------------*/
2020 static void
2021 genCpl (iCode * ic)
2022 {
2023   int offset = 0;
2024   int size;
2025   symbol *tlbl;
2026   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2027
2028   D(emitcode (";", "genCpl"));
2029
2030   /* assign asmOps to operand & result */
2031   aopOp (IC_LEFT (ic), ic, FALSE);
2032   aopOp (IC_RESULT (ic), ic, TRUE);
2033
2034   /* special case if in bit space */
2035   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2036     {
2037       char *l;
2038
2039       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2040           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2041         {
2042           /* promotion rules are responsible for this strange result:
2043              bit -> int -> ~int -> bit
2044              uchar -> int -> ~int -> bit
2045           */
2046           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2047           goto release;
2048         }
2049
2050       tlbl=newiTempLabel(NULL);
2051       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2052       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2053           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2054           IS_AOP_PREG (IC_LEFT (ic)))
2055         {
2056           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2057         }
2058       else
2059         {
2060           MOVA (l);
2061           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2062         }
2063       emitLabel (tlbl);
2064       outBitC (IC_RESULT(ic));
2065       goto release;
2066     }
2067
2068   size = AOP_SIZE (IC_RESULT (ic));
2069   while (size--)
2070     {
2071       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2072       MOVA (l);
2073       emitcode ("cpl", "a");
2074       aopPut (IC_RESULT (ic), "a", offset++);
2075     }
2076
2077
2078 release:
2079   /* release the aops */
2080   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2081   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2082 }
2083
2084 /*-----------------------------------------------------------------*/
2085 /* genUminusFloat - unary minus for floating points                */
2086 /*-----------------------------------------------------------------*/
2087 static void
2088 genUminusFloat (operand * op, operand * result)
2089 {
2090   int size, offset = 0;
2091   char *l;
2092
2093   D (emitcode (";", "genUminusFloat"));
2094
2095   /* for this we just copy and then flip the bit */
2096
2097   size = AOP_SIZE (op) - 1;
2098
2099   while (size--)
2100     {
2101       aopPut (result,
2102               aopGet (op, offset, FALSE, FALSE),
2103               offset);
2104       offset++;
2105     }
2106
2107   l = aopGet (op, offset, FALSE, FALSE);
2108   MOVA (l);
2109
2110   emitcode ("cpl", "acc.7");
2111   aopPut (result, "a", offset);
2112 }
2113
2114 /*-----------------------------------------------------------------*/
2115 /* genUminus - unary minus code generation                         */
2116 /*-----------------------------------------------------------------*/
2117 static void
2118 genUminus (iCode * ic)
2119 {
2120   int offset, size;
2121   sym_link *optype;
2122
2123   D (emitcode (";", "genUminus"));
2124
2125   /* assign asmops */
2126   aopOp (IC_LEFT (ic), ic, FALSE);
2127   aopOp (IC_RESULT (ic), ic, TRUE);
2128
2129   /* if both in bit space then special
2130      case */
2131   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2132       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2133     {
2134
2135       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2136       emitcode ("cpl", "c");
2137       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2138       goto release;
2139     }
2140
2141   optype = operandType (IC_LEFT (ic));
2142
2143   /* if float then do float stuff */
2144   if (IS_FLOAT (optype))
2145     {
2146       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2147       goto release;
2148     }
2149
2150   /* otherwise subtract from zero */
2151   size = AOP_SIZE (IC_LEFT (ic));
2152   offset = 0;
2153   while (size--)
2154     {
2155       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2156       if (!strcmp (l, "a"))
2157         {
2158           if (offset == 0)
2159             SETC;
2160           emitcode ("cpl", "a");
2161           emitcode ("addc", "a,#0");
2162         }
2163       else
2164         {
2165           if (offset == 0)
2166             CLRC;
2167           emitcode ("clr", "a");
2168           emitcode ("subb", "a,%s", l);
2169         }
2170       aopPut (IC_RESULT (ic), "a", offset++);
2171     }
2172
2173   /* if any remaining bytes in the result */
2174   /* we just need to propagate the sign   */
2175   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2176     {
2177       emitcode ("rlc", "a");
2178       emitcode ("subb", "a,acc");
2179       while (size--)
2180         aopPut (IC_RESULT (ic), "a", offset++);
2181     }
2182
2183 release:
2184   /* release the aops */
2185   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2186   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2187 }
2188
2189 /*-----------------------------------------------------------------*/
2190 /* saveRegisters - will look for a call and save the registers     */
2191 /*-----------------------------------------------------------------*/
2192 static void
2193 saveRegisters (iCode * lic)
2194 {
2195   int i;
2196   iCode *ic;
2197   bitVect *rsave;
2198
2199   /* look for call */
2200   for (ic = lic; ic; ic = ic->next)
2201     if (ic->op == CALL || ic->op == PCALL)
2202       break;
2203
2204   if (!ic)
2205     {
2206       fprintf (stderr, "found parameter push with no function call\n");
2207       return;
2208     }
2209
2210   /* if the registers have been saved already or don't need to be then
2211      do nothing */
2212   if (ic->regsSaved)
2213     return;
2214   if (IS_SYMOP(IC_LEFT(ic)) &&
2215       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2216        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2217     return;
2218
2219   /* save the registers in use at this time but skip the
2220      ones for the result */
2221   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2222                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2223
2224   ic->regsSaved = 1;
2225   if (options.useXstack)
2226     {
2227       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2228       int nBits = bitVectnBitsOn (rsavebits);
2229       int count = bitVectnBitsOn (rsave);
2230
2231       if (nBits != 0)
2232         {
2233           count = count - nBits + 1;
2234           /* remove all but the first bits as they are pushed all at once */
2235           rsave = bitVectCplAnd (rsave, rsavebits);
2236           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2237         }
2238
2239       if (count == 1)
2240         {
2241           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2242           if (reg->type == REG_BIT)
2243             {
2244               emitcode ("mov", "a,%s", reg->base);
2245             }
2246           else
2247             {
2248               emitcode ("mov", "a,%s", reg->name);
2249             }
2250           emitcode ("mov", "r0,%s", spname);
2251           emitcode ("inc", "%s", spname);// allocate before use
2252           emitcode ("movx", "@r0,a");
2253           if (bitVectBitValue (rsave, R0_IDX))
2254             emitcode ("mov", "r0,a");
2255         }
2256       else if (count != 0)
2257         {
2258           if (bitVectBitValue (rsave, R0_IDX))
2259             {
2260               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2261             }
2262           emitcode ("mov", "r0,%s", spname);
2263           MOVA ("r0");
2264           emitcode ("add", "a,#%d", count);
2265           emitcode ("mov", "%s,a", spname);
2266           for (i = 0; i < mcs51_nRegs; i++)
2267             {
2268               if (bitVectBitValue (rsave, i))
2269                 {
2270                   regs * reg = REG_WITH_INDEX (i);
2271                   if (i == R0_IDX)
2272                     {
2273                       emitcode ("pop", "acc");
2274                       emitcode ("push", "acc");
2275                     }
2276                   else if (reg->type == REG_BIT)
2277                     {
2278                       emitcode ("mov", "a,%s", reg->base);
2279                     }
2280                   else
2281                     {
2282                       emitcode ("mov", "a,%s", reg->name);
2283                     }
2284                   emitcode ("movx", "@r0,a");
2285                   if (--count)
2286                     {
2287                       emitcode ("inc", "r0");
2288                     }
2289                 }
2290             }
2291           if (bitVectBitValue (rsave, R0_IDX))
2292             {
2293               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2294             }
2295         }
2296     }
2297   else
2298     {
2299       bool bits_pushed = FALSE;
2300       for (i = 0; i < mcs51_nRegs; i++)
2301         {
2302           if (bitVectBitValue (rsave, i))
2303             {
2304               bits_pushed = pushReg (i, bits_pushed);
2305             }
2306         }
2307     }
2308 }
2309
2310 /*-----------------------------------------------------------------*/
2311 /* unsaveRegisters - pop the pushed registers                      */
2312 /*-----------------------------------------------------------------*/
2313 static void
2314 unsaveRegisters (iCode * ic)
2315 {
2316   int i;
2317   bitVect *rsave;
2318
2319   /* restore the registers in use at this time but skip the
2320      ones for the result */
2321   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2322                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2323
2324   if (options.useXstack)
2325     {
2326       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2327       int nBits = bitVectnBitsOn (rsavebits);
2328       int count = bitVectnBitsOn (rsave);
2329
2330       if (nBits != 0)
2331         {
2332           count = count - nBits + 1;
2333           /* remove all but the first bits as they are popped all at once */
2334           rsave = bitVectCplAnd (rsave, rsavebits);
2335           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2336         }
2337
2338       if (count == 1)
2339         {
2340           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2341           emitcode ("mov", "r0,%s", spname);
2342           emitcode ("dec", "r0");
2343           emitcode ("movx", "a,@r0");
2344           if (reg->type == REG_BIT)
2345             {
2346               emitcode ("mov", "%s,a", reg->base);
2347             }
2348           else
2349             {
2350               emitcode ("mov", "%s,a", reg->name);
2351             }
2352           emitcode ("dec", "%s", spname);
2353         }
2354       else if (count != 0)
2355         {
2356           emitcode ("mov", "r0,%s", spname);
2357           for (i = mcs51_nRegs; i >= 0; i--)
2358             {
2359               if (bitVectBitValue (rsave, i))
2360                 {
2361                   regs * reg = REG_WITH_INDEX (i);
2362                   emitcode ("dec", "r0");
2363                   emitcode ("movx", "a,@r0");
2364                   if (i == R0_IDX)
2365                     {
2366                       emitcode ("push", "acc");
2367                     }
2368                   else if (reg->type == REG_BIT)
2369                     {
2370                       emitcode ("mov", "%s,a", reg->base);
2371                     }
2372                   else
2373                     {
2374                       emitcode ("mov", "%s,a", reg->name);
2375                     }
2376                 }
2377             }
2378           emitcode ("mov", "%s,r0", spname);
2379           if (bitVectBitValue (rsave, R0_IDX))
2380             {
2381               emitcode ("pop", "ar0");
2382             }
2383         }
2384     }
2385   else
2386     {
2387       bool bits_popped = FALSE;
2388       for (i = mcs51_nRegs; i >= 0; i--)
2389         {
2390           if (bitVectBitValue (rsave, i))
2391             {
2392               bits_popped = popReg (i, bits_popped);
2393             }
2394         }
2395     }
2396 }
2397
2398
2399 /*-----------------------------------------------------------------*/
2400 /* pushSide -                                                      */
2401 /*-----------------------------------------------------------------*/
2402 static void
2403 pushSide (operand * oper, int size)
2404 {
2405   int offset = 0;
2406   while (size--)
2407     {
2408       char *l = aopGet (oper, offset++, FALSE, TRUE);
2409       if (AOP_TYPE (oper) != AOP_REG &&
2410           AOP_TYPE (oper) != AOP_DIR &&
2411           strcmp (l, "a"))
2412         {
2413           MOVA (l);
2414           emitcode ("push", "acc");
2415         }
2416       else
2417         {
2418           emitcode ("push", "%s", l);
2419         }
2420     }
2421 }
2422
2423 /*-----------------------------------------------------------------*/
2424 /* assignResultValue - also indicates if acc is in use afterwards  */
2425 /*-----------------------------------------------------------------*/
2426 static bool
2427 assignResultValue (operand * oper, operand * func)
2428 {
2429   int offset = 0;
2430   int size = AOP_SIZE (oper);
2431   bool accuse = FALSE;
2432   bool pushedA = FALSE;
2433
2434   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2435     {
2436       outBitC (oper);
2437       return FALSE;
2438     }
2439
2440   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2441     {
2442       emitcode ("push", "acc");
2443       pushedA = TRUE;
2444     }
2445   while (size--)
2446     {
2447       if ((offset == 3) && pushedA)
2448         emitcode ("pop", "acc");
2449       accuse |= aopPut (oper, fReturn[offset], offset);
2450       offset++;
2451     }
2452   return accuse;
2453 }
2454
2455
2456 /*-----------------------------------------------------------------*/
2457 /* genXpush - pushes onto the external stack                       */
2458 /*-----------------------------------------------------------------*/
2459 static void
2460 genXpush (iCode * ic)
2461 {
2462   asmop *aop = newAsmop (0);
2463   regs *r;
2464   int size, offset = 0;
2465
2466   D (emitcode (";", "genXpush"));
2467
2468   aopOp (IC_LEFT (ic), ic, FALSE);
2469   r = getFreePtr (ic, &aop, FALSE);
2470
2471   size = AOP_SIZE (IC_LEFT (ic));
2472
2473   if (size == 1)
2474     {
2475       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2476       emitcode ("mov", "%s,%s", r->name, spname);
2477       emitcode ("inc", "%s", spname); // allocate space first
2478       emitcode ("movx", "@%s,a", r->name);
2479     }
2480   else
2481     {
2482       // allocate space first
2483       emitcode ("mov", "%s,%s", r->name, spname);
2484       MOVA (r->name);
2485       emitcode ("add", "a,#%d", size);
2486       emitcode ("mov", "%s,a", spname);
2487
2488       while (size--)
2489         {
2490           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2491           emitcode ("movx", "@%s,a", r->name);
2492           emitcode ("inc", "%s", r->name);
2493         }
2494     }
2495
2496   freeAsmop (NULL, aop, ic, TRUE);
2497   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2498 }
2499
2500 /*-----------------------------------------------------------------*/
2501 /* genIpush - generate code for pushing this gets a little complex */
2502 /*-----------------------------------------------------------------*/
2503 static void
2504 genIpush (iCode * ic)
2505 {
2506   int size, offset = 0;
2507   char *l;
2508   char *prev = "";
2509
2510   D (emitcode (";", "genIpush"));
2511
2512   /* if this is not a parm push : ie. it is spill push
2513      and spill push is always done on the local stack */
2514   if (!ic->parmPush)
2515     {
2516
2517       /* and the item is spilt then do nothing */
2518       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2519         return;
2520
2521       aopOp (IC_LEFT (ic), ic, FALSE);
2522       size = AOP_SIZE (IC_LEFT (ic));
2523       /* push it on the stack */
2524       while (size--)
2525         {
2526           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2527           if (*l == '#')
2528             {
2529               MOVA (l);
2530               l = "acc";
2531             }
2532           emitcode ("push", "%s", l);
2533         }
2534       return;
2535     }
2536
2537   /* this is a parameter push: in this case we call
2538      the routine to find the call and save those
2539      registers that need to be saved */
2540   saveRegisters (ic);
2541
2542   /* if use external stack then call the external
2543      stack pushing routine */
2544   if (options.useXstack)
2545     {
2546       genXpush (ic);
2547       return;
2548     }
2549
2550   /* then do the push */
2551   aopOp (IC_LEFT (ic), ic, FALSE);
2552
2553   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2554   size = AOP_SIZE (IC_LEFT (ic));
2555
2556   while (size--)
2557     {
2558       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2559       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2560           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2561         {
2562           if (strcmp (l, prev) || *l == '@')
2563             MOVA (l);
2564           emitcode ("push", "acc");
2565         }
2566       else
2567         {
2568           emitcode ("push", "%s", l);
2569         }
2570       prev = l;
2571     }
2572
2573   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2574 }
2575
2576 /*-----------------------------------------------------------------*/
2577 /* genIpop - recover the registers: can happen only for spilling   */
2578 /*-----------------------------------------------------------------*/
2579 static void
2580 genIpop (iCode * ic)
2581 {
2582   int size, offset;
2583
2584   D (emitcode (";", "genIpop"));
2585
2586   /* if the temp was not pushed then */
2587   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2588     return;
2589
2590   aopOp (IC_LEFT (ic), ic, FALSE);
2591   size = AOP_SIZE (IC_LEFT (ic));
2592   offset = (size - 1);
2593   while (size--)
2594     {
2595       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2596                                      FALSE, TRUE));
2597     }
2598
2599   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2600 }
2601
2602 /*-----------------------------------------------------------------*/
2603 /* saveRBank - saves an entire register bank on the stack          */
2604 /*-----------------------------------------------------------------*/
2605 static void
2606 saveRBank (int bank, iCode * ic, bool pushPsw)
2607 {
2608   int i;
2609   int count = 8 + ((mcs51_nRegs > 8) ? 1 : 0) + (pushPsw ? 1 : 0);
2610   asmop *aop = NULL;
2611   regs *r = NULL;
2612
2613   if (options.useXstack)
2614     {
2615       if (!ic)
2616         {
2617           /* Assume r0 is available for use. */
2618           r = REG_WITH_INDEX (R0_IDX);;
2619         }
2620       else
2621         {
2622           aop = newAsmop (0);
2623           r = getFreePtr (ic, &aop, FALSE);
2624         }
2625       // allocate space first
2626       emitcode ("mov", "%s,%s", r->name, spname);
2627       MOVA (r->name);
2628       emitcode ("add", "a,#%d", count);
2629       emitcode ("mov", "%s,a", spname);
2630     }
2631
2632   for (i = 0; i < 8; i++)
2633     {
2634       if (options.useXstack)
2635         {
2636           emitcode ("mov", "a,(%s+%d)",
2637                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2638           emitcode ("movx", "@%s,a", r->name);
2639           if (--count)
2640             emitcode ("inc", "%s", r->name);
2641         }
2642       else
2643         emitcode ("push", "(%s+%d)",
2644                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2645     }
2646
2647   if (mcs51_nRegs > 8)
2648     {
2649       if (options.useXstack)
2650         {
2651           emitcode ("mov", "a,bits");
2652           emitcode ("movx", "@%s,a", r->name);
2653           if (--count)
2654             emitcode ("inc", "%s", r->name);
2655         }
2656       else
2657         {
2658           emitcode ("push", "bits");
2659         }
2660       BitBankUsed = 1;
2661     }
2662
2663   if (pushPsw)
2664     {
2665       if (options.useXstack)
2666         {
2667           emitcode ("mov", "a,psw");
2668           emitcode ("movx", "@%s,a", r->name);
2669         }
2670       else
2671         {
2672           emitcode ("push", "psw");
2673         }
2674
2675       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2676     }
2677
2678   if (aop)
2679     {
2680       freeAsmop (NULL, aop, ic, TRUE);
2681     }
2682
2683   if (ic)
2684   {
2685     ic->bankSaved = 1;
2686   }
2687 }
2688
2689 /*-----------------------------------------------------------------*/
2690 /* unsaveRBank - restores the register bank from stack             */
2691 /*-----------------------------------------------------------------*/
2692 static void
2693 unsaveRBank (int bank, iCode * ic, bool popPsw)
2694 {
2695   int i;
2696   asmop *aop = NULL;
2697   regs *r = NULL;
2698
2699   if (options.useXstack)
2700     {
2701       if (!ic)
2702         {
2703           /* Assume r0 is available for use. */
2704           r = REG_WITH_INDEX (R0_IDX);;
2705         }
2706       else
2707         {
2708           aop = newAsmop (0);
2709           r = getFreePtr (ic, &aop, FALSE);
2710         }
2711       emitcode ("mov", "%s,%s", r->name, spname);
2712     }
2713
2714   if (popPsw)
2715     {
2716       if (options.useXstack)
2717         {
2718           emitcode ("dec", "%s", r->name);
2719           emitcode ("movx", "a,@%s", r->name);
2720           emitcode ("mov", "psw,a");
2721         }
2722       else
2723         {
2724           emitcode ("pop", "psw");
2725         }
2726     }
2727
2728   if (mcs51_nRegs > 8)
2729     {
2730       if (options.useXstack)
2731         {
2732           emitcode ("dec", "%s", r->name);
2733           emitcode ("movx", "a,@%s", r->name);
2734           emitcode ("mov", "bits,a");
2735         }
2736       else
2737         {
2738           emitcode ("pop", "bits");
2739         }
2740     }
2741
2742   for (i = 7; i >= 0; i--)
2743     {
2744       if (options.useXstack)
2745         {
2746           emitcode ("dec", "%s", r->name);
2747           emitcode ("movx", "a,@%s", r->name);
2748           emitcode ("mov", "(%s+%d),a",
2749                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2750         }
2751       else
2752         {
2753           emitcode ("pop", "(%s+%d)",
2754                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2755         }
2756     }
2757
2758   if (options.useXstack)
2759     {
2760       emitcode ("mov", "%s,%s", spname, r->name);
2761     }
2762
2763   if (aop)
2764     {
2765       freeAsmop (NULL, aop, ic, TRUE);
2766     }
2767 }
2768
2769 /*-----------------------------------------------------------------*/
2770 /* genSend - gen code for SEND                                     */
2771 /*-----------------------------------------------------------------*/
2772 static void genSend(set *sendSet)
2773 {
2774   iCode *sic;
2775   int bit_count = 0;
2776
2777   /* first we do all bit parameters */
2778   for (sic = setFirstItem (sendSet); sic;
2779        sic = setNextItem (sendSet))
2780     {
2781       if (sic->argreg > 12)
2782         {
2783           int bit = sic->argreg-13;
2784
2785           aopOp (IC_LEFT (sic), sic, FALSE);
2786
2787           /* if left is a literal then
2788              we know what the value is */
2789           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2790             {
2791               if (((int) operandLitValue (IC_LEFT (sic))))
2792                   emitcode ("setb", "b[%d]", bit);
2793               else
2794                   emitcode ("clr", "b[%d]", bit);
2795             }
2796           else
2797             {
2798               /* we need to or */
2799               toCarry (IC_LEFT (sic));
2800               emitcode ("mov", "b[%d],c", bit);
2801             }
2802           bit_count++;
2803           BitBankUsed = 1;
2804
2805           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2806         }
2807     }
2808
2809   if (bit_count)
2810     {
2811       saveRegisters (setFirstItem (sendSet));
2812       emitcode ("mov", "bits,b");
2813     }
2814
2815   /* then we do all other parameters */
2816   for (sic = setFirstItem (sendSet); sic;
2817        sic = setNextItem (sendSet))
2818     {
2819       if (sic->argreg <= 12)
2820         {
2821           int size, offset = 0;
2822           aopOp (IC_LEFT (sic), sic, FALSE);
2823           size = AOP_SIZE (IC_LEFT (sic));
2824
2825           if (sic->argreg == 1)
2826             {
2827               while (size--)
2828                 {
2829                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2830                   if (strcmp (l, fReturn[offset]))
2831                     {
2832                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2833                     }
2834                   offset++;
2835                 }
2836             }
2837           else
2838             {
2839               while (size--)
2840                 {
2841                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2842                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2843                   offset++;
2844                 }
2845             }
2846           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2847         }
2848     }
2849 }
2850
2851 /*-----------------------------------------------------------------*/
2852 /* selectRegBank - emit code to select the register bank           */
2853 /*-----------------------------------------------------------------*/
2854 static void
2855 selectRegBank (short bank, bool keepFlags)
2856 {
2857   /* if f.e. result is in carry */
2858   if (keepFlags)
2859     {
2860       emitcode ("anl", "psw,#0xE7");
2861       if (bank)
2862         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2863     }
2864   else
2865     {
2866       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2867     }
2868 }
2869
2870 /*-----------------------------------------------------------------*/
2871 /* genCall - generates a call statement                            */
2872 /*-----------------------------------------------------------------*/
2873 static void
2874 genCall (iCode * ic)
2875 {
2876   sym_link *dtype;
2877   sym_link *etype;
2878 //  bool restoreBank = FALSE;
2879   bool swapBanks = FALSE;
2880   bool accuse = FALSE;
2881   bool accPushed = FALSE;
2882   bool resultInF0 = FALSE;
2883   bool assignResultGenerated = FALSE;
2884
2885   D (emitcode (";", "genCall"));
2886
2887   dtype = operandType (IC_LEFT (ic));
2888   etype = getSpec(dtype);
2889   /* if send set is not empty then assign */
2890   if (_G.sendSet)
2891     {
2892         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2893             genSend(reverseSet(_G.sendSet));
2894         } else {
2895             genSend(_G.sendSet);
2896         }
2897       _G.sendSet = NULL;
2898     }
2899
2900   /* if we are calling a not _naked function that is not using
2901      the same register bank then we need to save the
2902      destination registers on the stack */
2903   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2904       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2905        !IFFUNC_ISISR (dtype))
2906     {
2907       swapBanks = TRUE;
2908     }
2909
2910   /* if caller saves & we have not saved then */
2911   if (!ic->regsSaved)
2912       saveRegisters (ic);
2913
2914   if (swapBanks)
2915     {
2916         emitcode ("mov", "psw,#0x%02x",
2917            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2918     }
2919
2920   /* make the call */
2921   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2922     {
2923       if (IFFUNC_CALLEESAVES(dtype))
2924         {
2925           werror (E_BANKED_WITH_CALLEESAVES);
2926         }
2927       else
2928         {
2929           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2930                      OP_SYMBOL (IC_LEFT (ic))->rname :
2931                      OP_SYMBOL (IC_LEFT (ic))->name);
2932
2933           emitcode ("mov", "r0,#%s", l);
2934           emitcode ("mov", "r1,#(%s >> 8)", l);
2935           emitcode ("mov", "r2,#(%s >> 16)", l);
2936           emitcode ("lcall", "__sdcc_banked_call");
2937         }
2938     }
2939   else
2940     {
2941       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2942                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2943                                 OP_SYMBOL (IC_LEFT (ic))->name));
2944     }
2945
2946   if (swapBanks)
2947     {
2948       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2949     }
2950
2951   /* if we need assign a result value */
2952   if ((IS_ITEMP (IC_RESULT (ic)) &&
2953        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2954        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2955         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2956         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2957       IS_TRUE_SYMOP (IC_RESULT (ic)))
2958     {
2959
2960       _G.accInUse++;
2961       aopOp (IC_RESULT (ic), ic, FALSE);
2962       _G.accInUse--;
2963
2964       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2965       assignResultGenerated = TRUE;
2966
2967       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2968     }
2969
2970   /* adjust the stack for parameters if required */
2971   if (ic->parmBytes)
2972     {
2973       int i;
2974       if (ic->parmBytes > 3)
2975         {
2976           if (accuse)
2977             {
2978               emitcode ("push", "acc");
2979               accPushed = TRUE;
2980             }
2981           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2982               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2983               !assignResultGenerated)
2984             {
2985               emitcode ("mov", "F0,c");
2986               resultInF0 = TRUE;
2987             }
2988
2989           emitcode ("mov", "a,%s", spname);
2990           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2991           emitcode ("mov", "%s,a", spname);
2992
2993           /* unsaveRegisters from xstack needs acc, but */
2994           /* unsaveRegisters from stack needs this popped */
2995           if (accPushed && !options.useXstack)
2996             {
2997               emitcode ("pop", "acc");
2998               accPushed = FALSE;
2999             }
3000         }
3001       else
3002         for (i = 0; i < ic->parmBytes; i++)
3003           emitcode ("dec", "%s", spname);
3004     }
3005
3006   /* if we had saved some registers then unsave them */
3007   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3008     {
3009       if (accuse && !accPushed && options.useXstack)
3010         {
3011           /* xstack needs acc, but doesn't touch normal stack */
3012           emitcode ("push", "acc");
3013           accPushed = TRUE;
3014         }
3015       unsaveRegisters (ic);
3016     }
3017
3018 //  /* if register bank was saved then pop them */
3019 //  if (restoreBank)
3020 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3021
3022   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3023     {
3024       if (resultInF0)
3025           emitcode ("mov", "c,F0");
3026
3027       aopOp (IC_RESULT (ic), ic, FALSE);
3028       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3029       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3030     }
3031
3032   if (accPushed)
3033     emitcode ("pop", "acc");
3034 }
3035
3036 /*-----------------------------------------------------------------*/
3037 /* genPcall - generates a call by pointer statement                */
3038 /*-----------------------------------------------------------------*/
3039 static void
3040 genPcall (iCode * ic)
3041 {
3042   sym_link *dtype;
3043   sym_link *etype;
3044   symbol *rlbl = newiTempLabel (NULL);
3045 //  bool restoreBank=FALSE;
3046   bool swapBanks = FALSE;
3047   bool resultInF0 = FALSE;
3048
3049   D (emitcode (";", "genPcall"));
3050
3051   dtype = operandType (IC_LEFT (ic))->next;
3052   etype = getSpec(dtype);
3053   /* if caller saves & we have not saved then */
3054   if (!ic->regsSaved)
3055     saveRegisters (ic);
3056
3057   /* if we are calling a not _naked function that is not using
3058      the same register bank then we need to save the
3059      destination registers on the stack */
3060   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
3061       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3062       !IFFUNC_ISISR (dtype))
3063     {
3064 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3065 //    restoreBank=TRUE;
3066       swapBanks = TRUE;
3067       // need caution message to user here
3068     }
3069
3070   if (IS_LITERAL (etype))
3071     {
3072       /* if send set is not empty then assign */
3073       if (_G.sendSet)
3074         {
3075           genSend(reverseSet(_G.sendSet));
3076           _G.sendSet = NULL;
3077         }
3078
3079       if (swapBanks)
3080         {
3081           emitcode ("mov", "psw,#0x%02x",
3082            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3083         }
3084
3085       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
3086         {
3087           if (IFFUNC_CALLEESAVES(dtype))
3088             {
3089               werror (E_BANKED_WITH_CALLEESAVES);
3090             }
3091           else
3092             {
3093               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3094
3095               emitcode ("mov", "r0,#%s", l);
3096               emitcode ("mov", "r1,#(%s >> 8)", l);
3097               emitcode ("mov", "r2,#(%s >> 16)", l);
3098               emitcode ("lcall", "__sdcc_banked_call");
3099             }
3100         }
3101       else
3102         {
3103           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3104         }
3105     }
3106   else
3107     {
3108       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
3109         {
3110           if (IFFUNC_CALLEESAVES(dtype))
3111             {
3112               werror (E_BANKED_WITH_CALLEESAVES);
3113             }
3114           else
3115             {
3116               aopOp (IC_LEFT (ic), ic, FALSE);
3117
3118               if (!swapBanks)
3119                 {
3120                   /* what if aopGet needs r0 or r1 ??? */
3121                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3122                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3123                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3124                 }
3125               else
3126                 {
3127                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3128                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3129                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3130                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3131                 }
3132
3133               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3134
3135               /* if send set is not empty then assign */
3136               if (_G.sendSet)
3137                 {
3138                   genSend(reverseSet(_G.sendSet));
3139                   _G.sendSet = NULL;
3140                 }
3141
3142               if (swapBanks)
3143                 {
3144                   emitcode ("mov", "psw,#0x%02x",
3145                    ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3146                 }
3147
3148               /* make the call */
3149               emitcode ("lcall", "__sdcc_banked_call");
3150             }
3151         }
3152       else if (_G.sendSet)
3153         {
3154           /* push the return address on to the stack */
3155           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3156           emitcode ("push", "acc");
3157           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3158           emitcode ("push", "acc");
3159
3160           /* now push the calling address */
3161           aopOp (IC_LEFT (ic), ic, FALSE);
3162
3163           pushSide (IC_LEFT (ic), FPTRSIZE);
3164
3165           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3166
3167           /* if send set is not empty the assign */
3168           if (_G.sendSet)
3169             {
3170               genSend(reverseSet(_G.sendSet));
3171               _G.sendSet = NULL;
3172             }
3173
3174           if (swapBanks)
3175             {
3176               emitcode ("mov", "psw,#0x%02x",
3177                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3178             }
3179
3180           /* make the call */
3181           emitcode ("ret", "");
3182           emitLabel (rlbl);
3183         }
3184       else /* the send set is empty */
3185         {
3186           char *l;
3187           /* now get the calling address into dptr */
3188           aopOp (IC_LEFT (ic), ic, FALSE);
3189
3190           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3191           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3192             {
3193               emitcode ("mov", "r0,%s", l);
3194               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3195               emitcode ("mov", "dph,%s", l);
3196               emitcode ("mov", "dpl,r0");
3197             }
3198           else
3199             {
3200               emitcode ("mov", "dpl,%s", l);
3201               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3202               emitcode ("mov", "dph,%s", l);
3203             }
3204
3205           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3206
3207           if (swapBanks)
3208             {
3209               emitcode ("mov", "psw,#0x%02x",
3210                ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3211             }
3212
3213           /* make the call */
3214           emitcode ("lcall", "__sdcc_call_dptr");
3215         }
3216     }
3217   if (swapBanks)
3218     {
3219       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3220     }
3221
3222   /* if we need assign a result value */
3223   if ((IS_ITEMP (IC_RESULT (ic)) &&
3224        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3225        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3226         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3227       IS_TRUE_SYMOP (IC_RESULT (ic)))
3228     {
3229
3230       _G.accInUse++;
3231       aopOp (IC_RESULT (ic), ic, FALSE);
3232       _G.accInUse--;
3233
3234       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3235
3236       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3237     }
3238
3239   /* adjust the stack for parameters if required */
3240   if (ic->parmBytes)
3241     {
3242       int i;
3243       if (ic->parmBytes > 3)
3244         {
3245           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3246               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3247             {
3248               emitcode ("mov", "F0,c");
3249               resultInF0 = TRUE;
3250             }
3251
3252           emitcode ("mov", "a,%s", spname);
3253           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3254           emitcode ("mov", "%s,a", spname);
3255         }
3256       else
3257         for (i = 0; i < ic->parmBytes; i++)
3258           emitcode ("dec", "%s", spname);
3259     }
3260
3261 //  /* if register bank was saved then unsave them */
3262 //  if (restoreBank)
3263 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3264
3265   /* if we had saved some registers then unsave them */
3266   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3267     unsaveRegisters (ic);
3268
3269   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3270     {
3271       if (resultInF0)
3272           emitcode ("mov", "c,F0");
3273
3274       aopOp (IC_RESULT (ic), ic, FALSE);
3275       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3276       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3277     }
3278 }
3279
3280 /*-----------------------------------------------------------------*/
3281 /* resultRemat - result  is rematerializable                       */
3282 /*-----------------------------------------------------------------*/
3283 static int
3284 resultRemat (iCode * ic)
3285 {
3286   if (SKIP_IC (ic) || ic->op == IFX)
3287     return 0;
3288
3289   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3290     {
3291       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3292       if (sym->remat && !POINTER_SET (ic))
3293         return 1;
3294     }
3295
3296   return 0;
3297 }
3298
3299 /*-----------------------------------------------------------------*/
3300 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3301 /*-----------------------------------------------------------------*/
3302 static int
3303 regsCmp(void *p1, void *p2)
3304 {
3305   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3306 }
3307
3308 static bool
3309 inExcludeList (char *s)
3310 {
3311   const char *p = setFirstItem(options.excludeRegsSet);
3312
3313   if (p == NULL || STRCASECMP(p, "none") == 0)
3314     return FALSE;
3315
3316
3317   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3318 }
3319
3320 /*-----------------------------------------------------------------*/
3321 /* genFunction - generated code for function entry                 */
3322 /*-----------------------------------------------------------------*/
3323 static void
3324 genFunction (iCode * ic)
3325 {
3326   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3327   sym_link *ftype;
3328   bool     switchedPSW = FALSE;
3329   int      calleesaves_saved_register = -1;
3330   int      stackAdjust = sym->stack;
3331   int      accIsFree = sym->recvSize < 4;
3332   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3333   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3334
3335   _G.nRegsSaved = 0;
3336   /* create the function header */
3337   emitcode (";", "-----------------------------------------");
3338   emitcode (";", " function %s", sym->name);
3339   emitcode (";", "-----------------------------------------");
3340
3341   emitcode ("", "%s:", sym->rname);
3342   lineCurr->isLabel = 1;
3343   ftype = operandType (IC_LEFT (ic));
3344   _G.currentFunc = sym;
3345
3346   if (IFFUNC_ISNAKED(ftype))
3347   {
3348       emitcode(";", "naked function: no prologue.");
3349       return;
3350   }
3351
3352   /* here we need to generate the equates for the
3353      register bank if required */
3354   if (FUNC_REGBANK (ftype) != rbank)
3355     {
3356       int i;
3357
3358       rbank = FUNC_REGBANK (ftype);
3359       for (i = 0; i < mcs51_nRegs; i++)
3360         {
3361           if (regs8051[i].type != REG_BIT)
3362             {
3363               if (strcmp (regs8051[i].base, "0") == 0)
3364                 emitcode ("", "%s = 0x%02x",
3365                           regs8051[i].dname,
3366                           8 * rbank + regs8051[i].offset);
3367               else
3368                 emitcode ("", "%s = %s + 0x%02x",
3369                           regs8051[i].dname,
3370                           regs8051[i].base,
3371                           8 * rbank + regs8051[i].offset);
3372             }
3373         }
3374     }
3375
3376   /* if this is an interrupt service routine then
3377      save acc, b, dpl, dph  */
3378   if (IFFUNC_ISISR (sym->type))
3379     {
3380       if (!inExcludeList ("acc"))
3381         emitcode ("push", "acc");
3382       if (!inExcludeList ("b"))
3383         emitcode ("push", "b");
3384       if (!inExcludeList ("dpl"))
3385         emitcode ("push", "dpl");
3386       if (!inExcludeList ("dph"))
3387         emitcode ("push", "dph");
3388       /* if this isr has no bank i.e. is going to
3389          run with bank 0 , then we need to save more
3390          registers :-) */
3391       if (!FUNC_REGBANK (sym->type))
3392         {
3393           int i;
3394
3395           /* if this function does not call any other
3396              function then we can be economical and
3397              save only those registers that are used */
3398           if (!IFFUNC_HASFCALL(sym->type))
3399             {
3400               /* if any registers used */
3401               if (sym->regsUsed)
3402                 {
3403                   bool bits_pushed = FALSE;
3404                   /* save the registers used */
3405                   for (i = 0; i < sym->regsUsed->size; i++)
3406                     {
3407                       if (bitVectBitValue (sym->regsUsed, i))
3408                         bits_pushed = pushReg (i, bits_pushed);
3409                     }
3410                 }
3411             }
3412           else
3413             {
3414               /* this function has a function call. We cannot
3415                  determine register usage so we will have to push the
3416                  entire bank */
3417                 saveRBank (0, ic, FALSE);
3418                 if (options.parms_in_bank1) {
3419                     for (i=0; i < 8 ; i++ ) {
3420                         emitcode ("push","%s",rb1regs[i]);
3421                     }
3422                 }
3423             }
3424         }
3425         else
3426         {
3427             /* This ISR uses a non-zero bank.
3428              *
3429              * We assume that the bank is available for our
3430              * exclusive use.
3431              *
3432              * However, if this ISR calls a function which uses some
3433              * other bank, we must save that bank entirely.
3434              */
3435             unsigned long banksToSave = 0;
3436
3437             if (IFFUNC_HASFCALL(sym->type))
3438             {
3439
3440 #define MAX_REGISTER_BANKS 4
3441
3442                 iCode *i;
3443                 int ix;
3444
3445                 for (i = ic; i; i = i->next)
3446                 {
3447                     if (i->op == ENDFUNCTION)
3448                     {
3449                         /* we got to the end OK. */
3450                         break;
3451                     }
3452
3453                     if (i->op == CALL)
3454                     {
3455                         sym_link *dtype;
3456
3457                         dtype = operandType (IC_LEFT(i));
3458                         if (dtype
3459                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3460                         {
3461                              /* Mark this bank for saving. */
3462                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3463                              {
3464                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3465                              }
3466                              else
3467                              {
3468                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3469                              }
3470
3471                              /* And note that we don't need to do it in
3472                               * genCall.
3473                               */
3474                              i->bankSaved = 1;
3475                         }
3476                     }
3477                     if (i->op == PCALL)
3478                     {
3479                         /* This is a mess; we have no idea what
3480                          * register bank the called function might
3481                          * use.
3482                          *
3483                          * The only thing I can think of to do is
3484                          * throw a warning and hope.
3485                          */
3486                         werror(W_FUNCPTR_IN_USING_ISR);
3487                     }
3488                 }
3489
3490                 if (banksToSave && options.useXstack)
3491                 {
3492                     /* Since we aren't passing it an ic,
3493                      * saveRBank will assume r0 is available to abuse.
3494                      *
3495                      * So switch to our (trashable) bank now, so
3496                      * the caller's R0 isn't trashed.
3497                      */
3498                     emitcode ("push", "psw");
3499                     emitcode ("mov", "psw,#0x%02x",
3500                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3501                     switchedPSW = TRUE;
3502                 }
3503
3504                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3505                 {
3506                      if (banksToSave & (1 << ix))
3507                      {
3508                          saveRBank(ix, NULL, FALSE);
3509                      }
3510                 }
3511             }
3512             // TODO: this needs a closer look
3513             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3514         }
3515
3516       /* Set the register bank to the desired value if nothing else */
3517       /* has done so yet. */
3518       if (!switchedPSW)
3519         {
3520           emitcode ("push", "psw");
3521           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3522         }
3523     }
3524   else
3525     {
3526       /* This is a non-ISR function. The caller has already switched register */
3527       /* banks, if necessary, so just handle the callee-saves option. */
3528
3529       /* if callee-save to be used for this function
3530          then save the registers being used in this function */
3531       if (IFFUNC_CALLEESAVES(sym->type))
3532         {
3533           int i;
3534
3535           /* if any registers used */
3536           if (sym->regsUsed)
3537             {
3538               bool bits_pushed = FALSE;
3539               /* save the registers used */
3540               for (i = 0; i < sym->regsUsed->size; i++)
3541                 {
3542                   if (bitVectBitValue (sym->regsUsed, i))
3543                     {
3544                       /* remember one saved register for later usage */
3545                       if (calleesaves_saved_register < 0)
3546                         calleesaves_saved_register = i;
3547                       bits_pushed = pushReg (i, bits_pushed);
3548                       _G.nRegsSaved++;
3549                     }
3550                 }
3551             }
3552         }
3553     }
3554
3555   if (fReentrant)
3556     {
3557       if (options.useXstack)
3558         {
3559           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3560             {
3561               emitcode ("mov", "r0,%s", spname);
3562               emitcode ("inc", "%s", spname);
3563               emitcode ("xch", "a,_bpx");
3564               emitcode ("movx", "@r0,a");
3565               emitcode ("inc", "r0");
3566               emitcode ("mov", "a,r0");
3567               emitcode ("xch", "a,_bpx");
3568             }
3569           if (sym->stack)
3570             {
3571               emitcode ("push", "_bp");     /* save the callers stack  */
3572               emitcode ("mov", "_bp,sp");
3573             }
3574         }
3575       else
3576         {
3577           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3578             {
3579               /* set up the stack */
3580               emitcode ("push", "_bp");     /* save the callers stack  */
3581               emitcode ("mov", "_bp,sp");
3582             }
3583         }
3584     }
3585
3586   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3587   /* before setting up the stack frame completely. */
3588   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3589     {
3590       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3591
3592       if (rsym->isitmp)
3593         {
3594           if (rsym && rsym->regType == REG_CND)
3595             rsym = NULL;
3596           if (rsym && (rsym->accuse || rsym->ruonly))
3597             rsym = NULL;
3598           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3599             rsym = rsym->usl.spillLoc;
3600         }
3601
3602       /* If the RECEIVE operand immediately spills to the first entry on the */
3603       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3604       /* rather than the usual @r0/r1 machinations. */
3605       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3606         {
3607           int ofs;
3608
3609           _G.current_iCode = ric;
3610           D(emitcode (";     genReceive",""));
3611           for (ofs=0; ofs < sym->recvSize; ofs++)
3612             {
3613               if (!strcmp (fReturn[ofs], "a"))
3614                 emitcode ("push", "acc");
3615               else
3616                 emitcode ("push", fReturn[ofs]);
3617             }
3618           stackAdjust -= sym->recvSize;
3619           if (stackAdjust<0)
3620             {
3621               assert (stackAdjust>=0);
3622               stackAdjust = 0;
3623             }
3624           _G.current_iCode = ic;
3625           ric->generated = 1;
3626           accIsFree = 1;
3627         }
3628       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3629       /* to free up the accumulator. */
3630       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3631         {
3632           int ofs;
3633
3634           _G.current_iCode = ric;
3635           D(emitcode (";     genReceive",""));
3636           for (ofs=0; ofs < sym->recvSize; ofs++)
3637             {
3638               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3639             }
3640           _G.current_iCode = ic;
3641           ric->generated = 1;
3642           accIsFree = 1;
3643         }
3644     }
3645
3646   /* adjust the stack for the function */
3647   if (stackAdjust)
3648     {
3649       int i = stackAdjust;
3650       if (i > 256)
3651         werror (W_STACK_OVERFLOW, sym->name);
3652
3653       if (i > 3 && accIsFree)
3654         {
3655           emitcode ("mov", "a,sp");
3656           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3657           emitcode ("mov", "sp,a");
3658         }
3659       else if (i > 5)
3660         {
3661           /* The accumulator is not free, so we will need another register */
3662           /* to clobber. No need to worry about a possible conflict with */
3663           /* the above early RECEIVE optimizations since they would have */
3664           /* freed the accumulator if they were generated. */
3665
3666           if (IFFUNC_CALLEESAVES(sym->type))
3667             {
3668               /* if it's a callee-saves function we need a saved register */
3669               if (calleesaves_saved_register >= 0)
3670                 {
3671                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3672                   emitcode ("mov", "a,sp");
3673                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3674                   emitcode ("mov", "sp,a");
3675                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3676                 }
3677               else
3678                 /* do it the hard way */
3679                 while (i--)
3680                   emitcode ("inc", "sp");
3681             }
3682           else
3683             {
3684               /* not callee-saves, we can clobber r0 */
3685               emitcode ("mov", "r0,a");
3686               emitcode ("mov", "a,sp");
3687               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3688               emitcode ("mov", "sp,a");
3689               emitcode ("mov", "a,r0");
3690             }
3691         }
3692       else
3693         while (i--)
3694           emitcode ("inc", "sp");
3695     }
3696
3697   if (sym->xstack)
3698     {
3699       char i = ((char) sym->xstack & 0xff);
3700
3701       if (i > 3 && accIsFree)
3702         {
3703           emitcode ("mov", "a,_spx");
3704           emitcode ("add", "a,#0x%02x", i & 0xff);
3705           emitcode ("mov", "_spx,a");
3706         }
3707       else if (i > 5)
3708         {
3709           emitcode ("push", "acc");
3710           emitcode ("mov", "a,_spx");
3711           emitcode ("add", "a,#0x%02x", i & 0xff);
3712           emitcode ("mov", "_spx,a");
3713           emitcode ("pop", "acc");
3714         }
3715       else
3716         {
3717           while (i--)
3718             emitcode ("inc", "_spx");
3719         }
3720     }
3721
3722   /* if critical function then turn interrupts off */
3723   if (IFFUNC_ISCRITICAL (ftype))
3724     {
3725       symbol *tlbl = newiTempLabel (NULL);
3726       emitcode ("setb", "c");
3727       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3728       emitcode ("clr", "c");
3729       emitLabel (tlbl);
3730       emitcode ("push", "psw"); /* save old ea via c in psw */
3731     }
3732 }
3733
3734 /*-----------------------------------------------------------------*/
3735 /* genEndFunction - generates epilogue for functions               */
3736 /*-----------------------------------------------------------------*/
3737 static void
3738 genEndFunction (iCode * ic)
3739 {
3740   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3741   lineNode *lnp = lineCurr;
3742   bitVect  *regsUsed;
3743   bitVect  *regsUsedPrologue;
3744   bitVect  *regsUnneeded;
3745   int      idx;
3746
3747   _G.currentFunc = NULL;
3748   if (IFFUNC_ISNAKED(sym->type))
3749   {
3750       emitcode(";", "naked function: no epilogue.");
3751       if (options.debug && currFunc)
3752         debugFile->writeEndFunction (currFunc, ic, 0);
3753       return;
3754   }
3755
3756   if (IFFUNC_ISCRITICAL (sym->type))
3757     {
3758       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3759         {
3760           emitcode ("rlc", "a");   /* save c in a */
3761           emitcode ("pop", "psw"); /* restore ea via c in psw */
3762           emitcode ("mov", "ea,c");
3763           emitcode ("rrc", "a");   /* restore c from a */
3764         }
3765       else
3766         {
3767           emitcode ("pop", "psw"); /* restore ea via c in psw */
3768           emitcode ("mov", "ea,c");
3769         }
3770     }
3771
3772   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3773     {
3774       if (options.useXstack)
3775         {
3776           if (sym->stack)
3777             {
3778               emitcode ("mov", "sp,_bp");
3779               emitcode ("pop", "_bp");
3780             }
3781           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3782             {
3783               emitcode ("xch", "a,_bpx");
3784               emitcode ("mov", "r0,a");
3785               emitcode ("dec", "r0");
3786               emitcode ("movx", "a,@r0");
3787               emitcode ("xch", "a,_bpx");
3788               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3789             }
3790         }
3791       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3792         {
3793           if (sym->stack)
3794             emitcode ("mov", "sp,_bp");
3795           emitcode ("pop", "_bp");
3796         }
3797     }
3798
3799   /* restore the register bank  */
3800   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3801   {
3802     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3803      || !options.useXstack)
3804     {
3805         /* Special case of ISR using non-zero bank with useXstack
3806          * is handled below.
3807          */
3808         emitcode ("pop", "psw");
3809     }
3810   }
3811
3812   if (IFFUNC_ISISR (sym->type))
3813     {
3814
3815       /* now we need to restore the registers */
3816       /* if this isr has no bank i.e. is going to
3817          run with bank 0 , then we need to save more
3818          registers :-) */
3819       if (!FUNC_REGBANK (sym->type))
3820         {
3821           int i;
3822           /* if this function does not call any other
3823              function then we can be economical and
3824              save only those registers that are used */
3825           if (!IFFUNC_HASFCALL(sym->type))
3826             {
3827               /* if any registers used */
3828               if (sym->regsUsed)
3829                 {
3830                   bool bits_popped = FALSE;
3831                   /* save the registers used */
3832                   for (i = sym->regsUsed->size; i >= 0; i--)
3833                     {
3834                       if (bitVectBitValue (sym->regsUsed, i))
3835                         bits_popped = popReg (i, bits_popped);
3836                     }
3837                 }
3838             }
3839           else
3840             {
3841               if (options.parms_in_bank1) {
3842                   for (i = 7 ; i >= 0 ; i-- ) {
3843                       emitcode ("pop","%s",rb1regs[i]);
3844                   }
3845               }
3846               /* this function has  a function call cannot
3847                  determines register usage so we will have to pop the
3848                  entire bank */
3849               unsaveRBank (0, ic, FALSE);
3850             }
3851         }
3852         else
3853         {
3854             /* This ISR uses a non-zero bank.
3855              *
3856              * Restore any register banks saved by genFunction
3857              * in reverse order.
3858              */
3859             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3860             int ix;
3861
3862             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3863             {
3864                 if (savedBanks & (1 << ix))
3865                 {
3866                     unsaveRBank(ix, NULL, FALSE);
3867                 }
3868             }
3869
3870             if (options.useXstack)
3871             {
3872                 /* Restore bank AFTER calling unsaveRBank,
3873                  * since it can trash r0.
3874                  */
3875                 emitcode ("pop", "psw");
3876             }
3877         }
3878
3879       if (!inExcludeList ("dph"))
3880         emitcode ("pop", "dph");
3881       if (!inExcludeList ("dpl"))
3882         emitcode ("pop", "dpl");
3883       if (!inExcludeList ("b"))
3884         emitcode ("pop", "b");
3885       if (!inExcludeList ("acc"))
3886         emitcode ("pop", "acc");
3887
3888       /* if debug then send end of function */
3889       if (options.debug && currFunc)
3890         {
3891           debugFile->writeEndFunction (currFunc, ic, 1);
3892         }
3893
3894       emitcode ("reti", "");
3895     }
3896   else
3897     {
3898       if (IFFUNC_CALLEESAVES(sym->type))
3899         {
3900           int i;
3901
3902           /* if any registers used */
3903           if (sym->regsUsed)
3904             {
3905               /* save the registers used */
3906               for (i = sym->regsUsed->size; i >= 0; i--)
3907                 {
3908                   if (bitVectBitValue (sym->regsUsed, i) ||
3909                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3910                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3911                 }
3912             }
3913           else if (mcs51_ptrRegReq)
3914             {
3915               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3916               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3917             }
3918
3919         }
3920
3921       /* if debug then send end of function */
3922       if (options.debug && currFunc)
3923         {
3924           debugFile->writeEndFunction (currFunc, ic, 1);
3925         }
3926
3927       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3928         {
3929           emitcode ("ljmp", "__sdcc_banked_ret");
3930         }
3931       else
3932         {
3933           emitcode ("ret", "");
3934         }
3935     }
3936
3937   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3938     return;
3939
3940   /* If this was an interrupt handler using bank 0 that called another */
3941   /* function, then all registers must be saved; nothing to optimized. */
3942   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3943       && !FUNC_REGBANK(sym->type))
3944     return;
3945
3946   /* There are no push/pops to optimize if not callee-saves or ISR */
3947   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3948     return;
3949
3950   /* If there were stack parameters, we cannot optimize without also    */
3951   /* fixing all of the stack offsets; this is too dificult to consider. */
3952   if (FUNC_HASSTACKPARM(sym->type))
3953     return;
3954
3955   /* Compute the registers actually used */
3956   regsUsed = newBitVect (mcs51_nRegs);
3957   regsUsedPrologue = newBitVect (mcs51_nRegs);
3958   while (lnp)
3959     {
3960       if (lnp->ic && lnp->ic->op == FUNCTION)
3961         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3962       else
3963         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3964
3965       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3966           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3967         break;
3968       if (!lnp->prev)
3969         break;
3970       lnp = lnp->prev;
3971     }
3972
3973   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3974       && !bitVectBitValue (regsUsed, CND_IDX))
3975     {
3976       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3977       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3978           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3979         bitVectUnSetBit (regsUsed, CND_IDX);
3980     }
3981   else
3982     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3983
3984   /* If this was an interrupt handler that called another function */
3985   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3986   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3987     {
3988       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3989       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3990       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3991       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3992       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3993     }
3994
3995   /* Remove the unneeded push/pops */
3996   regsUnneeded = newBitVect (mcs51_nRegs);
3997   while (lnp)
3998     {
3999       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4000         {
4001           if (!strncmp(lnp->line, "push", 4))
4002             {
4003               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4004               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4005                 {
4006                   connectLine (lnp->prev, lnp->next);
4007                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4008                 }
4009             }
4010           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4011             {
4012               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4013               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4014                 {
4015                   connectLine (lnp->prev, lnp->next);
4016                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4017                 }
4018             }
4019         }
4020       lnp = lnp->next;
4021     }
4022
4023   for (idx = 0; idx < regsUnneeded->size; idx++)
4024     if (bitVectBitValue (regsUnneeded, idx))
4025       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4026
4027   freeBitVect (regsUnneeded);
4028   freeBitVect (regsUsed);
4029   freeBitVect (regsUsedPrologue);
4030 }
4031
4032 /*-----------------------------------------------------------------*/
4033 /* genRet - generate code for return statement                     */
4034 /*-----------------------------------------------------------------*/
4035 static void
4036 genRet (iCode * ic)
4037 {
4038   int size, offset = 0, pushed = 0;
4039
4040   D (emitcode (";", "genRet"));
4041
4042   /* if we have no return value then
4043      just generate the "ret" */
4044   if (!IC_LEFT (ic))
4045     goto jumpret;
4046
4047   /* we have something to return then
4048      move the return value into place */
4049   aopOp (IC_LEFT (ic), ic, FALSE);
4050   size = AOP_SIZE (IC_LEFT (ic));
4051
4052   if (IS_BIT(_G.currentFunc->etype))
4053     {
4054       toCarry (IC_LEFT (ic));
4055     }
4056   else
4057     {
4058       while (size--)
4059         {
4060           char *l;
4061           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4062             {
4063               /* #NOCHANGE */
4064               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4065               emitcode ("push", "%s", l);
4066               pushed++;
4067             }
4068           else
4069             {
4070               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4071               if (strcmp (fReturn[offset], l))
4072                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4073             }
4074         }
4075
4076       while (pushed)
4077         {
4078           pushed--;
4079           if (strcmp (fReturn[pushed], "a"))
4080             emitcode ("pop", fReturn[pushed]);
4081           else
4082             emitcode ("pop", "acc");
4083         }
4084     }
4085   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4086
4087 jumpret:
4088   /* generate a jump to the return label
4089      if the next is not the return statement */
4090   if (!(ic->next && ic->next->op == LABEL &&
4091         IC_LABEL (ic->next) == returnLabel))
4092
4093     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4094
4095 }
4096
4097 /*-----------------------------------------------------------------*/
4098 /* genLabel - generates a label                                    */
4099 /*-----------------------------------------------------------------*/
4100 static void
4101 genLabel (iCode * ic)
4102 {
4103   /* special case never generate */
4104   if (IC_LABEL (ic) == entryLabel)
4105     return;
4106
4107   emitLabel (IC_LABEL (ic));
4108 }
4109
4110 /*-----------------------------------------------------------------*/
4111 /* genGoto - generates a ljmp                                      */
4112 /*-----------------------------------------------------------------*/
4113 static void
4114 genGoto (iCode * ic)
4115 {
4116   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4117 }
4118
4119 /*-----------------------------------------------------------------*/
4120 /* findLabelBackwards: walks back through the iCode chain looking  */
4121 /* for the given label. Returns number of iCode instructions     */
4122 /* between that label and given ic.          */
4123 /* Returns zero if label not found.          */
4124 /*-----------------------------------------------------------------*/
4125 static int
4126 findLabelBackwards (iCode * ic, int key)
4127 {
4128   int count = 0;
4129
4130   while (ic->prev)
4131     {
4132       ic = ic->prev;
4133       count++;
4134
4135       /* If we have any pushes or pops, we cannot predict the distance.
4136          I don't like this at all, this should be dealt with in the
4137          back-end */
4138       if (ic->op == IPUSH || ic->op == IPOP) {
4139         return 0;
4140       }
4141
4142       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4143         {
4144           return count;
4145         }
4146     }
4147
4148   return 0;
4149 }
4150
4151 /*-----------------------------------------------------------------*/
4152 /* genPlusIncr :- does addition with increment if possible         */
4153 /*-----------------------------------------------------------------*/
4154 static bool
4155 genPlusIncr (iCode * ic)
4156 {
4157   unsigned int icount;
4158   unsigned int size = getDataSize (IC_RESULT (ic));
4159
4160   /* will try to generate an increment */
4161   /* if the right side is not a literal
4162      we cannot */
4163   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4164     return FALSE;
4165
4166   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4167
4168   D(emitcode (";","genPlusIncr"));
4169
4170   /* if increment >=16 bits in register or direct space */
4171   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4172         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4173         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4174       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4175       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4176       (size > 1) &&
4177       (icount == 1))
4178     {
4179       symbol *tlbl;
4180       int emitTlbl;
4181       int labelRange;
4182
4183       /* If the next instruction is a goto and the goto target
4184        * is < 10 instructions previous to this, we can generate
4185        * jumps straight to that target.
4186        */
4187       if (ic->next && ic->next->op == GOTO
4188           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4189           && labelRange <= 10)
4190         {
4191           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4192           tlbl = IC_LABEL (ic->next);
4193           emitTlbl = 0;
4194         }
4195       else
4196         {
4197           tlbl = newiTempLabel (NULL);
4198           emitTlbl = 1;
4199         }
4200       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4201       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4202           IS_AOP_PREG (IC_RESULT (ic)))
4203         emitcode ("cjne", "%s,#0x00,%05d$",
4204                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4205                   tlbl->key + 100);
4206       else
4207         {
4208           emitcode ("clr", "a");
4209           emitcode ("cjne", "a,%s,%05d$",
4210                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4211                     tlbl->key + 100);
4212         }
4213
4214       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4215       if (size > 2)
4216         {
4217           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4218               IS_AOP_PREG (IC_RESULT (ic)))
4219             emitcode ("cjne", "%s,#0x00,%05d$",
4220                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4221                       tlbl->key + 100);
4222           else
4223             emitcode ("cjne", "a,%s,%05d$",
4224                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4225                       tlbl->key + 100);
4226
4227           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4228         }
4229       if (size > 3)
4230         {
4231           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4232               IS_AOP_PREG (IC_RESULT (ic)))
4233             emitcode ("cjne", "%s,#0x00,%05d$",
4234                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4235                       tlbl->key + 100);
4236           else
4237             {
4238               emitcode ("cjne", "a,%s,%05d$",
4239                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4240                         tlbl->key + 100);
4241             }
4242           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4243         }
4244
4245       if (emitTlbl)
4246         {
4247           emitLabel (tlbl);
4248         }
4249       return TRUE;
4250     }
4251
4252   /* if result is dptr */
4253   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4254       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4255       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4256       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4257     {
4258       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4259         return FALSE;
4260
4261       if (icount > 9)
4262         return FALSE;
4263
4264       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4265         return FALSE;
4266
4267       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4268       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4269       while (icount--)
4270         emitcode ("inc", "dptr");
4271
4272       return TRUE;
4273     }
4274
4275   /* if the literal value of the right hand side
4276      is greater than 4 then it is not worth it */
4277   if (icount > 4)
4278     return FALSE;
4279
4280   /* if the sizes are greater than 1 then we cannot */
4281   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4282       AOP_SIZE (IC_LEFT (ic)) > 1)
4283     return FALSE;
4284
4285   /* we can if the aops of the left & result match or
4286      if they are in registers and the registers are the
4287      same */
4288   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4289     {
4290       if (icount > 3)
4291         {
4292           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4293           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4294           aopPut (IC_RESULT (ic), "a", 0);
4295         }
4296       else
4297         {
4298           while (icount--)
4299             {
4300               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4301             }
4302         }
4303
4304       return TRUE;
4305     }
4306
4307   if (icount == 1)
4308     {
4309       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4310       emitcode ("inc", "a");
4311       aopPut (IC_RESULT (ic), "a", 0);
4312       return TRUE;
4313     }
4314
4315   return FALSE;
4316 }
4317
4318 /*-----------------------------------------------------------------*/
4319 /* outBitAcc - output a bit in acc                                 */
4320 /*-----------------------------------------------------------------*/
4321 static void
4322 outBitAcc (operand * result)
4323 {
4324   symbol *tlbl = newiTempLabel (NULL);
4325   /* if the result is a bit */
4326   if (AOP_TYPE (result) == AOP_CRY)
4327     {
4328       aopPut (result, "a", 0);
4329     }
4330   else
4331     {
4332       emitcode ("jz", "%05d$", tlbl->key + 100);
4333       emitcode ("mov", "a,%s", one);
4334       emitLabel (tlbl);
4335       outAcc (result);
4336     }
4337 }
4338
4339 /*-----------------------------------------------------------------*/
4340 /* genPlusBits - generates code for addition of two bits           */
4341 /*-----------------------------------------------------------------*/
4342 static void
4343 genPlusBits (iCode * ic)
4344 {
4345   D (emitcode (";", "genPlusBits"));
4346
4347   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4348   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4349     {
4350       symbol *lbl = newiTempLabel (NULL);
4351       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4352       emitcode ("cpl", "c");
4353       emitLabel (lbl);
4354       outBitC (IC_RESULT (ic));
4355     }
4356   else
4357     {
4358       emitcode ("clr", "a");
4359       emitcode ("rlc", "a");
4360       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4361       emitcode ("addc", "a,%s", zero);
4362       outAcc (IC_RESULT (ic));
4363     }
4364 }
4365
4366 #if 0
4367 /* This is the original version of this code.
4368
4369  * This is being kept around for reference,
4370  * because I am not entirely sure I got it right...
4371  */
4372 static void
4373 adjustArithmeticResult (iCode * ic)
4374 {
4375   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4376       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4377       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4378     aopPut (IC_RESULT (ic),
4379             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4380             2);
4381
4382   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4383       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4384       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4385     aopPut (IC_RESULT (ic),
4386             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4387             2);
4388
4389   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4390       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4391       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4392       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4393       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4394     {
4395       char buffer[5];
4396       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4397       aopPut (IC_RESULT (ic), buffer, 2);
4398     }
4399 }
4400 #else
4401 /* This is the pure and virtuous version of this code.
4402  * I'm pretty certain it's right, but not enough to toss the old
4403  * code just yet...
4404  */
4405 static void
4406 adjustArithmeticResult (iCode * ic)
4407 {
4408   if (opIsGptr (IC_RESULT (ic)) &&
4409       opIsGptr (IC_LEFT (ic)) &&
4410       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4411     {
4412       aopPut (IC_RESULT (ic),
4413               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4414               GPTRSIZE - 1);
4415     }
4416
4417   if (opIsGptr (IC_RESULT (ic)) &&
4418       opIsGptr (IC_RIGHT (ic)) &&
4419       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4420     {
4421       aopPut (IC_RESULT (ic),
4422               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4423               GPTRSIZE - 1);
4424     }
4425
4426   if (opIsGptr (IC_RESULT (ic)) &&
4427       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4428       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4429       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4430       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4431     {
4432       char buffer[5];
4433       SNPRINTF (buffer, sizeof(buffer),
4434                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4435       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4436     }
4437 }
4438 #endif
4439
4440 /*-----------------------------------------------------------------*/
4441 /* genPlus - generates code for addition                           */
4442 /*-----------------------------------------------------------------*/
4443 static void
4444 genPlus (iCode * ic)
4445 {
4446   int size, offset = 0;
4447   int skip_bytes = 0;
4448   char *add = "add";
4449   bool swappedLR = FALSE;
4450   operand *leftOp, *rightOp;
4451   operand * op;
4452
4453   D (emitcode (";", "genPlus"));
4454
4455   /* special cases :- */
4456
4457   aopOp (IC_LEFT (ic), ic, FALSE);
4458   aopOp (IC_RIGHT (ic), ic, FALSE);
4459   aopOp (IC_RESULT (ic), ic, TRUE);
4460
4461   /* if literal, literal on the right or
4462      if left requires ACC or right is already
4463      in ACC */
4464   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4465       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4466       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4467     {
4468       operand *t = IC_RIGHT (ic);
4469       IC_RIGHT (ic) = IC_LEFT (ic);
4470       IC_LEFT (ic) = t;
4471       swappedLR = TRUE;
4472     }
4473
4474   /* if both left & right are in bit
4475      space */
4476   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4477       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4478     {
4479       genPlusBits (ic);
4480       goto release;
4481     }
4482
4483   /* if left in bit space & right literal */
4484   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4485       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4486     {
4487       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4488       /* if result in bit space */
4489       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4490         {
4491           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4492             emitcode ("cpl", "c");
4493           outBitC (IC_RESULT (ic));
4494         }
4495       else
4496         {
4497           size = getDataSize (IC_RESULT (ic));
4498           while (size--)
4499             {
4500               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4501               emitcode ("addc", "a,%s", zero);
4502               aopPut (IC_RESULT (ic), "a", offset++);
4503             }
4504         }
4505       goto release;
4506     }
4507
4508   /* if I can do an increment instead
4509      of add then GOOD for ME */
4510   if (genPlusIncr (ic) == TRUE)
4511     goto release;
4512
4513   size = getDataSize (IC_RESULT (ic));
4514   leftOp = IC_LEFT(ic);
4515   rightOp = IC_RIGHT(ic);
4516   op = IC_LEFT(ic);
4517
4518   /* if this is an add for an array access
4519      at a 256 byte boundary */
4520   if ( 2 == size
4521        && AOP_TYPE (op) == AOP_IMMD
4522        && IS_SYMOP (op)
4523        && IS_SPEC (OP_SYM_ETYPE (op))
4524        && SPEC_ABSA (OP_SYM_ETYPE (op))
4525        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4526      )
4527     {
4528       D(emitcode (";     genPlus aligned array",""));
4529       aopPut (IC_RESULT (ic),
4530               aopGet (rightOp, 0, FALSE, FALSE),
4531               0);
4532
4533       if( 1 == getDataSize (IC_RIGHT (ic)) )
4534         {
4535           aopPut (IC_RESULT (ic),
4536                   aopGet (leftOp, 1, FALSE, FALSE),
4537                   1);
4538         }
4539       else
4540         {
4541           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4542           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4543           aopPut (IC_RESULT (ic), "a", 1);
4544         }
4545       goto release;
4546     }
4547
4548   /* if the lower bytes of a literal are zero skip the addition */
4549   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4550     {
4551        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4552               (skip_bytes+1 < size))
4553          {
4554            skip_bytes++;
4555          }
4556        if (skip_bytes)
4557          D(emitcode (";     genPlus shortcut",""));
4558     }
4559
4560   while (size--)
4561     {
4562       if( offset >= skip_bytes )
4563         {
4564           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4565             {
4566               bool pushedB;
4567               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4568               pushedB = pushB ();
4569               emitcode("xch", "a,b");
4570               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4571               emitcode (add, "a,b");
4572               popB (pushedB);
4573             }
4574           else if (aopGetUsesAcc (leftOp, offset))
4575             {
4576               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4577               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4578             }
4579           else
4580             {
4581               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4582               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4583             }
4584           aopPut (IC_RESULT (ic), "a", offset);
4585           add = "addc";  /* further adds must propagate carry */
4586         }
4587       else
4588         {
4589           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4590               isOperandVolatile (IC_RESULT (ic), FALSE))
4591             {
4592               /* just move */
4593               aopPut (IC_RESULT (ic),
4594                       aopGet (leftOp, offset, FALSE, FALSE),
4595                       offset);
4596             }
4597         }
4598       offset++;
4599     }
4600
4601   adjustArithmeticResult (ic);
4602
4603 release:
4604   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4605   if (!swappedLR)
4606     {
4607       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4608       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4609     }
4610   else
4611     {
4612       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4613       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4614     }
4615 }
4616
4617 /*-----------------------------------------------------------------*/
4618 /* genMinusDec :- does subtraction with decrement if possible      */
4619 /*-----------------------------------------------------------------*/
4620 static bool
4621 genMinusDec (iCode * ic)
4622 {
4623   unsigned int icount;
4624   unsigned int size = getDataSize (IC_RESULT (ic));
4625
4626   /* will try to generate an increment */
4627   /* if the right side is not a literal
4628      we cannot */
4629   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4630     return FALSE;
4631
4632   /* if the literal value of the right hand side
4633      is greater than 4 then it is not worth it */
4634   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4635     return FALSE;
4636
4637   D (emitcode (";", "genMinusDec"));
4638
4639   /* if decrement >=16 bits in register or direct space */
4640   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4641         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4642         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4643       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4644       (size > 1) &&
4645       (icount == 1))
4646     {
4647       symbol *tlbl;
4648       int emitTlbl;
4649       int labelRange;
4650
4651       /* If the next instruction is a goto and the goto target
4652        * is <= 10 instructions previous to this, we can generate
4653        * jumps straight to that target.
4654        */
4655       if (ic->next && ic->next->op == GOTO
4656           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4657           && labelRange <= 10)
4658         {
4659           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4660           tlbl = IC_LABEL (ic->next);
4661           emitTlbl = 0;
4662         }
4663       else
4664         {
4665           tlbl = newiTempLabel (NULL);
4666           emitTlbl = 1;
4667         }
4668
4669       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4670       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4671           IS_AOP_PREG (IC_RESULT (ic)))
4672         emitcode ("cjne", "%s,#0xff,%05d$"
4673                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4674                   ,tlbl->key + 100);
4675       else
4676         {
4677           emitcode ("mov", "a,#0xff");
4678           emitcode ("cjne", "a,%s,%05d$"
4679                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4680                     ,tlbl->key + 100);
4681         }
4682       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4683       if (size > 2)
4684         {
4685           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4686               IS_AOP_PREG (IC_RESULT (ic)))
4687             emitcode ("cjne", "%s,#0xff,%05d$"
4688                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4689                       ,tlbl->key + 100);
4690           else
4691             {
4692               emitcode ("cjne", "a,%s,%05d$"
4693                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4694                         ,tlbl->key + 100);
4695             }
4696           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4697         }
4698       if (size > 3)
4699         {
4700           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4701               IS_AOP_PREG (IC_RESULT (ic)))
4702             emitcode ("cjne", "%s,#0xff,%05d$"
4703                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4704                       ,tlbl->key + 100);
4705           else
4706             {
4707               emitcode ("cjne", "a,%s,%05d$"
4708                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4709                         ,tlbl->key + 100);
4710             }
4711           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4712         }
4713       if (emitTlbl)
4714         {
4715           emitLabel (tlbl);
4716         }
4717       return TRUE;
4718     }
4719
4720   /* if the sizes are greater than 1 then we cannot */
4721   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4722       AOP_SIZE (IC_LEFT (ic)) > 1)
4723     return FALSE;
4724
4725   /* we can if the aops of the left & result match or
4726      if they are in registers and the registers are the
4727      same */
4728   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4729     {
4730       char *l;
4731
4732       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4733         {
4734           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4735           l = "a";
4736         }
4737       else
4738         {
4739           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4740         }
4741
4742       while (icount--)
4743         {
4744           emitcode ("dec", "%s", l);
4745         }
4746
4747       if (AOP_NEEDSACC (IC_RESULT (ic)))
4748         aopPut (IC_RESULT (ic), "a", 0);
4749
4750       return TRUE;
4751     }
4752
4753   if (icount == 1)
4754     {
4755       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4756       emitcode ("dec", "a");
4757       aopPut (IC_RESULT (ic), "a", 0);
4758       return TRUE;
4759     }
4760
4761   return FALSE;
4762 }
4763
4764 /*-----------------------------------------------------------------*/
4765 /* addSign - complete with sign                                    */
4766 /*-----------------------------------------------------------------*/
4767 static void
4768 addSign (operand * result, int offset, int sign)
4769 {
4770   int size = (getDataSize (result) - offset);
4771   if (size > 0)
4772     {
4773       if (sign)
4774         {
4775           emitcode ("rlc", "a");
4776           emitcode ("subb", "a,acc");
4777           while (size--)
4778             {
4779               aopPut (result, "a", offset++);
4780             }
4781         }
4782       else
4783         {
4784           while (size--)
4785             {
4786               aopPut (result, zero, offset++);
4787             }
4788         }
4789     }
4790 }
4791
4792 /*-----------------------------------------------------------------*/
4793 /* genMinusBits - generates code for subtraction  of two bits      */
4794 /*-----------------------------------------------------------------*/
4795 static void
4796 genMinusBits (iCode * ic)
4797 {
4798   symbol *lbl = newiTempLabel (NULL);
4799
4800   D (emitcode (";", "genMinusBits"));
4801
4802   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4803     {
4804       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4805       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4806       emitcode ("cpl", "c");
4807       emitLabel (lbl);
4808       outBitC (IC_RESULT (ic));
4809     }
4810   else
4811     {
4812       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4813       emitcode ("subb", "a,acc");
4814       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4815       emitcode ("inc", "a");
4816       emitLabel (lbl);
4817       aopPut (IC_RESULT (ic), "a", 0);
4818       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4819     }
4820 }
4821
4822 /*-----------------------------------------------------------------*/
4823 /* genMinus - generates code for subtraction                       */
4824 /*-----------------------------------------------------------------*/
4825 static void
4826 genMinus (iCode * ic)
4827 {
4828   int size, offset = 0;
4829
4830   D (emitcode (";", "genMinus"));
4831
4832   aopOp (IC_LEFT (ic), ic, FALSE);
4833   aopOp (IC_RIGHT (ic), ic, FALSE);
4834   aopOp (IC_RESULT (ic), ic, TRUE);
4835
4836   /* special cases :- */
4837   /* if both left & right are in bit space */
4838   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4839       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4840     {
4841       genMinusBits (ic);
4842       goto release;
4843     }
4844
4845   /* if I can do an decrement instead
4846      of subtract then GOOD for ME */
4847   if (genMinusDec (ic) == TRUE)
4848     goto release;
4849
4850   size = getDataSize (IC_RESULT (ic));
4851
4852   /* if literal, add a,#-lit, else normal subb */
4853   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4854     {
4855       unsigned long lit = 0L;
4856       bool useCarry = FALSE;
4857
4858       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4859       lit = -(long) lit;
4860
4861       while (size--)
4862         {
4863           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4864             {
4865               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4866               if (!offset && !size && lit== (unsigned long) -1)
4867                 {
4868                   emitcode ("dec", "a");
4869                 }
4870               else if (!useCarry)
4871                 {
4872                   /* first add without previous c */
4873                   emitcode ("add", "a,#0x%02x",
4874                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4875                   useCarry = TRUE;
4876                 }
4877               else
4878                 {
4879                   emitcode ("addc", "a,#0x%02x",
4880                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4881                 }
4882               aopPut (IC_RESULT (ic), "a", offset++);
4883             }
4884           else
4885             {
4886               /* no need to add zeroes */
4887               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4888                 {
4889                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4890                           offset);
4891                 }
4892               offset++;
4893             }
4894         }
4895     }
4896   else
4897     {
4898       operand *leftOp, *rightOp;
4899
4900       leftOp = IC_LEFT(ic);
4901       rightOp = IC_RIGHT(ic);
4902
4903       while (size--)
4904         {
4905           if (aopGetUsesAcc(rightOp, offset)) {
4906             if (aopGetUsesAcc(leftOp, offset)) {
4907               bool pushedB;
4908
4909               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4910               pushedB = pushB ();
4911               emitcode ("mov", "b,a");
4912               if (offset == 0)
4913                 CLRC;
4914               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4915               emitcode ("subb", "a,b");
4916               popB (pushedB);
4917             } else {
4918               /* reverse subtraction with 2's complement */
4919               if (offset == 0)
4920                 emitcode( "setb", "c");
4921               else
4922                 emitcode( "cpl", "c");
4923               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4924               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4925               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4926               emitcode("cpl", "a");
4927               if (size) /* skip if last byte */
4928                 emitcode( "cpl", "c");
4929             }
4930           } else {
4931             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4932             if (offset == 0)
4933               CLRC;
4934             emitcode ("subb", "a,%s",
4935                       aopGet(rightOp, offset, FALSE, TRUE));
4936           }
4937
4938           aopPut (IC_RESULT (ic), "a", offset++);
4939         }
4940     }
4941
4942   adjustArithmeticResult (ic);
4943
4944 release:
4945   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4946   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4947   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4948 }
4949
4950
4951 /*-----------------------------------------------------------------*/
4952 /* genMultbits :- multiplication of bits                           */
4953 /*-----------------------------------------------------------------*/
4954 static void
4955 genMultbits (operand * left,
4956              operand * right,
4957              operand * result)
4958 {
4959   D (emitcode (";", "genMultbits"));
4960
4961   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4962   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4963   outBitC (result);
4964 }
4965
4966 /*-----------------------------------------------------------------*/
4967 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4968 /*-----------------------------------------------------------------*/
4969 static void
4970 genMultOneByte (operand * left,
4971                 operand * right,
4972                 operand * result)
4973 {
4974   symbol *lbl;
4975   int size = AOP_SIZE (result);
4976   bool runtimeSign, compiletimeSign;
4977   bool lUnsigned, rUnsigned, pushedB;
4978
4979   D (emitcode (";", "genMultOneByte"));
4980
4981   if (size < 1 || size > 2)
4982     {
4983       /* this should never happen */
4984       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4985                AOP_SIZE(result), __FILE__, lineno);
4986       exit (1);
4987     }
4988
4989   /* (if two literals: the value is computed before) */
4990   /* if one literal, literal on the right */
4991   if (AOP_TYPE (left) == AOP_LIT)
4992     {
4993       operand *t = right;
4994       right = left;
4995       left = t;
4996       /* emitcode (";", "swapped left and right"); */
4997     }
4998   /* if no literal, unsigned on the right: shorter code */
4999   if (   AOP_TYPE (right) != AOP_LIT
5000       && SPEC_USIGN (getSpec (operandType (left))))
5001     {
5002       operand *t = right;
5003       right = left;
5004       left = t;
5005     }
5006
5007   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5008   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5009
5010   pushedB = pushB ();
5011
5012   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5013                    no need to take care about the signedness! */
5014       || (lUnsigned && rUnsigned))
5015     {
5016       /* just an unsigned 8 * 8 = 8 multiply
5017          or 8u * 8u = 16u */
5018       /* emitcode (";","unsigned"); */
5019       /* TODO: check for accumulator clash between left & right aops? */
5020
5021       if (AOP_TYPE (right) == AOP_LIT)
5022         {
5023           /* moving to accumulator first helps peepholes */
5024           MOVA (aopGet (left, 0, FALSE, FALSE));
5025           MOVB (aopGet (right, 0, FALSE, FALSE));
5026         }
5027       else
5028         {
5029           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5030           MOVA (aopGet (left, 0, FALSE, FALSE));
5031         }
5032
5033       emitcode ("mul", "ab");
5034       aopPut (result, "a", 0);
5035       if (size == 2)
5036         aopPut (result, "b", 1);
5037
5038       popB (pushedB);
5039       return;
5040     }
5041
5042   /* we have to do a signed multiply */
5043   /* emitcode (";", "signed"); */
5044
5045   /* now sign adjust for both left & right */
5046
5047   /* let's see what's needed: */
5048   /* apply negative sign during runtime */
5049   runtimeSign = FALSE;
5050   /* negative sign from literals */
5051   compiletimeSign = FALSE;
5052
5053   if (!lUnsigned)
5054     {
5055       if (AOP_TYPE(left) == AOP_LIT)
5056         {
5057           /* signed literal */
5058           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5059           if (val < 0)
5060             compiletimeSign = TRUE;
5061         }
5062       else
5063         /* signed but not literal */
5064         runtimeSign = TRUE;
5065     }
5066
5067   if (!rUnsigned)
5068     {
5069       if (AOP_TYPE(right) == AOP_LIT)
5070         {
5071           /* signed literal */
5072           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5073           if (val < 0)
5074             compiletimeSign ^= TRUE;
5075         }
5076       else
5077         /* signed but not literal */
5078         runtimeSign = TRUE;
5079     }
5080
5081   /* initialize F0, which stores the runtime sign */
5082   if (runtimeSign)
5083     {
5084       if (compiletimeSign)
5085         emitcode ("setb", "F0"); /* set sign flag */
5086       else
5087         emitcode ("clr", "F0"); /* reset sign flag */
5088     }
5089
5090   /* save the signs of the operands */
5091   if (AOP_TYPE(right) == AOP_LIT)
5092     {
5093       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5094
5095       if (!rUnsigned && val < 0)
5096         emitcode ("mov", "b,#0x%02x", -val);
5097       else
5098         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5099     }
5100   else /* ! literal */
5101     {
5102       if (rUnsigned)  /* emitcode (";", "signed"); */
5103         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5104       else
5105         {
5106           MOVA (aopGet (right, 0, FALSE, FALSE));
5107           lbl = newiTempLabel (NULL);
5108           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5109           emitcode ("cpl", "F0"); /* complement sign flag */
5110           emitcode ("cpl", "a");  /* 2's complement */
5111           emitcode ("inc", "a");
5112           emitLabel (lbl);
5113           emitcode ("mov", "b,a");
5114         }
5115     }
5116
5117   if (AOP_TYPE(left) == AOP_LIT)
5118     {
5119       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5120
5121       if (!lUnsigned && val < 0)
5122         emitcode ("mov", "a,#0x%02x", -val);
5123       else
5124         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5125     }
5126   else /* ! literal */
5127     {
5128       MOVA (aopGet (left, 0, FALSE, FALSE));
5129
5130       if (!lUnsigned)
5131         {
5132           lbl = newiTempLabel (NULL);
5133           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5134           emitcode ("cpl", "F0"); /* complement sign flag */
5135           emitcode ("cpl", "a"); /* 2's complement */
5136           emitcode ("inc", "a");
5137           emitLabel (lbl);
5138         }
5139     }
5140
5141   /* now the multiplication */
5142   emitcode ("mul", "ab");
5143   if (runtimeSign || compiletimeSign)
5144     {
5145       lbl = newiTempLabel (NULL);
5146       if (runtimeSign)
5147         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5148       emitcode ("cpl", "a"); /* lsb 2's complement */
5149       if (size != 2)
5150         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5151       else
5152         {
5153           emitcode ("add", "a,#1"); /* this sets carry flag */
5154           emitcode ("xch", "a,b");
5155           emitcode ("cpl", "a"); /* msb 2's complement */
5156           emitcode ("addc", "a,#0");
5157           emitcode ("xch", "a,b");
5158         }
5159       emitLabel (lbl);
5160     }
5161   aopPut (result, "a", 0);
5162   if (size == 2)
5163     aopPut (result, "b", 1);
5164
5165   popB (pushedB);
5166 }
5167
5168 /*-----------------------------------------------------------------*/
5169 /* genMult - generates code for multiplication                     */
5170 /*-----------------------------------------------------------------*/
5171 static void
5172 genMult (iCode * ic)
5173 {
5174   operand *left = IC_LEFT (ic);
5175   operand *right = IC_RIGHT (ic);
5176   operand *result = IC_RESULT (ic);
5177
5178   D (emitcode (";", "genMult"));
5179
5180   /* assign the asmops */
5181   aopOp (left, ic, FALSE);
5182   aopOp (right, ic, FALSE);
5183   aopOp (result, ic, TRUE);
5184
5185   /* special cases first */
5186   /* both are bits */
5187   if (AOP_TYPE (left) == AOP_CRY &&
5188       AOP_TYPE (right) == AOP_CRY)
5189     {
5190       genMultbits (left, right, result);
5191       goto release;
5192     }
5193
5194   /* if both are of size == 1 */
5195 #if 0 // one of them can be a sloc shared with the result
5196     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5197 #else
5198   if (getSize(operandType(left)) == 1 &&
5199       getSize(operandType(right)) == 1)
5200 #endif
5201     {
5202       genMultOneByte (left, right, result);
5203       goto release;
5204     }
5205
5206   /* should have been converted to function call */
5207     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5208              getSize(OP_SYMBOL(right)->type));
5209   assert (0);
5210
5211 release:
5212   freeAsmop (result, NULL, ic, TRUE);
5213   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5214   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5215 }
5216
5217 /*-----------------------------------------------------------------*/
5218 /* genDivbits :- division of bits                                  */
5219 /*-----------------------------------------------------------------*/
5220 static void
5221 genDivbits (operand * left,
5222             operand * right,
5223             operand * result)
5224 {
5225   char *l;
5226   bool pushedB;
5227
5228   D(emitcode (";     genDivbits",""));
5229
5230   pushedB = pushB ();
5231
5232   /* the result must be bit */
5233   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5234   l = aopGet (left, 0, FALSE, FALSE);
5235
5236   MOVA (l);
5237
5238   emitcode ("div", "ab");
5239   emitcode ("rrc", "a");
5240
5241   popB (pushedB);
5242
5243   aopPut (result, "c", 0);
5244 }
5245
5246 /*-----------------------------------------------------------------*/
5247 /* genDivOneByte : 8 bit division                                  */
5248 /*-----------------------------------------------------------------*/
5249 static void
5250 genDivOneByte (operand * left,
5251                operand * right,
5252                operand * result)
5253 {
5254   bool lUnsigned, rUnsigned, pushedB;
5255   bool runtimeSign, compiletimeSign;
5256   bool accuse = FALSE;
5257   bool pushedA = FALSE;
5258   symbol *lbl;
5259   int size, offset;
5260
5261   D(emitcode (";     genDivOneByte",""));
5262
5263   /* Why is it necessary that genDivOneByte() can return an int result?
5264      Have a look at:
5265
5266         volatile unsigned char uc;
5267         volatile signed char sc1, sc2;
5268         volatile int i;
5269
5270         uc  = 255;
5271         sc1 = -1;
5272         i = uc / sc1;
5273
5274      Or:
5275
5276         sc1 = -128;
5277         sc2 = -1;
5278         i = sc1 / sc2;
5279
5280      In all cases a one byte result would overflow, the following cast to int
5281      would return the wrong result.
5282
5283      Two possible solution:
5284         a) cast operands to int, if ((unsigned) / (signed)) or
5285            ((signed) / (signed))
5286         b) return an 16 bit signed int; this is what we're doing here!
5287   */
5288
5289   size = AOP_SIZE (result) - 1;
5290   offset = 1;
5291   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5292   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5293
5294   pushedB = pushB ();
5295
5296   /* signed or unsigned */
5297   if (lUnsigned && rUnsigned)
5298     {
5299       /* unsigned is easy */
5300       MOVB (aopGet (right, 0, FALSE, FALSE));
5301       MOVA (aopGet (left, 0, FALSE, FALSE));
5302       emitcode ("div", "ab");
5303       aopPut (result, "a", 0);
5304       while (size--)
5305         aopPut (result, zero, offset++);
5306
5307       popB (pushedB);
5308       return;
5309     }
5310
5311   /* signed is a little bit more difficult */
5312
5313   /* now sign adjust for both left & right */
5314
5315   /* let's see what's needed: */
5316   /* apply negative sign during runtime */
5317   runtimeSign = FALSE;
5318   /* negative sign from literals */
5319   compiletimeSign = FALSE;
5320
5321   if (!lUnsigned)
5322     {
5323       if (AOP_TYPE(left) == AOP_LIT)
5324         {
5325           /* signed literal */
5326           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5327           if (val < 0)
5328             compiletimeSign = TRUE;
5329         }
5330       else
5331         /* signed but not literal */
5332         runtimeSign = TRUE;
5333     }
5334
5335   if (!rUnsigned)
5336     {
5337       if (AOP_TYPE(right) == AOP_LIT)
5338         {
5339           /* signed literal */
5340           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5341           if (val < 0)
5342             compiletimeSign ^= TRUE;
5343         }
5344       else
5345         /* signed but not literal */
5346         runtimeSign = TRUE;
5347     }
5348
5349   /* initialize F0, which stores the runtime sign */
5350   if (runtimeSign)
5351     {
5352       if (compiletimeSign)
5353         emitcode ("setb", "F0"); /* set sign flag */
5354       else
5355         emitcode ("clr", "F0"); /* reset sign flag */
5356     }
5357
5358   /* save the signs of the operands */
5359   if (AOP_TYPE(right) == AOP_LIT)
5360     {
5361       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5362
5363       if (!rUnsigned && val < 0)
5364         emitcode ("mov", "b,#0x%02x", -val);
5365       else
5366         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5367     }
5368   else /* ! literal */
5369     {
5370       if (rUnsigned)
5371         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5372       else
5373         {
5374           MOVA (aopGet (right, 0, FALSE, FALSE));
5375           lbl = newiTempLabel (NULL);
5376           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5377           emitcode ("cpl", "F0"); /* complement sign flag */
5378           emitcode ("cpl", "a");  /* 2's complement */
5379           emitcode ("inc", "a");
5380           emitLabel (lbl);
5381           emitcode ("mov", "b,a");
5382         }
5383     }
5384
5385   if (AOP_TYPE(left) == AOP_LIT)
5386     {
5387       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5388
5389       if (!lUnsigned && val < 0)
5390         emitcode ("mov", "a,#0x%02x", -val);
5391       else
5392         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5393     }
5394   else /* ! literal */
5395     {
5396       MOVA (aopGet (left, 0, FALSE, FALSE));
5397
5398       if (!lUnsigned)
5399         {
5400           lbl = newiTempLabel (NULL);
5401           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5402           emitcode ("cpl", "F0"); /* complement sign flag */
5403           emitcode ("cpl", "a");  /* 2's complement */
5404           emitcode ("inc", "a");
5405           emitLabel (lbl);
5406         }
5407     }
5408
5409   /* now the division */
5410   emitcode ("div", "ab");
5411
5412   if (runtimeSign || compiletimeSign)
5413     {
5414       lbl = newiTempLabel (NULL);
5415       if (runtimeSign)
5416         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5417       emitcode ("cpl", "a"); /* lsb 2's complement */
5418       emitcode ("inc", "a");
5419       emitLabel (lbl);
5420
5421       accuse = aopPut (result, "a", 0);
5422       if (size > 0)
5423         {
5424           /* msb is 0x00 or 0xff depending on the sign */
5425           if (runtimeSign)
5426             {
5427               if (accuse)
5428                 {
5429                   emitcode ("push", "acc");
5430                   pushedA = TRUE;
5431                 }
5432               emitcode ("mov", "c,F0");
5433               emitcode ("subb", "a,acc");
5434               while (size--)
5435                 aopPut (result, "a", offset++);
5436             }
5437           else /* compiletimeSign */
5438             {
5439               if (aopPutUsesAcc (result, "#0xFF", offset))
5440                 {
5441                   emitcode ("push", "acc");
5442                   pushedA = TRUE;
5443                 }
5444               while (size--)
5445                 aopPut (result, "#0xff", offset++);
5446             }
5447         }
5448     }
5449   else
5450     {
5451       aopPut (result, "a", 0);
5452       while (size--)
5453         aopPut (result, zero, offset++);
5454     }
5455
5456   if (pushedA)
5457     emitcode ("pop", "acc");
5458   popB (pushedB);
5459 }
5460
5461 /*-----------------------------------------------------------------*/
5462 /* genDiv - generates code for division                            */
5463 /*-----------------------------------------------------------------*/
5464 static void
5465 genDiv (iCode * ic)
5466 {
5467   operand *left = IC_LEFT (ic);
5468   operand *right = IC_RIGHT (ic);
5469   operand *result = IC_RESULT (ic);
5470
5471   D (emitcode (";", "genDiv"));
5472
5473   /* assign the amsops */
5474   aopOp (left, ic, FALSE);
5475   aopOp (right, ic, FALSE);
5476   aopOp (result, ic, TRUE);
5477
5478   /* special cases first */
5479   /* both are bits */
5480   if (AOP_TYPE (left) == AOP_CRY &&
5481       AOP_TYPE (right) == AOP_CRY)
5482     {
5483       genDivbits (left, right, result);
5484       goto release;
5485     }
5486
5487   /* if both are of size == 1 */
5488   if (AOP_SIZE (left) == 1 &&
5489       AOP_SIZE (right) == 1)
5490     {
5491       genDivOneByte (left, right, result);
5492       goto release;
5493     }
5494
5495   /* should have been converted to function call */
5496   assert (0);
5497 release:
5498   freeAsmop (result, NULL, ic, TRUE);
5499   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5500   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5501 }
5502
5503 /*-----------------------------------------------------------------*/
5504 /* genModbits :- modulus of bits                                   */
5505 /*-----------------------------------------------------------------*/
5506 static void
5507 genModbits (operand * left,
5508             operand * right,
5509             operand * result)
5510 {
5511   char *l;
5512   bool pushedB;
5513
5514   D (emitcode (";", "genModbits"));
5515
5516   pushedB = pushB ();
5517
5518   /* the result must be bit */
5519   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5520   l = aopGet (left, 0, FALSE, FALSE);
5521
5522   MOVA (l);
5523
5524   emitcode ("div", "ab");
5525   emitcode ("mov", "a,b");
5526   emitcode ("rrc", "a");
5527
5528   popB (pushedB);
5529
5530   aopPut (result, "c", 0);
5531 }
5532
5533 /*-----------------------------------------------------------------*/
5534 /* genModOneByte : 8 bit modulus                                   */
5535 /*-----------------------------------------------------------------*/
5536 static void
5537 genModOneByte (operand * left,
5538                operand * right,
5539                operand * result)
5540 {
5541   bool lUnsigned, rUnsigned, pushedB;
5542   bool runtimeSign, compiletimeSign;
5543   symbol *lbl;
5544   int size, offset;
5545
5546   D (emitcode (";", "genModOneByte"));
5547
5548   size = AOP_SIZE (result) - 1;
5549   offset = 1;
5550   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5551   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5552
5553   /* if right is a literal, check it for 2^n */
5554   if (AOP_TYPE(right) == AOP_LIT)
5555     {
5556       unsigned char val = abs((int) operandLitValue(right));
5557       symbol *lbl2 = NULL;
5558
5559       switch (val)
5560         {
5561           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5562           case 2:
5563           case 4:
5564           case 8:
5565           case 16:
5566           case 32:
5567           case 64:
5568           case 128:
5569             if (lUnsigned)
5570               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5571                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5572               /* because iCode should have been changed to genAnd  */
5573               /* see file "SDCCopt.c", function "convertToFcall()" */
5574
5575             MOVA (aopGet (left, 0, FALSE, FALSE));
5576             emitcode ("mov", "c,acc.7");
5577             emitcode ("anl", "a,#0x%02x", val - 1);
5578             lbl = newiTempLabel (NULL);
5579             emitcode ("jz", "%05d$", (lbl->key + 100));
5580             emitcode ("jnc", "%05d$", (lbl->key + 100));
5581             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5582             if (size)
5583               {
5584                 int size2 = size;
5585                 int offs2 = offset;
5586
5587                 aopPut (result, "a", 0);
5588                 while (size2--)
5589                   aopPut (result, "#0xff", offs2++);
5590                 lbl2 = newiTempLabel (NULL);
5591                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5592               }
5593             emitLabel (lbl);
5594             aopPut (result, "a", 0);
5595             while (size--)
5596               aopPut (result, zero, offset++);
5597             if (lbl2)
5598               {
5599                 emitLabel (lbl2);
5600               }
5601             return;
5602
5603           default:
5604             break;
5605         }
5606     }
5607
5608   pushedB = pushB ();
5609
5610   /* signed or unsigned */
5611   if (lUnsigned && rUnsigned)
5612     {
5613       /* unsigned is easy */
5614       MOVB (aopGet (right, 0, FALSE, FALSE));
5615       MOVA (aopGet (left, 0, FALSE, FALSE));
5616       emitcode ("div", "ab");
5617       aopPut (result, "b", 0);
5618       while (size--)
5619         aopPut (result, zero, offset++);
5620
5621       popB (pushedB);
5622       return;
5623     }
5624
5625   /* signed is a little bit more difficult */
5626
5627   /* now sign adjust for both left & right */
5628
5629   /* modulus: sign of the right operand has no influence on the result! */
5630   if (AOP_TYPE(right) == AOP_LIT)
5631     {
5632       signed char val = (char) operandLitValue(right);
5633
5634       if (!rUnsigned && val < 0)
5635         emitcode ("mov", "b,#0x%02x", -val);
5636       else
5637         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5638     }
5639   else /* not literal */
5640     {
5641       if (rUnsigned)
5642         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5643       else
5644         {
5645           MOVA (aopGet (right, 0, FALSE, FALSE));
5646           lbl = newiTempLabel (NULL);
5647           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5648           emitcode ("cpl", "a"); /* 2's complement */
5649           emitcode ("inc", "a");
5650           emitLabel (lbl);
5651           emitcode ("mov", "b,a");
5652         }
5653     }
5654
5655   /* let's see what's needed: */
5656   /* apply negative sign during runtime */
5657   runtimeSign = FALSE;
5658   /* negative sign from literals */
5659   compiletimeSign = FALSE;
5660
5661   /* sign adjust left side */
5662   if (AOP_TYPE(left) == AOP_LIT)
5663     {
5664       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5665
5666       if (!lUnsigned && val < 0)
5667         {
5668           compiletimeSign = TRUE; /* set sign flag */
5669           emitcode ("mov", "a,#0x%02x", -val);
5670         }
5671       else
5672         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5673     }
5674   else /* ! literal */
5675     {
5676       MOVA (aopGet (left, 0, FALSE, FALSE));
5677
5678       if (!lUnsigned)
5679         {
5680           runtimeSign = TRUE;
5681           emitcode ("clr", "F0"); /* clear sign flag */
5682
5683           lbl = newiTempLabel (NULL);
5684           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5685           emitcode ("setb", "F0"); /* set sign flag */
5686           emitcode ("cpl", "a");   /* 2's complement */
5687           emitcode ("inc", "a");
5688           emitLabel (lbl);
5689         }
5690     }
5691
5692   /* now the modulus */
5693   emitcode ("div", "ab");
5694
5695   if (runtimeSign || compiletimeSign)
5696     {
5697       emitcode ("mov", "a,b");
5698       lbl = newiTempLabel (NULL);
5699       if (runtimeSign)
5700         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5701       emitcode ("cpl", "a"); /* 2's complement */
5702       emitcode ("inc", "a");
5703       emitLabel (lbl);
5704
5705       aopPut (result, "a", 0);
5706       if (size > 0)
5707         {
5708           /* msb is 0x00 or 0xff depending on the sign */
5709           if (runtimeSign)
5710             {
5711               emitcode ("mov", "c,F0");
5712               emitcode ("subb", "a,acc");
5713               while (size--)
5714                 aopPut (result, "a", offset++);
5715             }
5716           else /* compiletimeSign */
5717             while (size--)
5718               aopPut (result, "#0xff", offset++);
5719         }
5720     }
5721   else
5722     {
5723       aopPut (result, "b", 0);
5724       while (size--)
5725         aopPut (result, zero, offset++);
5726     }
5727
5728   popB (pushedB);
5729 }
5730
5731 /*-----------------------------------------------------------------*/
5732 /* genMod - generates code for division                            */
5733 /*-----------------------------------------------------------------*/
5734 static void
5735 genMod (iCode * ic)
5736 {
5737   operand *left = IC_LEFT (ic);
5738   operand *right = IC_RIGHT (ic);
5739   operand *result = IC_RESULT (ic);
5740
5741   D (emitcode (";", "genMod"));
5742
5743   /* assign the asmops */
5744   aopOp (left, ic, FALSE);
5745   aopOp (right, ic, FALSE);
5746   aopOp (result, ic, TRUE);
5747
5748   /* special cases first */
5749   /* both are bits */
5750   if (AOP_TYPE (left) == AOP_CRY &&
5751       AOP_TYPE (right) == AOP_CRY)
5752     {
5753       genModbits (left, right, result);
5754       goto release;
5755     }
5756
5757   /* if both are of size == 1 */
5758   if (AOP_SIZE (left) == 1 &&
5759       AOP_SIZE (right) == 1)
5760     {
5761       genModOneByte (left, right, result);
5762       goto release;
5763     }
5764
5765   /* should have been converted to function call */
5766   assert (0);
5767
5768 release:
5769   freeAsmop (result, NULL, ic, TRUE);
5770   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5771   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5772 }
5773
5774 /*-----------------------------------------------------------------*/
5775 /* genIfxJump :- will create a jump depending on the ifx           */
5776 /*-----------------------------------------------------------------*/
5777 static void
5778 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5779 {
5780   symbol *jlbl;
5781   symbol *tlbl = newiTempLabel (NULL);
5782   char *inst;
5783
5784   D (emitcode (";", "genIfxJump"));
5785
5786   /* if true label then we jump if condition
5787      supplied is true */
5788   if (IC_TRUE (ic))
5789     {
5790       jlbl = IC_TRUE (ic);
5791       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5792                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5793     }
5794   else
5795     {
5796       /* false label is present */
5797       jlbl = IC_FALSE (ic);
5798       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5799                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5800     }
5801   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5802     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5803   else
5804     emitcode (inst, "%05d$", tlbl->key + 100);
5805   freeForBranchAsmop (result);
5806   freeForBranchAsmop (right);
5807   freeForBranchAsmop (left);
5808   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5809   emitLabel (tlbl);
5810
5811   /* mark the icode as generated */
5812   ic->generated = 1;
5813 }
5814
5815 /*-----------------------------------------------------------------*/
5816 /* genCmp :- greater or less than comparison                       */
5817 /*-----------------------------------------------------------------*/
5818 static void
5819 genCmp (operand * left, operand * right,
5820         operand * result, iCode * ifx, int sign, iCode *ic)
5821 {
5822   int size, offset = 0;
5823   unsigned long lit = 0L;
5824   bool rightInB;
5825
5826   D (emitcode (";", "genCmp"));
5827
5828   /* if left & right are bit variables */
5829   if (AOP_TYPE (left) == AOP_CRY &&
5830       AOP_TYPE (right) == AOP_CRY)
5831     {
5832       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5833       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5834     }
5835   else
5836     {
5837       /* subtract right from left if at the
5838          end the carry flag is set then we know that
5839          left is greater than right */
5840       size = max (AOP_SIZE (left), AOP_SIZE (right));
5841
5842       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5843       if ((size == 1) && !sign &&
5844           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5845         {
5846           symbol *lbl = newiTempLabel (NULL);
5847           emitcode ("cjne", "%s,%s,%05d$",
5848                     aopGet (left, offset, FALSE, FALSE),
5849                     aopGet (right, offset, FALSE, FALSE),
5850                     lbl->key + 100);
5851           emitLabel (lbl);
5852         }
5853       else
5854         {
5855           if (AOP_TYPE (right) == AOP_LIT)
5856             {
5857               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5858               /* optimize if(x < 0) or if(x >= 0) */
5859               if (lit == 0L)
5860                 {
5861                   if (!sign)
5862                     {
5863                       CLRC;
5864                     }
5865                   else
5866                     {
5867                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5868                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5869                         {
5870                           genIfxJump (ifx, "acc.7", left, right, result);
5871                           freeAsmop (right, NULL, ic, TRUE);
5872                           freeAsmop (left, NULL, ic, TRUE);
5873
5874                           return;
5875                         }
5876                       else
5877                         {
5878                           emitcode ("rlc", "a");
5879                         }
5880                     }
5881                   goto release;
5882                 }
5883               else
5884                 {//nonzero literal
5885                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5886                   while (size && (bytelit == 0))
5887                     {
5888                       offset++;
5889                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5890                       size--;
5891                     }
5892                   CLRC;
5893                   while (size--)
5894                     {
5895                       MOVA (aopGet (left, offset, FALSE, FALSE));
5896                       if (sign && size == 0)
5897                         {
5898                           emitcode ("xrl", "a,#0x80");
5899                           emitcode ("subb", "a,#0x%02x",
5900                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5901                         }
5902                       else
5903                         {
5904                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5905                         }
5906                       offset++;
5907                     }
5908                   goto release;
5909                 }
5910             }
5911           CLRC;
5912           while (size--)
5913             {
5914               bool pushedB = FALSE;
5915               rightInB = aopGetUsesAcc(right, offset);
5916               if (rightInB)
5917                 {
5918                   pushedB = pushB ();
5919                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5920                 }
5921               MOVA (aopGet (left, offset, FALSE, FALSE));
5922               if (sign && size == 0)
5923                 {
5924                   emitcode ("xrl", "a,#0x80");
5925                   if (!rightInB)
5926                     {
5927                       pushedB = pushB ();
5928                       rightInB++;
5929                       MOVB (aopGet (right, offset, FALSE, FALSE));
5930                     }
5931                   emitcode ("xrl", "b,#0x80");
5932                   emitcode ("subb", "a,b");
5933                 }
5934               else
5935                 {
5936                   if (rightInB)
5937                     emitcode ("subb", "a,b");
5938                   else
5939                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5940                 }
5941               if (rightInB)
5942                 popB (pushedB);
5943               offset++;
5944             }
5945         }
5946     }
5947
5948 release:
5949   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5950   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5951   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5952     {
5953       outBitC (result);
5954     }
5955   else
5956     {
5957       /* if the result is used in the next
5958          ifx conditional branch then generate
5959          code a little differently */
5960       if (ifx)
5961         {
5962           genIfxJump (ifx, "c", NULL, NULL, result);
5963         }
5964       else
5965         {
5966           outBitC (result);
5967         }
5968       /* leave the result in acc */
5969     }
5970 }
5971
5972 /*-----------------------------------------------------------------*/
5973 /* genCmpGt :- greater than comparison                             */
5974 /*-----------------------------------------------------------------*/
5975 static void
5976 genCmpGt (iCode * ic, iCode * ifx)
5977 {
5978   operand *left, *right, *result;
5979   sym_link *letype, *retype;
5980   int sign;
5981
5982   D (emitcode (";", "genCmpGt"));
5983
5984   left = IC_LEFT (ic);
5985   right = IC_RIGHT (ic);
5986   result = IC_RESULT (ic);
5987
5988   letype = getSpec (operandType (left));
5989   retype = getSpec (operandType (right));
5990   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5991            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5992   /* assign the amsops */
5993   aopOp (result, ic, TRUE);
5994   aopOp (left, ic, FALSE);
5995   aopOp (right, ic, FALSE);
5996
5997   genCmp (right, left, result, ifx, sign, ic);
5998
5999   freeAsmop (result, NULL, ic, TRUE);
6000 }
6001
6002 /*-----------------------------------------------------------------*/
6003 /* genCmpLt - less than comparisons                                */
6004 /*-----------------------------------------------------------------*/
6005 static void
6006 genCmpLt (iCode * ic, iCode * ifx)
6007 {
6008   operand *left, *right, *result;
6009   sym_link *letype, *retype;
6010   int sign;
6011
6012   D (emitcode (";", "genCmpLt"));
6013
6014   left = IC_LEFT (ic);
6015   right = IC_RIGHT (ic);
6016   result = IC_RESULT (ic);
6017
6018   letype = getSpec (operandType (left));
6019   retype = getSpec (operandType (right));
6020   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6021            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6022   /* assign the amsops */
6023   aopOp (result, ic, TRUE);
6024   aopOp (left, ic, FALSE);
6025   aopOp (right, ic, FALSE);
6026
6027   genCmp (left, right, result, ifx, sign, ic);
6028
6029   freeAsmop (result, NULL, ic, TRUE);
6030 }
6031
6032 /*-----------------------------------------------------------------*/
6033 /* gencjneshort - compare and jump if not equal                    */
6034 /*-----------------------------------------------------------------*/
6035 static void
6036 gencjneshort (operand * left, operand * right, symbol * lbl)
6037 {
6038   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6039   int offset = 0;
6040   unsigned long lit = 0L;
6041
6042   D (emitcode (";", "gencjneshort"));
6043
6044   /* if the left side is a literal or
6045      if the right is in a pointer register and left
6046      is not */
6047   if ((AOP_TYPE (left) == AOP_LIT) ||
6048       (AOP_TYPE (left) == AOP_IMMD) ||
6049       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6050     {
6051       operand *t = right;
6052       right = left;
6053       left = t;
6054     }
6055
6056   if (AOP_TYPE (right) == AOP_LIT)
6057     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6058
6059   /* if the right side is a literal then anything goes */
6060   if (AOP_TYPE (right) == AOP_LIT &&
6061       AOP_TYPE (left) != AOP_DIR  &&
6062       AOP_TYPE (left) != AOP_IMMD)
6063     {
6064       while (size--)
6065         {
6066           emitcode ("cjne", "%s,%s,%05d$",
6067                     aopGet (left, offset, FALSE, FALSE),
6068                     aopGet (right, offset, FALSE, FALSE),
6069                     lbl->key + 100);
6070           offset++;
6071         }
6072     }
6073
6074   /* if the right side is in a register or in direct space or
6075      if the left is a pointer register & right is not */
6076   else if (AOP_TYPE (right) == AOP_REG ||
6077            AOP_TYPE (right) == AOP_DIR ||
6078            AOP_TYPE (right) == AOP_LIT ||
6079            AOP_TYPE (right) == AOP_IMMD ||
6080            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6081            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6082     {
6083       while (size--)
6084         {
6085           MOVA (aopGet (left, offset, FALSE, FALSE));
6086           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6087               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6088             emitcode ("jnz", "%05d$", lbl->key + 100);
6089           else
6090             emitcode ("cjne", "a,%s,%05d$",
6091                       aopGet (right, offset, FALSE, TRUE),
6092                       lbl->key + 100);
6093           offset++;
6094         }
6095     }
6096   else
6097     {
6098       /* right is a pointer reg need both a & b */
6099       while (size--)
6100         {
6101           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6102           wassertl(!BINUSE, "B was in use");
6103           MOVB (aopGet (left, offset, FALSE, FALSE));
6104           MOVA (aopGet (right, offset, FALSE, FALSE));
6105           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6106           offset++;
6107         }
6108     }
6109 }
6110
6111 /*-----------------------------------------------------------------*/
6112 /* gencjne - compare and jump if not equal                         */
6113 /*-----------------------------------------------------------------*/
6114 static void
6115 gencjne (operand * left, operand * right, symbol * lbl)
6116 {
6117   symbol *tlbl = newiTempLabel (NULL);
6118
6119   D (emitcode (";", "gencjne"));
6120
6121   gencjneshort (left, right, lbl);
6122
6123   emitcode ("mov", "a,%s", one);
6124   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6125   emitLabel (lbl);
6126   emitcode ("clr", "a");
6127   emitLabel (tlbl);
6128 }
6129
6130 /*-----------------------------------------------------------------*/
6131 /* genCmpEq - generates code for equal to                          */
6132 /*-----------------------------------------------------------------*/
6133 static void
6134 genCmpEq (iCode * ic, iCode * ifx)
6135 {
6136   bool swappedLR = FALSE;
6137   operand *left, *right, *result;
6138
6139   D (emitcode (";", "genCmpEq"));
6140
6141   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6142   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6143   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6144
6145   /* if literal, literal on the right or
6146      if the right is in a pointer register and left
6147      is not */
6148   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6149       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6150     {
6151       operand *t = IC_RIGHT (ic);
6152       IC_RIGHT (ic) = IC_LEFT (ic);
6153       IC_LEFT (ic) = t;
6154       swappedLR = TRUE;
6155     }
6156
6157   if (ifx && !AOP_SIZE (result))
6158     {
6159       symbol *tlbl;
6160       /* if they are both bit variables */
6161       if (AOP_TYPE (left) == AOP_CRY &&
6162           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6163         {
6164           if (AOP_TYPE (right) == AOP_LIT)
6165             {
6166               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6167               if (lit == 0L)
6168                 {
6169                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6170                   emitcode ("cpl", "c");
6171                 }
6172               else if (lit == 1L)
6173                 {
6174                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6175                 }
6176               else
6177                 {
6178                   emitcode ("clr", "c");
6179                 }
6180               /* AOP_TYPE(right) == AOP_CRY */
6181             }
6182           else
6183             {
6184               symbol *lbl = newiTempLabel (NULL);
6185               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6186               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6187               emitcode ("cpl", "c");
6188               emitLabel (lbl);
6189             }
6190           /* if true label then we jump if condition
6191              supplied is true */
6192           tlbl = newiTempLabel (NULL);
6193           if (IC_TRUE (ifx))
6194             {
6195               emitcode ("jnc", "%05d$", tlbl->key + 100);
6196               freeForBranchAsmop (result);
6197               freeForBranchAsmop (right);
6198               freeForBranchAsmop (left);
6199               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6200             }
6201           else
6202             {
6203               emitcode ("jc", "%05d$", tlbl->key + 100);
6204               freeForBranchAsmop (result);
6205               freeForBranchAsmop (right);
6206               freeForBranchAsmop (left);
6207               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6208             }
6209           emitLabel (tlbl);
6210         }
6211       else
6212         {
6213           tlbl = newiTempLabel (NULL);
6214           gencjneshort (left, right, tlbl);
6215           if (IC_TRUE (ifx))
6216             {
6217               freeForBranchAsmop (result);
6218               freeForBranchAsmop (right);
6219               freeForBranchAsmop (left);
6220               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6221               emitLabel (tlbl);
6222             }
6223           else
6224             {
6225               symbol *lbl = newiTempLabel (NULL);
6226               emitcode ("sjmp", "%05d$", lbl->key + 100);
6227               emitLabel (tlbl);
6228               freeForBranchAsmop (result);
6229               freeForBranchAsmop (right);
6230               freeForBranchAsmop (left);
6231               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6232               emitLabel (lbl);
6233             }
6234         }
6235       /* mark the icode as generated */
6236       ifx->generated = 1;
6237       goto release;
6238     }
6239
6240   /* if they are both bit variables */
6241   if (AOP_TYPE (left) == AOP_CRY &&
6242       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6243     {
6244       if (AOP_TYPE (right) == AOP_LIT)
6245         {
6246           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6247           if (lit == 0L)
6248             {
6249               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6250               emitcode ("cpl", "c");
6251             }
6252           else if (lit == 1L)
6253             {
6254               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6255             }
6256           else
6257             {
6258               emitcode ("clr", "c");
6259             }
6260           /* AOP_TYPE(right) == AOP_CRY */
6261         }
6262       else
6263         {
6264           symbol *lbl = newiTempLabel (NULL);
6265           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6266           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6267           emitcode ("cpl", "c");
6268           emitLabel (lbl);
6269         }
6270       /* c = 1 if egal */
6271       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6272         {
6273           outBitC (result);
6274           goto release;
6275         }
6276       if (ifx)
6277         {
6278           genIfxJump (ifx, "c", left, right, result);
6279           goto release;
6280         }
6281       /* if the result is used in an arithmetic operation
6282          then put the result in place */
6283       outBitC (result);
6284     }
6285   else
6286     {
6287       gencjne (left, right, newiTempLabel (NULL));
6288       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6289         {
6290           aopPut (result, "a", 0);
6291           goto release;
6292         }
6293       if (ifx)
6294         {
6295           genIfxJump (ifx, "a", left, right, result);
6296           goto release;
6297         }
6298       /* if the result is used in an arithmetic operation
6299          then put the result in place */
6300       if (AOP_TYPE (result) != AOP_CRY)
6301         outAcc (result);
6302       /* leave the result in acc */
6303     }
6304
6305 release:
6306   freeAsmop (result, NULL, ic, TRUE);
6307   if (!swappedLR)
6308     {
6309       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6310       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6311     }
6312   else
6313     {
6314       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6315       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6316     }
6317 }
6318
6319 /*-----------------------------------------------------------------*/
6320 /* ifxForOp - returns the icode containing the ifx for operand     */
6321 /*-----------------------------------------------------------------*/
6322 static iCode *
6323 ifxForOp (operand * op, iCode * ic)
6324 {
6325   /* if true symbol then needs to be assigned */
6326   if (IS_TRUE_SYMOP (op))
6327     return NULL;
6328
6329   /* if this has register type condition and
6330      the next instruction is ifx with the same operand
6331      and live to of the operand is upto the ifx only then */
6332   if (ic->next &&
6333       ic->next->op == IFX &&
6334       IC_COND (ic->next)->key == op->key &&
6335       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6336     return ic->next;
6337
6338   return NULL;
6339 }
6340
6341 /*-----------------------------------------------------------------*/
6342 /* hasInc - operand is incremented before any other use            */
6343 /*-----------------------------------------------------------------*/
6344 static iCode *
6345 hasInc (operand *op, iCode *ic, int osize)
6346 {
6347   sym_link *type = operandType(op);
6348   sym_link *retype = getSpec (type);
6349   iCode *lic = ic->next;
6350   int isize ;
6351
6352   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6353   if (!IS_SYMOP(op)) return NULL;
6354
6355   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6356   if (IS_AGGREGATE(type->next)) return NULL;
6357   if (osize != (isize = getSize(type->next))) return NULL;
6358
6359   while (lic) {
6360     /* if operand of the form op = op + <sizeof *op> */
6361     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6362         isOperandEqual(IC_RESULT(lic),op) &&
6363         isOperandLiteral(IC_RIGHT(lic)) &&
6364         operandLitValue(IC_RIGHT(lic)) == isize) {
6365       return lic;
6366     }
6367     /* if the operand used or deffed */
6368     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6369       return NULL;
6370     }
6371     /* if GOTO or IFX */
6372     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6373     lic = lic->next;
6374   }
6375   return NULL;
6376 }
6377
6378 /*-----------------------------------------------------------------*/
6379 /* genAndOp - for && operation                                     */
6380 /*-----------------------------------------------------------------*/
6381 static void
6382 genAndOp (iCode * ic)
6383 {
6384   operand *left, *right, *result;
6385   symbol *tlbl;
6386
6387   D (emitcode (";", "genAndOp"));
6388
6389   /* note here that && operations that are in an
6390      if statement are taken away by backPatchLabels
6391      only those used in arthmetic operations remain */
6392   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6393   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6394   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6395
6396   /* if both are bit variables */
6397   if (AOP_TYPE (left) == AOP_CRY &&
6398       AOP_TYPE (right) == AOP_CRY)
6399     {
6400       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6401       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6402       outBitC (result);
6403     }
6404   else
6405     {
6406       tlbl = newiTempLabel (NULL);
6407       toBoolean (left);
6408       emitcode ("jz", "%05d$", tlbl->key + 100);
6409       toBoolean (right);
6410       emitLabel (tlbl);
6411       outBitAcc (result);
6412     }
6413
6414   freeAsmop (result, NULL, ic, TRUE);
6415   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6416   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6417 }
6418
6419
6420 /*-----------------------------------------------------------------*/
6421 /* genOrOp - for || operation                                      */
6422 /*-----------------------------------------------------------------*/
6423 static void
6424 genOrOp (iCode * ic)
6425 {
6426   operand *left, *right, *result;
6427   symbol *tlbl;
6428
6429   D (emitcode (";", "genOrOp"));
6430
6431   /* note here that || operations that are in an
6432      if statement are taken away by backPatchLabels
6433      only those used in arthmetic operations remain */
6434   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6435   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6436   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6437
6438   /* if both are bit variables */
6439   if (AOP_TYPE (left) == AOP_CRY &&
6440       AOP_TYPE (right) == AOP_CRY)
6441     {
6442       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6443       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6444       outBitC (result);
6445     }
6446   else
6447     {
6448       tlbl = newiTempLabel (NULL);
6449       toBoolean (left);
6450       emitcode ("jnz", "%05d$", tlbl->key + 100);
6451       toBoolean (right);
6452       emitLabel (tlbl);
6453       outBitAcc (result);
6454     }
6455
6456   freeAsmop (result, NULL, ic, TRUE);
6457   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6458   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6459 }
6460
6461 /*-----------------------------------------------------------------*/
6462 /* isLiteralBit - test if lit == 2^n                               */
6463 /*-----------------------------------------------------------------*/
6464 static int
6465 isLiteralBit (unsigned long lit)
6466 {
6467   unsigned long pw[32] =
6468   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6469    0x100L, 0x200L, 0x400L, 0x800L,
6470    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6471    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6472    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6473    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6474    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6475   int idx;
6476
6477   for (idx = 0; idx < 32; idx++)
6478     if (lit == pw[idx])
6479       return idx + 1;
6480   return 0;
6481 }
6482
6483 /*-----------------------------------------------------------------*/
6484 /* continueIfTrue -                                                */
6485 /*-----------------------------------------------------------------*/
6486 static void
6487 continueIfTrue (iCode * ic)
6488 {
6489   if (IC_TRUE (ic))
6490     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6491   ic->generated = 1;
6492 }
6493
6494 /*-----------------------------------------------------------------*/
6495 /* jmpIfTrue -                                                     */
6496 /*-----------------------------------------------------------------*/
6497 static void
6498 jumpIfTrue (iCode * ic)
6499 {
6500   if (!IC_TRUE (ic))
6501     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6502   ic->generated = 1;
6503 }
6504
6505 /*-----------------------------------------------------------------*/
6506 /* jmpTrueOrFalse -                                                */
6507 /*-----------------------------------------------------------------*/
6508 static void
6509 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6510 {
6511   // ugly but optimized by peephole
6512   if (IC_TRUE (ic))
6513     {
6514       symbol *nlbl = newiTempLabel (NULL);
6515       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6516       emitLabel (tlbl);
6517       freeForBranchAsmop (result);
6518       freeForBranchAsmop (right);
6519       freeForBranchAsmop (left);
6520       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6521       emitLabel (nlbl);
6522     }
6523   else
6524     {
6525       freeForBranchAsmop (result);
6526       freeForBranchAsmop (right);
6527       freeForBranchAsmop (left);
6528       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6529       emitLabel (tlbl);
6530     }
6531   ic->generated = 1;
6532 }
6533
6534 /*-----------------------------------------------------------------*/
6535 /* genAnd  - code for and                                          */
6536 /*-----------------------------------------------------------------*/
6537 static void
6538 genAnd (iCode * ic, iCode * ifx)
6539 {
6540   operand *left, *right, *result;
6541   int size, offset = 0;
6542   unsigned long lit = 0L;
6543   int bytelit = 0;
6544   char buffer[10];
6545
6546   D (emitcode (";", "genAnd"));
6547
6548   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6549   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6550   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6551
6552 #ifdef DEBUG_TYPE
6553   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6554             AOP_TYPE (result),
6555             AOP_TYPE (left), AOP_TYPE (right));
6556   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6557             AOP_SIZE (result),
6558             AOP_SIZE (left), AOP_SIZE (right));
6559 #endif
6560
6561   /* if left is a literal & right is not then exchange them */
6562   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6563       AOP_NEEDSACC (left))
6564     {
6565       operand *tmp = right;
6566       right = left;
6567       left = tmp;
6568     }
6569
6570   /* if result = right then exchange left and right */
6571   if (sameRegs (AOP (result), AOP (right)))
6572     {
6573       operand *tmp = right;
6574       right = left;
6575       left = tmp;
6576     }
6577
6578   /* if right is bit then exchange them */
6579   if (AOP_TYPE (right) == AOP_CRY &&
6580       AOP_TYPE (left) != AOP_CRY)
6581     {
6582       operand *tmp = right;
6583       right = left;
6584       left = tmp;
6585     }
6586   if (AOP_TYPE (right) == AOP_LIT)
6587     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6588
6589   size = AOP_SIZE (result);
6590
6591   // if(bit & yy)
6592   // result = bit & yy;
6593   if (AOP_TYPE (left) == AOP_CRY)
6594     {
6595       // c = bit & literal;
6596       if (AOP_TYPE (right) == AOP_LIT)
6597         {
6598           if (lit & 1)
6599             {
6600               if (size && sameRegs (AOP (result), AOP (left)))
6601                 // no change
6602                 goto release;
6603               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6604             }
6605           else
6606             {
6607               // bit(result) = 0;
6608               if (size && (AOP_TYPE (result) == AOP_CRY))
6609                 {
6610                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6611                   goto release;
6612                 }
6613               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6614                 {
6615                   jumpIfTrue (ifx);
6616                   goto release;
6617                 }
6618               emitcode ("clr", "c");
6619             }
6620         }
6621       else
6622         {
6623           if (AOP_TYPE (right) == AOP_CRY)
6624             {
6625               // c = bit & bit;
6626               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6627               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6628             }
6629           else
6630             {
6631               // c = bit & val;
6632               MOVA (aopGet (right, 0, FALSE, FALSE));
6633               // c = lsb
6634               emitcode ("rrc", "a");
6635               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6636             }
6637         }
6638       // bit = c
6639       // val = c
6640       if (size)
6641         outBitC (result);
6642       // if(bit & ...)
6643       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6644         genIfxJump (ifx, "c", left, right, result);
6645       goto release;
6646     }
6647
6648   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6649   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6650   if ((AOP_TYPE (right) == AOP_LIT) &&
6651       (AOP_TYPE (result) == AOP_CRY) &&
6652       (AOP_TYPE (left) != AOP_CRY))
6653     {
6654       int posbit = isLiteralBit (lit);
6655       /* left &  2^n */
6656       if (posbit)
6657         {
6658           posbit--;
6659           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6660           // bit = left & 2^n
6661           if (size)
6662             {
6663               switch (posbit & 0x07)
6664                 {
6665                   case 0: emitcode ("rrc", "a");
6666                           break;
6667                   case 7: emitcode ("rlc", "a");
6668                           break;
6669                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6670                           break;
6671                 }
6672             }
6673           // if(left &  2^n)
6674           else
6675             {
6676               if (ifx)
6677                 {
6678                   SNPRINTF (buffer, sizeof(buffer),
6679                             "acc.%d", posbit & 0x07);
6680                   genIfxJump (ifx, buffer, left, right, result);
6681                 }
6682               else
6683                 {// what is this case? just found it in ds390/gen.c
6684                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6685                 }
6686               goto release;
6687             }
6688         }
6689       else
6690         {
6691           symbol *tlbl = newiTempLabel (NULL);
6692           int sizel = AOP_SIZE (left);
6693           if (size)
6694             emitcode ("setb", "c");
6695           while (sizel--)
6696             {
6697               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6698                 {
6699                   MOVA (aopGet (left, offset, FALSE, FALSE));
6700                   // byte ==  2^n ?
6701                   if ((posbit = isLiteralBit (bytelit)) != 0)
6702                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6703                   else
6704                     {
6705                       if (bytelit != 0x0FFL)
6706                         emitcode ("anl", "a,%s",
6707                                   aopGet (right, offset, FALSE, TRUE));
6708                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6709                     }
6710                 }
6711               offset++;
6712             }
6713           // bit = left & literal
6714           if (size)
6715             {
6716               emitcode ("clr", "c");
6717               emitLabel (tlbl);
6718             }
6719           // if(left & literal)
6720           else
6721             {
6722               if (ifx)
6723                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6724               else
6725                 emitLabel (tlbl);
6726               goto release;
6727             }
6728         }
6729       outBitC (result);
6730       goto release;
6731     }
6732
6733   /* if left is same as result */
6734   if (sameRegs (AOP (result), AOP (left)))
6735     {
6736       for (; size--; offset++)
6737         {
6738           if (AOP_TYPE (right) == AOP_LIT)
6739             {
6740               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6741               if (bytelit == 0x0FF)
6742                 {
6743                   /* dummy read of volatile operand */
6744                   if (isOperandVolatile (left, FALSE))
6745                     MOVA (aopGet (left, offset, FALSE, FALSE));
6746                   else
6747                     continue;
6748                 }
6749               else if (bytelit == 0)
6750                 {
6751                   aopPut (result, zero, offset);
6752                 }
6753               else if (IS_AOP_PREG (result))
6754                 {
6755                   MOVA (aopGet (left, offset, FALSE, TRUE));
6756                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6757                   aopPut (result, "a", offset);
6758                 }
6759               else
6760                 emitcode ("anl", "%s,%s",
6761                           aopGet (left, offset, FALSE, TRUE),
6762                           aopGet (right, offset, FALSE, FALSE));
6763             }
6764           else
6765             {
6766               if (AOP_TYPE (left) == AOP_ACC)
6767                 {
6768                   if (offset)
6769                     emitcode("mov", "a,b");
6770                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6771                 }
6772               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6773                 {
6774                   MOVB (aopGet (left, offset, FALSE, FALSE));
6775                   MOVA (aopGet (right, offset, FALSE, FALSE));
6776                   emitcode ("anl", "a,b");
6777                   aopPut (result, "a", offset);
6778                 }
6779               else if (aopGetUsesAcc (left, offset))
6780                 {
6781                   MOVA (aopGet (left, offset, FALSE, FALSE));
6782                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6783                   aopPut (result, "a", offset);
6784                 }
6785               else
6786                 {
6787                   MOVA (aopGet (right, offset, FALSE, FALSE));
6788                   if (IS_AOP_PREG (result))
6789                     {
6790                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6791                       aopPut (result, "a", offset);
6792                     }
6793                   else
6794                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6795                 }
6796             }
6797         }
6798     }
6799   else
6800     {
6801       // left & result in different registers
6802       if (AOP_TYPE (result) == AOP_CRY)
6803         {
6804           // result = bit
6805           // if(size), result in bit
6806           // if(!size && ifx), conditional oper: if(left & right)
6807           symbol *tlbl = newiTempLabel (NULL);
6808           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6809           if (size)
6810             emitcode ("setb", "c");
6811           while (sizer--)
6812             {
6813               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6814                   && AOP_TYPE(left)==AOP_ACC)
6815                 {
6816                   if (offset)
6817                     emitcode("mov", "a,b");
6818                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6819                 }
6820               else if (AOP_TYPE(left)==AOP_ACC)
6821                 {
6822                   if (!offset)
6823                     {
6824                       bool pushedB = pushB ();
6825                       emitcode("mov", "b,a");
6826                       MOVA (aopGet (right, offset, FALSE, FALSE));
6827                       emitcode("anl", "a,b");
6828                       popB (pushedB);
6829                     }
6830                   else
6831                     {
6832                       MOVA (aopGet (right, offset, FALSE, FALSE));
6833                       emitcode("anl", "a,b");
6834                     }
6835                 }
6836               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6837                 {
6838                   MOVB (aopGet (left, offset, FALSE, FALSE));
6839                   MOVA (aopGet (right, offset, FALSE, FALSE));
6840                   emitcode ("anl", "a,b");
6841                 }
6842               else if (aopGetUsesAcc (left, offset))
6843                 {
6844                   MOVA (aopGet (left, offset, FALSE, FALSE));
6845                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6846                     }
6847               else
6848                 {
6849                   MOVA (aopGet (right, offset, FALSE, FALSE));
6850                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6851                 }
6852
6853               emitcode ("jnz", "%05d$", tlbl->key + 100);
6854               offset++;
6855             }
6856           if (size)
6857             {
6858               CLRC;
6859               emitLabel (tlbl);
6860               outBitC (result);
6861             }
6862           else if (ifx)
6863             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6864           else
6865             emitLabel (tlbl);
6866         }
6867       else
6868         {
6869           for (; (size--); offset++)
6870             {
6871               // normal case
6872               // result = left & right
6873               if (AOP_TYPE (right) == AOP_LIT)
6874                 {
6875                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6876                   if (bytelit == 0x0FF)
6877                     {
6878                       aopPut (result,
6879                               aopGet (left, offset, FALSE, FALSE),
6880                               offset);
6881                       continue;
6882                     }
6883                   else if (bytelit == 0)
6884                     {
6885                       /* dummy read of volatile operand */
6886                       if (isOperandVolatile (left, FALSE))
6887                         MOVA (aopGet (left, offset, FALSE, FALSE));
6888                       aopPut (result, zero, offset);
6889                       continue;
6890                     }
6891                   else if (AOP_TYPE (left) == AOP_ACC)
6892                     {
6893                       if (!offset)
6894                         {
6895                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6896                           aopPut (result, "a", offset);
6897                           continue;
6898                         }
6899                       else
6900                         {
6901                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6902                           aopPut (result, "b", offset);
6903                           continue;
6904                         }
6905                     }
6906                 }
6907               // faster than result <- left, anl result,right
6908               // and better if result is SFR
6909               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6910                   && AOP_TYPE(left)==AOP_ACC)
6911                 {
6912                   if (offset)
6913                     emitcode("mov", "a,b");
6914                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6915                 }
6916               else if (AOP_TYPE(left)==AOP_ACC)
6917                 {
6918                   if (!offset)
6919                     {
6920                       bool pushedB = pushB ();
6921                       emitcode("mov", "b,a");
6922                       MOVA (aopGet (right, offset, FALSE, FALSE));
6923                       emitcode("anl", "a,b");
6924                       popB (pushedB);
6925                     }
6926                   else
6927                     {
6928                       MOVA (aopGet (right, offset, FALSE, FALSE));
6929                       emitcode("anl", "a,b");
6930                     }
6931                 }
6932               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6933                 {
6934                   MOVB (aopGet (left, offset, FALSE, FALSE));
6935                   MOVA (aopGet (right, offset, FALSE, FALSE));
6936                   emitcode ("anl", "a,b");
6937                 }
6938               else if (aopGetUsesAcc (left, offset))
6939                 {
6940                   MOVA (aopGet (left, offset, FALSE, FALSE));
6941                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6942                 }
6943               else
6944                 {
6945                   MOVA (aopGet (right, offset, FALSE, FALSE));
6946                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6947                 }
6948               aopPut (result, "a", offset);
6949             }
6950         }
6951     }
6952
6953 release:
6954   freeAsmop (result, NULL, ic, TRUE);
6955   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6956   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6957 }
6958
6959 /*-----------------------------------------------------------------*/
6960 /* genOr  - code for or                                            */
6961 /*-----------------------------------------------------------------*/
6962 static void
6963 genOr (iCode * ic, iCode * ifx)
6964 {
6965   operand *left, *right, *result;
6966   int size, offset = 0;
6967   unsigned long lit = 0L;
6968   int bytelit = 0;
6969
6970   D (emitcode (";", "genOr"));
6971
6972   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6973   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6974   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6975
6976 #ifdef DEBUG_TYPE
6977   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6978             AOP_TYPE (result),
6979             AOP_TYPE (left), AOP_TYPE (right));
6980   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6981             AOP_SIZE (result),
6982             AOP_SIZE (left), AOP_SIZE (right));
6983 #endif
6984
6985   /* if left is a literal & right is not then exchange them */
6986   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6987       AOP_NEEDSACC (left))
6988     {
6989       operand *tmp = right;
6990       right = left;
6991       left = tmp;
6992     }
6993
6994   /* if result = right then exchange them */
6995   if (sameRegs (AOP (result), AOP (right)))
6996     {
6997       operand *tmp = right;
6998       right = left;
6999       left = tmp;
7000     }
7001
7002   /* if right is bit then exchange them */
7003   if (AOP_TYPE (right) == AOP_CRY &&
7004       AOP_TYPE (left) != AOP_CRY)
7005     {
7006       operand *tmp = right;
7007       right = left;
7008       left = tmp;
7009     }
7010   if (AOP_TYPE (right) == AOP_LIT)
7011     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7012
7013   size = AOP_SIZE (result);
7014
7015   // if(bit | yy)
7016   // xx = bit | yy;
7017   if (AOP_TYPE (left) == AOP_CRY)
7018     {
7019       if (AOP_TYPE (right) == AOP_LIT)
7020         {
7021           // c = bit | literal;
7022           if (lit)
7023             {
7024               // lit != 0 => result = 1
7025               if (AOP_TYPE (result) == AOP_CRY)
7026                 {
7027                   if (size)
7028                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7029                   else if (ifx)
7030                     continueIfTrue (ifx);
7031                   goto release;
7032                 }
7033               emitcode ("setb", "c");
7034             }
7035           else
7036             {
7037               // lit == 0 => result = left
7038               if (size && sameRegs (AOP (result), AOP (left)))
7039                 goto release;
7040               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7041             }
7042         }
7043       else
7044         {
7045           if (AOP_TYPE (right) == AOP_CRY)
7046             {
7047               // c = bit | bit;
7048               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7049               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7050             }
7051           else
7052             {
7053               // c = bit | val;
7054               symbol *tlbl = newiTempLabel (NULL);
7055               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7056                 emitcode ("setb", "c");
7057               emitcode ("jb", "%s,%05d$",
7058                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7059               toBoolean (right);
7060               emitcode ("jnz", "%05d$", tlbl->key + 100);
7061               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7062                 {
7063                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7064                   goto release;
7065                 }
7066               else
7067                 {
7068                   CLRC;
7069                   emitLabel (tlbl);
7070                 }
7071             }
7072         }
7073       // bit = c
7074       // val = c
7075       if (size)
7076         outBitC (result);
7077       // if(bit | ...)
7078       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7079         genIfxJump (ifx, "c", left, right, result);
7080       goto release;
7081     }
7082
7083   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7084   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7085   if ((AOP_TYPE (right) == AOP_LIT) &&
7086       (AOP_TYPE (result) == AOP_CRY) &&
7087       (AOP_TYPE (left) != AOP_CRY))
7088     {
7089       if (lit)
7090         {
7091           // result = 1
7092           if (size)
7093             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7094           else
7095             continueIfTrue (ifx);
7096           goto release;
7097         }
7098       else
7099         {
7100           // lit = 0, result = boolean(left)
7101           if (size)
7102             emitcode ("setb", "c");
7103           toBoolean (right);
7104           if (size)
7105             {
7106               symbol *tlbl = newiTempLabel (NULL);
7107               emitcode ("jnz", "%05d$", tlbl->key + 100);
7108               CLRC;
7109               emitLabel (tlbl);
7110             }
7111           else
7112             {
7113               genIfxJump (ifx, "a", left, right, result);
7114               goto release;
7115             }
7116         }
7117       outBitC (result);
7118       goto release;
7119     }
7120
7121   /* if left is same as result */
7122   if (sameRegs (AOP (result), AOP (left)))
7123     {
7124       for (; size--; offset++)
7125         {
7126           if (AOP_TYPE (right) == AOP_LIT)
7127             {
7128               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7129               if (bytelit == 0)
7130                 {
7131                   /* dummy read of volatile operand */
7132                   if (isOperandVolatile (left, FALSE))
7133                     MOVA (aopGet (left, offset, FALSE, FALSE));
7134                   else
7135                     continue;
7136                 }
7137               else if (bytelit == 0x0FF)
7138                 {
7139                   aopPut (result, "#0xFF", offset);
7140                 }
7141               else if (IS_AOP_PREG (left))
7142                 {
7143                   MOVA (aopGet (left, offset, FALSE, TRUE));
7144                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7145                   aopPut (result, "a", offset);
7146                 }
7147               else
7148                 {
7149                   emitcode ("orl", "%s,%s",
7150                             aopGet (left, offset, FALSE, TRUE),
7151                             aopGet (right, offset, FALSE, FALSE));
7152                 }
7153             }
7154           else
7155             {
7156               if (AOP_TYPE (left) == AOP_ACC)
7157                 {
7158                   if (offset)
7159                     emitcode("mov", "a,b");
7160                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7161                 }
7162               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7163                 {
7164                   MOVB (aopGet (left, offset, FALSE, FALSE));
7165                   MOVA (aopGet (right, offset, FALSE, FALSE));
7166                   emitcode ("orl", "a,b");
7167                   aopPut (result, "a", offset);
7168                 }
7169               else if (aopGetUsesAcc (left, offset))
7170                 {
7171                   MOVA (aopGet (left, offset, FALSE, FALSE));
7172                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7173                   aopPut (result, "a", offset);
7174                 }
7175               else
7176                 {
7177                   MOVA (aopGet (right, offset, FALSE, FALSE));
7178                   if (IS_AOP_PREG (left))
7179                     {
7180                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7181                       aopPut (result, "a", offset);
7182                     }
7183                   else
7184                     {
7185                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7186                     }
7187                 }
7188             }
7189         }
7190     }
7191   else
7192     {
7193       // left & result in different registers
7194       if (AOP_TYPE (result) == AOP_CRY)
7195         {
7196           // result = bit
7197           // if(size), result in bit
7198           // if(!size && ifx), conditional oper: if(left | right)
7199           symbol *tlbl = newiTempLabel (NULL);
7200           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7201           if (size)
7202             emitcode ("setb", "c");
7203           while (sizer--)
7204             {
7205               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7206                   && AOP_TYPE(left)==AOP_ACC)
7207                 {
7208                   if (offset)
7209                     emitcode("mov", "a,b");
7210                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7211                 }
7212               else if (AOP_TYPE(left)==AOP_ACC)
7213                 {
7214                   if (!offset)
7215                     {
7216                       bool pushedB = pushB ();
7217                       emitcode("mov", "b,a");
7218                       MOVA (aopGet (right, offset, FALSE, FALSE));
7219                       emitcode("orl", "a,b");
7220                       popB (pushedB);
7221                     }
7222                   else
7223                     {
7224                       MOVA (aopGet (right, offset, FALSE, FALSE));
7225                       emitcode("orl", "a,b");
7226                     }
7227                 }
7228               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7229                 {
7230                   MOVB (aopGet (left, offset, FALSE, FALSE));
7231                   MOVA (aopGet (right, offset, FALSE, FALSE));
7232                   emitcode ("orl", "a,b");
7233                 }
7234               else if (aopGetUsesAcc (left, offset))
7235                 {
7236                   MOVA (aopGet (left, offset, FALSE, FALSE));
7237                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7238                 }
7239               else
7240                 {
7241                   MOVA (aopGet (right, offset, FALSE, FALSE));
7242                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7243               }
7244
7245               emitcode ("jnz", "%05d$", tlbl->key + 100);
7246               offset++;
7247             }
7248           if (size)
7249             {
7250               CLRC;
7251               emitLabel (tlbl);
7252               outBitC (result);
7253             }
7254           else if (ifx)
7255             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7256           else
7257             emitLabel (tlbl);
7258         }
7259       else
7260         {
7261           for (; (size--); offset++)
7262             {
7263               // normal case
7264               // result = left | right
7265               if (AOP_TYPE (right) == AOP_LIT)
7266                 {
7267                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7268                   if (bytelit == 0)
7269                     {
7270                       aopPut (result,
7271                               aopGet (left, offset, FALSE, FALSE),
7272                               offset);
7273                       continue;
7274                     }
7275                   else if (bytelit == 0x0FF)
7276                     {
7277                       /* dummy read of volatile operand */
7278                       if (isOperandVolatile (left, FALSE))
7279                         MOVA (aopGet (left, offset, FALSE, FALSE));
7280                       aopPut (result, "#0xFF", offset);
7281                       continue;
7282                     }
7283                 }
7284               // faster than result <- left, orl result,right
7285               // and better if result is SFR
7286               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7287                   && AOP_TYPE(left)==AOP_ACC)
7288                 {
7289                   if (offset)
7290                     emitcode("mov", "a,b");
7291                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7292                 }
7293               else if (AOP_TYPE(left)==AOP_ACC)
7294                 {
7295                   if (!offset)
7296                     {
7297                       bool pushedB = pushB ();
7298                       emitcode("mov", "b,a");
7299                       MOVA (aopGet (right, offset, FALSE, FALSE));
7300                       emitcode("orl", "a,b");
7301                       popB (pushedB);
7302                     }
7303                   else
7304                     {
7305                       MOVA (aopGet (right, offset, FALSE, FALSE));
7306                       emitcode("orl", "a,b");
7307                     }
7308                 }
7309               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7310                 {
7311                   MOVB (aopGet (left, offset, FALSE, FALSE));
7312                   MOVA (aopGet (right, offset, FALSE, FALSE));
7313                   emitcode ("orl", "a,b");
7314                 }
7315               else if (aopGetUsesAcc (left, offset))
7316                 {
7317                   MOVA (aopGet (left, offset, FALSE, FALSE));
7318                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7319                 }
7320               else
7321                 {
7322                   MOVA (aopGet (right, offset, FALSE, FALSE));
7323                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7324                 }
7325               aopPut (result, "a", offset);
7326             }
7327         }
7328     }
7329
7330 release:
7331   freeAsmop (result, NULL, ic, TRUE);
7332   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7333   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7334 }
7335
7336 /*-----------------------------------------------------------------*/
7337 /* genXor - code for xclusive or                                   */
7338 /*-----------------------------------------------------------------*/
7339 static void
7340 genXor (iCode * ic, iCode * ifx)
7341 {
7342   operand *left, *right, *result;
7343   int size, offset = 0;
7344   unsigned long lit = 0L;
7345   int bytelit = 0;
7346
7347   D (emitcode (";", "genXor"));
7348
7349   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7350   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7351   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7352
7353 #ifdef DEBUG_TYPE
7354   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7355             AOP_TYPE (result),
7356             AOP_TYPE (left), AOP_TYPE (right));
7357   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7358             AOP_SIZE (result),
7359             AOP_SIZE (left), AOP_SIZE (right));
7360 #endif
7361
7362   /* if left is a literal & right is not ||
7363      if left needs acc & right does not */
7364   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7365       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7366     {
7367       operand *tmp = right;
7368       right = left;
7369       left = tmp;
7370     }
7371
7372   /* if result = right then exchange them */
7373   if (sameRegs (AOP (result), AOP (right)))
7374     {
7375       operand *tmp = right;
7376       right = left;
7377       left = tmp;
7378     }
7379
7380   /* if right is bit then exchange them */
7381   if (AOP_TYPE (right) == AOP_CRY &&
7382       AOP_TYPE (left) != AOP_CRY)
7383     {
7384       operand *tmp = right;
7385       right = left;
7386       left = tmp;
7387     }
7388   if (AOP_TYPE (right) == AOP_LIT)
7389     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7390
7391   size = AOP_SIZE (result);
7392
7393   // if(bit ^ yy)
7394   // xx = bit ^ yy;
7395   if (AOP_TYPE (left) == AOP_CRY)
7396     {
7397       if (AOP_TYPE (right) == AOP_LIT)
7398         {
7399           // c = bit & literal;
7400           if (lit >> 1)
7401             {
7402               // lit>>1  != 0 => result = 1
7403               if (AOP_TYPE (result) == AOP_CRY)
7404                 {
7405                   if (size)
7406                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7407                   else if (ifx)
7408                     continueIfTrue (ifx);
7409                   goto release;
7410                 }
7411               emitcode ("setb", "c");
7412             }
7413           else
7414             {
7415               // lit == (0 or 1)
7416               if (lit == 0)
7417                 {
7418                   // lit == 0, result = left
7419                   if (size && sameRegs (AOP (result), AOP (left)))
7420                     goto release;
7421                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7422                 }
7423               else
7424                 {
7425                   // lit == 1, result = not(left)
7426                   if (size && sameRegs (AOP (result), AOP (left)))
7427                     {
7428                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7429                       goto release;
7430                     }
7431                   else
7432                     {
7433                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7434                       emitcode ("cpl", "c");
7435                     }
7436                 }
7437             }
7438         }
7439       else
7440         {
7441           // right != literal
7442           symbol *tlbl = newiTempLabel (NULL);
7443           if (AOP_TYPE (right) == AOP_CRY)
7444             {
7445               // c = bit ^ bit;
7446               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7447             }
7448           else
7449             {
7450               int sizer = AOP_SIZE (right);
7451               // c = bit ^ val
7452               // if val>>1 != 0, result = 1
7453               emitcode ("setb", "c");
7454               while (sizer)
7455                 {
7456                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE));
7457                   if (sizer == 1)
7458                     // test the msb of the lsb
7459                     emitcode ("anl", "a,#0xfe");
7460                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7461                   sizer--;
7462                 }
7463               // val = (0,1)
7464               emitcode ("rrc", "a");
7465             }
7466           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7467           emitcode ("cpl", "c");
7468           emitLabel (tlbl);
7469         }
7470       // bit = c
7471       // val = c
7472       if (size)
7473         outBitC (result);
7474       // if(bit | ...)
7475       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7476         genIfxJump (ifx, "c", left, right, result);
7477       goto release;
7478     }
7479
7480   /* if left is same as result */
7481   if (sameRegs (AOP (result), AOP (left)))
7482     {
7483       for (; size--; offset++)
7484         {
7485           if (AOP_TYPE (right) == AOP_LIT)
7486             {
7487               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7488               if (bytelit == 0)
7489                 {
7490                   /* dummy read of volatile operand */
7491                   if (isOperandVolatile (left, FALSE))
7492                     MOVA (aopGet (left, offset, FALSE, FALSE));
7493                   else
7494                     continue;
7495                 }
7496               else if (IS_AOP_PREG (left))
7497                 {
7498                   MOVA (aopGet (left, offset, FALSE, TRUE));
7499                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7500                   aopPut (result, "a", offset);
7501                 }
7502               else
7503                 {
7504                   emitcode ("xrl", "%s,%s",
7505                             aopGet (left, offset, FALSE, TRUE),
7506                             aopGet (right, offset, FALSE, FALSE));
7507                 }
7508             }
7509           else
7510             {
7511               if (AOP_TYPE (left) == AOP_ACC)
7512                 {
7513                   if (offset)
7514                     emitcode("mov", "a,b");
7515                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7516                 }
7517               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7518                 {
7519                   MOVB (aopGet (left, offset, FALSE, FALSE));
7520                   MOVA (aopGet (right, offset, FALSE, FALSE));
7521                   emitcode ("xrl", "a,b");
7522                   aopPut (result, "a", offset);
7523                 }
7524               else if (aopGetUsesAcc (left, offset))
7525                 {
7526                   MOVA (aopGet (left, offset, FALSE, FALSE));
7527                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7528                   aopPut (result, "a", offset);
7529                 }
7530               else
7531                 {
7532                   MOVA (aopGet (right, offset, FALSE, FALSE));
7533                   if (IS_AOP_PREG (left))
7534                     {
7535                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7536                       aopPut (result, "a", offset);
7537                     }
7538                   else
7539                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7540                 }
7541             }
7542         }
7543     }
7544   else
7545     {
7546       // left & result in different registers
7547       if (AOP_TYPE (result) == AOP_CRY)
7548         {
7549           // result = bit
7550           // if(size), result in bit
7551           // if(!size && ifx), conditional oper: if(left ^ right)
7552           symbol *tlbl = newiTempLabel (NULL);
7553           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7554
7555           if (size)
7556             emitcode ("setb", "c");
7557           while (sizer--)
7558             {
7559               if ((AOP_TYPE (right) == AOP_LIT) &&
7560                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7561                 {
7562                   MOVA (aopGet (left, offset, FALSE, FALSE));
7563                 }
7564               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7565                   && AOP_TYPE(left)==AOP_ACC)
7566                 {
7567                   if (offset)
7568                     emitcode("mov", "a,b");
7569                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7570                 }
7571               else if (AOP_TYPE(left)==AOP_ACC)
7572                 {
7573                   if (!offset)
7574                     {
7575                       bool pushedB = pushB ();
7576                       emitcode("mov", "b,a");
7577                       MOVA (aopGet (right, offset, FALSE, FALSE));
7578                       emitcode("xrl", "a,b");
7579                       popB (pushedB);
7580                     }
7581                   else
7582                     {
7583                       MOVA (aopGet (right, offset, FALSE, FALSE));
7584                       emitcode("xrl", "a,b");
7585                     }
7586                 }
7587               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7588                 {
7589                   MOVB (aopGet (left, offset, FALSE, FALSE));
7590                   MOVA (aopGet (right, offset, FALSE, FALSE));
7591                   emitcode ("xrl", "a,b");
7592                 }
7593               else if (aopGetUsesAcc (left, offset))
7594                 {
7595                   MOVA (aopGet (left, offset, FALSE, FALSE));
7596                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7597                 }
7598               else
7599                 {
7600                   MOVA (aopGet (right, offset, FALSE, FALSE));
7601                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7602                 }
7603
7604               emitcode ("jnz", "%05d$", tlbl->key + 100);
7605               offset++;
7606             }
7607           if (size)
7608             {
7609               CLRC;
7610               emitLabel (tlbl);
7611               outBitC (result);
7612             }
7613           else if (ifx)
7614             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7615         }
7616       else
7617         {
7618           for (; (size--); offset++)
7619             {
7620               // normal case
7621               // result = left ^ right
7622               if (AOP_TYPE (right) == AOP_LIT)
7623                 {
7624                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7625                   if (bytelit == 0)
7626                     {
7627                       aopPut (result,
7628                               aopGet (left, offset, FALSE, FALSE),
7629                               offset);
7630                       continue;
7631                     }
7632                 }
7633               // faster than result <- left, xrl result,right
7634               // and better if result is SFR
7635               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7636                   && AOP_TYPE(left)==AOP_ACC)
7637                 {
7638                   if (offset)
7639                     emitcode("mov", "a,b");
7640                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7641                 }
7642               else if (AOP_TYPE(left)==AOP_ACC)
7643                 {
7644                   if (!offset)
7645                     {
7646                       bool pushedB = pushB ();
7647                       emitcode("mov", "b,a");
7648                       MOVA (aopGet (right, offset, FALSE, FALSE));
7649                       emitcode("xrl", "a,b");
7650                       popB (pushedB);
7651                     }
7652                   else
7653                     {
7654                       MOVA (aopGet (right, offset, FALSE, FALSE));
7655                       emitcode("xrl", "a,b");
7656                     }
7657                 }
7658               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7659                 {
7660                   MOVB (aopGet (left, offset, FALSE, FALSE));
7661                   MOVA (aopGet (right, offset, FALSE, FALSE));
7662                   emitcode ("xrl", "a,b");
7663                 }
7664               else if (aopGetUsesAcc (left, offset))
7665                 {
7666                   MOVA (aopGet (left, offset, FALSE, FALSE));
7667                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7668                 }
7669               else
7670                 {
7671                   MOVA (aopGet (right, offset, FALSE, FALSE));
7672                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7673                 }
7674               aopPut (result, "a", offset);
7675             }
7676         }
7677     }
7678
7679 release:
7680   freeAsmop (result, NULL, ic, TRUE);
7681   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7682   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7683 }
7684
7685 /*-----------------------------------------------------------------*/
7686 /* genInline - write the inline code out                           */
7687 /*-----------------------------------------------------------------*/
7688 static void
7689 genInline (iCode * ic)
7690 {
7691   char *buffer, *bp, *bp1;
7692
7693   D (emitcode (";", "genInline"));
7694
7695   _G.inLine += (!options.asmpeep);
7696
7697   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
7698
7699   /* emit each line as a code */
7700   while (*bp)
7701     {
7702       if (*bp == '\n')
7703         {
7704           *bp++ = '\0';
7705           emitcode (bp1, "");
7706           bp1 = bp;
7707         }
7708       else
7709         {
7710           /* Add \n for labels, not dirs such as c:\mydir */
7711           if ( (*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         }
7722     }
7723   if (bp1 != bp)
7724     emitcode (bp1, "");
7725   /*     emitcode("",buffer); */
7726   _G.inLine -= (!options.asmpeep);
7727 }
7728
7729 /*-----------------------------------------------------------------*/
7730 /* genRRC - rotate right with carry                                */
7731 /*-----------------------------------------------------------------*/
7732 static void
7733 genRRC (iCode * ic)
7734 {
7735   operand *left, *result;
7736   int size, offset;
7737   char *l;
7738
7739   D (emitcode (";", "genRRC"));
7740
7741   /* rotate right with carry */
7742   left = IC_LEFT (ic);
7743   result = IC_RESULT (ic);
7744   aopOp (left, ic, FALSE);
7745   aopOp (result, ic, FALSE);
7746
7747   /* move it to the result */
7748   size = AOP_SIZE (result);
7749   offset = size - 1;
7750   if (size == 1) { /* special case for 1 byte */
7751       l = aopGet (left, offset, FALSE, FALSE);
7752       MOVA (l);
7753       emitcode ("rr", "a");
7754       goto release;
7755   }
7756   /* no need to clear carry, bit7 will be written later */
7757   while (size--)
7758     {
7759       l = aopGet (left, offset, FALSE, FALSE);
7760       MOVA (l);
7761       emitcode ("rrc", "a");
7762       if (AOP_SIZE (result) > 1)
7763         aopPut (result, "a", offset--);
7764     }
7765   /* now we need to put the carry into the
7766      highest order byte of the result */
7767   if (AOP_SIZE (result) > 1)
7768     {
7769       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7770       MOVA (l);
7771     }
7772   emitcode ("mov", "acc.7,c");
7773  release:
7774   aopPut (result, "a", AOP_SIZE (result) - 1);
7775   freeAsmop (result, NULL, ic, TRUE);
7776   freeAsmop (left, NULL, ic, TRUE);
7777 }
7778
7779 /*-----------------------------------------------------------------*/
7780 /* genRLC - generate code for rotate left with carry               */
7781 /*-----------------------------------------------------------------*/
7782 static void
7783 genRLC (iCode * ic)
7784 {
7785   operand *left, *result;
7786   int size, offset;
7787   char *l;
7788
7789   D (emitcode (";", "genRLC"));
7790
7791   /* rotate right with carry */
7792   left = IC_LEFT (ic);
7793   result = IC_RESULT (ic);
7794   aopOp (left, ic, FALSE);
7795   aopOp (result, ic, FALSE);
7796
7797   /* move it to the result */
7798   size = AOP_SIZE (result);
7799   offset = 0;
7800   if (size--)
7801     {
7802       l = aopGet (left, offset, FALSE, FALSE);
7803       MOVA (l);
7804       if (size == 0) { /* special case for 1 byte */
7805               emitcode("rl","a");
7806               goto release;
7807       }
7808       emitcode("rlc","a"); /* bit0 will be written later */
7809       if (AOP_SIZE (result) > 1)
7810         {
7811           aopPut (result, "a", offset++);
7812         }
7813
7814       while (size--)
7815         {
7816           l = aopGet (left, offset, FALSE, FALSE);
7817           MOVA (l);
7818           emitcode ("rlc", "a");
7819           if (AOP_SIZE (result) > 1)
7820             aopPut (result, "a", offset++);
7821         }
7822     }
7823   /* now we need to put the carry into the
7824      highest order byte of the result */
7825   if (AOP_SIZE (result) > 1)
7826     {
7827       l = aopGet (result, 0, FALSE, FALSE);
7828       MOVA (l);
7829     }
7830   emitcode ("mov", "acc.0,c");
7831  release:
7832   aopPut (result, "a", 0);
7833   freeAsmop (result, NULL, ic, TRUE);
7834   freeAsmop (left, NULL, ic, TRUE);
7835 }
7836
7837 /*-----------------------------------------------------------------*/
7838 /* genGetHbit - generates code get highest order bit               */
7839 /*-----------------------------------------------------------------*/
7840 static void
7841 genGetHbit (iCode * ic)
7842 {
7843   operand *left, *result;
7844
7845   D (emitcode (";", "genGetHbit"));
7846
7847   left = IC_LEFT (ic);
7848   result = IC_RESULT (ic);
7849   aopOp (left, ic, FALSE);
7850   aopOp (result, ic, FALSE);
7851
7852   /* get the highest order byte into a */
7853   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7854   if (AOP_TYPE (result) == AOP_CRY)
7855     {
7856       emitcode ("rlc", "a");
7857       outBitC (result);
7858     }
7859   else
7860     {
7861       emitcode ("rl", "a");
7862       emitcode ("anl", "a,#0x01");
7863       outAcc (result);
7864     }
7865
7866   freeAsmop (result, NULL, ic, TRUE);
7867   freeAsmop (left, NULL, ic, TRUE);
7868 }
7869
7870 /*-----------------------------------------------------------------*/
7871 /* genGetAbit - generates code get a single bit                    */
7872 /*-----------------------------------------------------------------*/
7873 static void
7874 genGetAbit (iCode * ic)
7875 {
7876   operand *left, *right, *result;
7877   int shCount;
7878
7879   D (emitcode (";", "genGetAbit"));
7880
7881   left = IC_LEFT (ic);
7882   right = IC_RIGHT (ic);
7883   result = IC_RESULT (ic);
7884   aopOp (left, ic, FALSE);
7885   aopOp (right, ic, FALSE);
7886   aopOp (result, ic, FALSE);
7887
7888   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7889
7890   /* get the needed byte into a */
7891   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7892   shCount %= 8;
7893   if (AOP_TYPE (result) == AOP_CRY)
7894     {
7895       if ((shCount) == 7)
7896           emitcode ("rlc", "a");
7897       else if ((shCount) == 0)
7898           emitcode ("rrc", "a");
7899       else
7900           emitcode ("mov", "c,acc[%d]", shCount);
7901       outBitC (result);
7902     }
7903   else
7904     {
7905       switch (shCount)
7906         {
7907         case 2:
7908           emitcode ("rr", "a");
7909           //fallthrough
7910         case 1:
7911           emitcode ("rr", "a");
7912           //fallthrough
7913         case 0:
7914           emitcode ("anl", "a,#0x01");
7915           break;
7916         case 3:
7917         case 5:
7918           emitcode ("mov", "c,acc[%d]", shCount);
7919           emitcode ("clr", "a");
7920           emitcode ("rlc", "a");
7921           break;
7922         case 4:
7923           emitcode ("swap", "a");
7924           emitcode ("anl", "a,#0x01");
7925           break;
7926         case 6:
7927           emitcode ("rl", "a");
7928           //fallthrough
7929         case 7:
7930           emitcode ("rl", "a");
7931           emitcode ("anl", "a,#0x01");
7932           break;
7933         }
7934       outAcc (result);
7935     }
7936
7937   freeAsmop (result, NULL, ic, TRUE);
7938   freeAsmop (right, NULL, ic, TRUE);
7939   freeAsmop (left, NULL, ic, TRUE);
7940 }
7941
7942 /*-----------------------------------------------------------------*/
7943 /* genGetByte - generates code get a single byte                   */
7944 /*-----------------------------------------------------------------*/
7945 static void
7946 genGetByte (iCode * ic)
7947 {
7948   operand *left, *right, *result;
7949   int offset;
7950
7951   D (emitcode (";", "genGetByte"));
7952
7953   left = IC_LEFT (ic);
7954   right = IC_RIGHT (ic);
7955   result = IC_RESULT (ic);
7956   aopOp (left, ic, FALSE);
7957   aopOp (right, ic, FALSE);
7958   aopOp (result, ic, FALSE);
7959
7960   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7961   aopPut (result,
7962           aopGet (left, offset, FALSE, FALSE),
7963           0);
7964
7965   freeAsmop (result, NULL, ic, TRUE);
7966   freeAsmop (right, NULL, ic, TRUE);
7967   freeAsmop (left, NULL, ic, TRUE);
7968 }
7969
7970 /*-----------------------------------------------------------------*/
7971 /* genGetWord - generates code get two bytes                       */
7972 /*-----------------------------------------------------------------*/
7973 static void
7974 genGetWord (iCode * ic)
7975 {
7976   operand *left, *right, *result;
7977   int offset;
7978
7979   D (emitcode (";", "genGetWord"));
7980
7981   left = IC_LEFT (ic);
7982   right = IC_RIGHT (ic);
7983   result = IC_RESULT (ic);
7984   aopOp (left, ic, FALSE);
7985   aopOp (right, ic, FALSE);
7986   aopOp (result, ic, FALSE);
7987
7988   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7989   aopPut (result,
7990           aopGet (left, offset, FALSE, FALSE),
7991           0);
7992   aopPut (result,
7993           aopGet (left, offset+1, FALSE, FALSE),
7994           1);
7995
7996   freeAsmop (result, NULL, ic, TRUE);
7997   freeAsmop (right, NULL, ic, TRUE);
7998   freeAsmop (left, NULL, ic, TRUE);
7999 }
8000
8001 /*-----------------------------------------------------------------*/
8002 /* genSwap - generates code to swap nibbles or bytes               */
8003 /*-----------------------------------------------------------------*/
8004 static void
8005 genSwap (iCode * ic)
8006 {
8007   operand *left, *result;
8008
8009   D(emitcode (";     genSwap",""));
8010
8011   left = IC_LEFT (ic);
8012   result = IC_RESULT (ic);
8013   aopOp (left, ic, FALSE);
8014   aopOp (result, ic, FALSE);
8015
8016   switch (AOP_SIZE (left))
8017     {
8018     case 1: /* swap nibbles in byte */
8019       MOVA (aopGet (left, 0, FALSE, FALSE));
8020       emitcode ("swap", "a");
8021       aopPut (result, "a", 0);
8022       break;
8023     case 2: /* swap bytes in word */
8024       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8025         {
8026           MOVA (aopGet (left, 0, FALSE, FALSE));
8027           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8028           aopPut (result, "a", 1);
8029         }
8030       else if (operandsEqu (left, result))
8031         {
8032           char * reg = "a";
8033           bool pushedB = FALSE, leftInB = FALSE;
8034
8035           MOVA (aopGet (left, 0, FALSE, FALSE));
8036           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8037             {
8038               pushedB = pushB ();
8039               emitcode ("mov", "b,a");
8040               reg = "b";
8041               leftInB = TRUE;
8042             }
8043           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8044           aopPut (result, reg, 1);
8045
8046           if (leftInB)
8047             popB (pushedB);
8048         }
8049       else
8050         {
8051           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8052           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8053         }
8054       break;
8055     default:
8056       wassertl(FALSE, "unsupported SWAP operand size");
8057     }
8058
8059   freeAsmop (result, NULL, ic, TRUE);
8060   freeAsmop (left, NULL, ic, TRUE);
8061 }
8062
8063 /*-----------------------------------------------------------------*/
8064 /* AccRol - rotate left accumulator by known count                 */
8065 /*-----------------------------------------------------------------*/
8066 static void
8067 AccRol (int shCount)
8068 {
8069   shCount &= 0x0007;            // shCount : 0..7
8070
8071   switch (shCount)
8072     {
8073     case 0:
8074       break;
8075     case 1:
8076       emitcode ("rl", "a");
8077       break;
8078     case 2:
8079       emitcode ("rl", "a");
8080       emitcode ("rl", "a");
8081       break;
8082     case 3:
8083       emitcode ("swap", "a");
8084       emitcode ("rr", "a");
8085       break;
8086     case 4:
8087       emitcode ("swap", "a");
8088       break;
8089     case 5:
8090       emitcode ("swap", "a");
8091       emitcode ("rl", "a");
8092       break;
8093     case 6:
8094       emitcode ("rr", "a");
8095       emitcode ("rr", "a");
8096       break;
8097     case 7:
8098       emitcode ("rr", "a");
8099       break;
8100     }
8101 }
8102
8103 /*-----------------------------------------------------------------*/
8104 /* AccLsh - left shift accumulator by known count                  */
8105 /*-----------------------------------------------------------------*/
8106 static void
8107 AccLsh (int shCount)
8108 {
8109   if (shCount != 0)
8110     {
8111       if (shCount == 1)
8112         emitcode ("add", "a,acc");
8113       else if (shCount == 2)
8114         {
8115           emitcode ("add", "a,acc");
8116           emitcode ("add", "a,acc");
8117         }
8118       else
8119         {
8120           /* rotate left accumulator */
8121           AccRol (shCount);
8122           /* and kill the lower order bits */
8123           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8124         }
8125     }
8126 }
8127
8128 /*-----------------------------------------------------------------*/
8129 /* AccRsh - right shift accumulator by known count                 */
8130 /*-----------------------------------------------------------------*/
8131 static void
8132 AccRsh (int shCount)
8133 {
8134   if (shCount != 0)
8135     {
8136       if (shCount == 1)
8137         {
8138           CLRC;
8139           emitcode ("rrc", "a");
8140         }
8141       else
8142         {
8143           /* rotate right accumulator */
8144           AccRol (8 - shCount);
8145           /* and kill the higher order bits */
8146           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8147         }
8148     }
8149 }
8150
8151 /*-----------------------------------------------------------------*/
8152 /* AccSRsh - signed right shift accumulator by known count                 */
8153 /*-----------------------------------------------------------------*/
8154 static void
8155 AccSRsh (int shCount)
8156 {
8157   symbol *tlbl;
8158   if (shCount != 0)
8159     {
8160       if (shCount == 1)
8161         {
8162           emitcode ("mov", "c,acc.7");
8163           emitcode ("rrc", "a");
8164         }
8165       else if (shCount == 2)
8166         {
8167           emitcode ("mov", "c,acc.7");
8168           emitcode ("rrc", "a");
8169           emitcode ("mov", "c,acc.7");
8170           emitcode ("rrc", "a");
8171         }
8172       else
8173         {
8174           tlbl = newiTempLabel (NULL);
8175           /* rotate right accumulator */
8176           AccRol (8 - shCount);
8177           /* and kill the higher order bits */
8178           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8179           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8180           emitcode ("orl", "a,#0x%02x",
8181                     (unsigned char) ~SRMask[shCount]);
8182           emitLabel (tlbl);
8183         }
8184     }
8185 }
8186
8187 /*-----------------------------------------------------------------*/
8188 /* shiftR1Left2Result - shift right one byte from left to result   */
8189 /*-----------------------------------------------------------------*/
8190 static void
8191 shiftR1Left2Result (operand * left, int offl,
8192                     operand * result, int offr,
8193                     int shCount, int sign)
8194 {
8195   MOVA (aopGet (left, offl, FALSE, FALSE));
8196   /* shift right accumulator */
8197   if (sign)
8198     AccSRsh (shCount);
8199   else
8200     AccRsh (shCount);
8201   aopPut (result, "a", offr);
8202 }
8203
8204 /*-----------------------------------------------------------------*/
8205 /* shiftL1Left2Result - shift left one byte from left to result    */
8206 /*-----------------------------------------------------------------*/
8207 static void
8208 shiftL1Left2Result (operand * left, int offl,
8209                     operand * result, int offr, int shCount)
8210 {
8211   char *l;
8212   l = aopGet (left, offl, FALSE, FALSE);
8213   MOVA (l);
8214   /* shift left accumulator */
8215   AccLsh (shCount);
8216   aopPut (result, "a", offr);
8217 }
8218
8219 /*-----------------------------------------------------------------*/
8220 /* movLeft2Result - move byte from left to result                  */
8221 /*-----------------------------------------------------------------*/
8222 static void
8223 movLeft2Result (operand * left, int offl,
8224                 operand * result, int offr, int sign)
8225 {
8226   char *l;
8227   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8228     {
8229       l = aopGet (left, offl, FALSE, FALSE);
8230
8231       if (*l == '@' && (IS_AOP_PREG (result)))
8232         {
8233           emitcode ("mov", "a,%s", l);
8234           aopPut (result, "a", offr);
8235         }
8236       else
8237         {
8238           if (!sign)
8239             {
8240               aopPut (result, l, offr);
8241             }
8242           else
8243             {
8244               /* MSB sign in acc.7 ! */
8245               if (getDataSize (left) == offl + 1)
8246                 {
8247                   MOVA (l);
8248                   aopPut (result, "a", offr);
8249                 }
8250             }
8251         }
8252     }
8253 }
8254
8255 /*-----------------------------------------------------------------*/
8256 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8257 /*-----------------------------------------------------------------*/
8258 static void
8259 AccAXRrl1 (char *x)
8260 {
8261   emitcode ("rrc", "a");
8262   emitcode ("xch", "a,%s", x);
8263   emitcode ("rrc", "a");
8264   emitcode ("xch", "a,%s", x);
8265 }
8266
8267 /*-----------------------------------------------------------------*/
8268 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8269 /*-----------------------------------------------------------------*/
8270 static void
8271 AccAXLrl1 (char *x)
8272 {
8273   emitcode ("xch", "a,%s", x);
8274   emitcode ("rlc", "a");
8275   emitcode ("xch", "a,%s", x);
8276   emitcode ("rlc", "a");
8277 }
8278
8279 /*-----------------------------------------------------------------*/
8280 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8281 /*-----------------------------------------------------------------*/
8282 static void
8283 AccAXLsh1 (char *x)
8284 {
8285   emitcode ("xch", "a,%s", x);
8286   emitcode ("add", "a,acc");
8287   emitcode ("xch", "a,%s", x);
8288   emitcode ("rlc", "a");
8289 }
8290
8291 /*-----------------------------------------------------------------*/
8292 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8293 /*-----------------------------------------------------------------*/
8294 static void
8295 AccAXLsh (char *x, int shCount)
8296 {
8297   switch (shCount)
8298     {
8299     case 0:
8300       break;
8301     case 1:
8302       AccAXLsh1 (x);
8303       break;
8304     case 2:
8305       AccAXLsh1 (x);
8306       AccAXLsh1 (x);
8307       break;
8308     case 3:
8309     case 4:
8310     case 5:                     // AAAAABBB:CCCCCDDD
8311
8312       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8313
8314       emitcode ("anl", "a,#0x%02x",
8315                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8316
8317       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8318
8319       AccRol (shCount);         // DDDCCCCC:BBB00000
8320
8321       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8322
8323       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8324
8325       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8326
8327       emitcode ("anl", "a,#0x%02x",
8328                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8329
8330       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8331
8332       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8333
8334       break;
8335     case 6:                     // AAAAAABB:CCCCCCDD
8336       emitcode ("anl", "a,#0x%02x",
8337                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8338       emitcode ("mov", "c,acc.0");      // c = B
8339       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8340 #if 0 // REMOVE ME
8341       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8342       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8343 #else
8344       emitcode("rrc","a");
8345       emitcode("xch","a,%s", x);
8346       emitcode("rrc","a");
8347       emitcode("mov","c,acc.0"); //<< get correct bit
8348       emitcode("xch","a,%s", x);
8349
8350       emitcode("rrc","a");
8351       emitcode("xch","a,%s", x);
8352       emitcode("rrc","a");
8353       emitcode("xch","a,%s", x);
8354 #endif
8355       break;
8356     case 7:                     // a:x <<= 7
8357
8358       emitcode ("anl", "a,#0x%02x",
8359                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8360
8361       emitcode ("mov", "c,acc.0");      // c = B
8362
8363       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8364
8365       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8366
8367       break;
8368     default:
8369       break;
8370     }
8371 }
8372
8373 /*-----------------------------------------------------------------*/
8374 /* AccAXRsh - right shift a:x known count (0..7)                   */
8375 /*-----------------------------------------------------------------*/
8376 static void
8377 AccAXRsh (char *x, int shCount)
8378 {
8379   switch (shCount)
8380     {
8381     case 0:
8382       break;
8383     case 1:
8384       CLRC;
8385       AccAXRrl1 (x);            // 0->a:x
8386
8387       break;
8388     case 2:
8389       CLRC;
8390       AccAXRrl1 (x);            // 0->a:x
8391
8392       CLRC;
8393       AccAXRrl1 (x);            // 0->a:x
8394
8395       break;
8396     case 3:
8397     case 4:
8398     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8399
8400       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8401
8402       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8403
8404       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8405
8406       emitcode ("anl", "a,#0x%02x",
8407                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8408
8409       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8410
8411       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8412
8413       emitcode ("anl", "a,#0x%02x",
8414                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8415
8416       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8417
8418       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8419
8420       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8421
8422       break;
8423     case 6:                     // AABBBBBB:CCDDDDDD
8424
8425       emitcode ("mov", "c,acc.7");
8426       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8427
8428       emitcode ("mov", "c,acc.7");
8429       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8430
8431       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8432
8433       emitcode ("anl", "a,#0x%02x",
8434                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8435
8436       break;
8437     case 7:                     // ABBBBBBB:CDDDDDDD
8438
8439       emitcode ("mov", "c,acc.7");      // c = A
8440
8441       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8442
8443       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8444
8445       emitcode ("anl", "a,#0x%02x",
8446                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8447
8448       break;
8449     default:
8450       break;
8451     }
8452 }
8453
8454 /*-----------------------------------------------------------------*/
8455 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8456 /*-----------------------------------------------------------------*/
8457 static void
8458 AccAXRshS (char *x, int shCount)
8459 {
8460   symbol *tlbl;
8461   switch (shCount)
8462     {
8463     case 0:
8464       break;
8465     case 1:
8466       emitcode ("mov", "c,acc.7");
8467       AccAXRrl1 (x);            // s->a:x
8468
8469       break;
8470     case 2:
8471       emitcode ("mov", "c,acc.7");
8472       AccAXRrl1 (x);            // s->a:x
8473
8474       emitcode ("mov", "c,acc.7");
8475       AccAXRrl1 (x);            // s->a:x
8476
8477       break;
8478     case 3:
8479     case 4:
8480     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8481
8482       tlbl = newiTempLabel (NULL);
8483       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8484
8485       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8486
8487       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8488
8489       emitcode ("anl", "a,#0x%02x",
8490                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8491
8492       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8493
8494       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8495
8496       emitcode ("anl", "a,#0x%02x",
8497                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8498
8499       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8500
8501       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8502
8503       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8504
8505       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8506       emitcode ("orl", "a,#0x%02x",
8507                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8508
8509       emitLabel (tlbl);
8510       break;                    // SSSSAAAA:BBBCCCCC
8511
8512     case 6:                     // AABBBBBB:CCDDDDDD
8513
8514       tlbl = newiTempLabel (NULL);
8515       emitcode ("mov", "c,acc.7");
8516       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8517
8518       emitcode ("mov", "c,acc.7");
8519       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8520
8521       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8522
8523       emitcode ("anl", "a,#0x%02x",
8524                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8525
8526       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8527       emitcode ("orl", "a,#0x%02x",
8528                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8529
8530       emitLabel (tlbl);
8531       break;
8532     case 7:                     // ABBBBBBB:CDDDDDDD
8533
8534       tlbl = newiTempLabel (NULL);
8535       emitcode ("mov", "c,acc.7");      // c = A
8536
8537       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8538
8539       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8540
8541       emitcode ("anl", "a,#0x%02x",
8542                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8543
8544       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8545       emitcode ("orl", "a,#0x%02x",
8546                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8547
8548       emitLabel (tlbl);
8549       break;
8550     default:
8551       break;
8552     }
8553 }
8554
8555 /*-----------------------------------------------------------------*/
8556 /* shiftL2Left2Result - shift left two bytes from left to result   */
8557 /*-----------------------------------------------------------------*/
8558 static void
8559 shiftL2Left2Result (operand * left, int offl,
8560                     operand * result, int offr, int shCount)
8561 {
8562   char * x;
8563   bool pushedB = FALSE;
8564   bool usedB = FALSE;
8565
8566   if (sameRegs (AOP (result), AOP (left)) &&
8567       ((offl + MSB16) == offr))
8568     {
8569       /* don't crash result[offr] */
8570       MOVA (aopGet (left, offl, FALSE, FALSE));
8571       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8572       usedB = !strncmp(x, "b", 1);
8573     }
8574   else if (aopGetUsesAcc (result, offr))
8575     {
8576       movLeft2Result (left, offl, result, offr, 0);
8577       pushedB = pushB ();
8578       usedB = TRUE;
8579       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8580       MOVA (aopGet (result, offr, FALSE, FALSE));
8581       emitcode ("xch", "a,b");
8582       x = "b";
8583     }
8584   else
8585     {
8586       movLeft2Result (left, offl, result, offr, 0);
8587       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8588       x = aopGet (result, offr, FALSE, FALSE);
8589     }
8590   /* ax << shCount (x = lsb(result)) */
8591   AccAXLsh (x, shCount);
8592   if (usedB)
8593     {
8594       emitcode ("xch", "a,b");
8595       aopPut (result, "a", offr);
8596       aopPut (result, "b", offr + MSB16);
8597       popB (pushedB);
8598     }
8599   else
8600     {
8601       aopPut (result, "a", offr + MSB16);
8602     }
8603 }
8604
8605
8606 /*-----------------------------------------------------------------*/
8607 /* shiftR2Left2Result - shift right two bytes from left to result  */
8608 /*-----------------------------------------------------------------*/
8609 static void
8610 shiftR2Left2Result (operand * left, int offl,
8611                     operand * result, int offr,
8612                     int shCount, int sign)
8613 {
8614   char * x;
8615   bool pushedB = FALSE;
8616   bool usedB = FALSE;
8617
8618   if (sameRegs (AOP (result), AOP (left)) &&
8619       ((offl + MSB16) == offr))
8620     {
8621       /* don't crash result[offr] */
8622       MOVA (aopGet (left, offl, FALSE, FALSE));
8623       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8624       usedB = !strncmp(x, "b", 1);
8625     }
8626   else if (aopGetUsesAcc (result, offr))
8627     {
8628       movLeft2Result (left, offl, result, offr, 0);
8629       pushedB = pushB ();
8630       usedB = TRUE;
8631       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8632       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8633       x = "b";
8634     }
8635   else
8636     {
8637       movLeft2Result (left, offl, result, offr, 0);
8638       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8639       x = aopGet (result, offr, FALSE, FALSE);
8640     }
8641   /* a:x >> shCount (x = lsb(result)) */
8642   if (sign)
8643     AccAXRshS (x, shCount);
8644   else
8645     AccAXRsh (x, shCount);
8646   if (usedB)
8647     {
8648       emitcode ("xch", "a,b");
8649       aopPut (result, "a", offr);
8650       emitcode ("xch", "a,b");
8651       popB (pushedB);
8652     }
8653   if (getDataSize (result) > 1)
8654     aopPut (result, "a", offr + MSB16);
8655 }
8656
8657 /*-----------------------------------------------------------------*/
8658 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8659 /*-----------------------------------------------------------------*/
8660 static void
8661 shiftLLeftOrResult (operand * left, int offl,
8662                     operand * result, int offr, int shCount)
8663 {
8664   MOVA (aopGet (left, offl, FALSE, FALSE));
8665   /* shift left accumulator */
8666   AccLsh (shCount);
8667   /* or with result */
8668   if (aopGetUsesAcc (result, offr))
8669     {
8670       emitcode ("xch", "a,b");
8671       MOVA (aopGet (result, offr, FALSE, FALSE));
8672       emitcode ("orl", "a,b");
8673     }
8674   else
8675     {
8676       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8677     }
8678   /* back to result */
8679   aopPut (result, "a", offr);
8680 }
8681
8682 /*-----------------------------------------------------------------*/
8683 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8684 /*-----------------------------------------------------------------*/
8685 static void
8686 shiftRLeftOrResult (operand * left, int offl,
8687                     operand * result, int offr, int shCount)
8688 {
8689   MOVA (aopGet (left, offl, FALSE, FALSE));
8690   /* shift right accumulator */
8691   AccRsh (shCount);
8692   /* or with result */
8693   if (aopGetUsesAcc(result, offr))
8694     {
8695       emitcode ("xch", "a,b");
8696       MOVA (aopGet (result, offr, FALSE, FALSE));
8697       emitcode ("orl", "a,b");
8698     }
8699   else
8700     {
8701       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8702     }
8703   /* back to result */
8704   aopPut (result, "a", offr);
8705 }
8706
8707 /*-----------------------------------------------------------------*/
8708 /* genlshOne - left shift a one byte quantity by known count       */
8709 /*-----------------------------------------------------------------*/
8710 static void
8711 genlshOne (operand * result, operand * left, int shCount)
8712 {
8713   D (emitcode (";", "genlshOne"));
8714
8715   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8716 }
8717
8718 /*-----------------------------------------------------------------*/
8719 /* genlshTwo - left shift two bytes by known amount != 0           */
8720 /*-----------------------------------------------------------------*/
8721 static void
8722 genlshTwo (operand * result, operand * left, int shCount)
8723 {
8724   int size;
8725
8726   D (emitcode (";", "genlshTwo"));
8727
8728   size = getDataSize (result);
8729
8730   /* if shCount >= 8 */
8731   if (shCount >= 8)
8732     {
8733       shCount -= 8;
8734
8735       if (size > 1)
8736         {
8737           if (shCount)
8738             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8739           else
8740             movLeft2Result (left, LSB, result, MSB16, 0);
8741         }
8742       aopPut (result, zero, LSB);
8743     }
8744
8745   /*  1 <= shCount <= 7 */
8746   else
8747     {
8748       if (size == 1)
8749         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8750       else
8751         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8752     }
8753 }
8754
8755 /*-----------------------------------------------------------------*/
8756 /* shiftLLong - shift left one long from left to result            */
8757 /* offl = LSB or MSB16                                             */
8758 /*-----------------------------------------------------------------*/
8759 static void
8760 shiftLLong (operand * left, operand * result, int offr)
8761 {
8762   char *l;
8763   int size = AOP_SIZE (result);
8764
8765   if (size >= LSB + offr)
8766     {
8767       l = aopGet (left, LSB, FALSE, FALSE);
8768       MOVA (l);
8769       emitcode ("add", "a,acc");
8770       if (sameRegs (AOP (left), AOP (result)) &&
8771           size >= MSB16 + offr && offr != LSB)
8772         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8773       else
8774         aopPut (result, "a", LSB + offr);
8775     }
8776
8777   if (size >= MSB16 + offr)
8778     {
8779       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8780         {
8781           l = aopGet (left, MSB16, FALSE, FALSE);
8782           MOVA (l);
8783         }
8784       emitcode ("rlc", "a");
8785       if (sameRegs (AOP (left), AOP (result)) &&
8786           size >= MSB24 + offr && offr != LSB)
8787         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8788       else
8789         aopPut (result, "a", MSB16 + offr);
8790     }
8791
8792   if (size >= MSB24 + offr)
8793     {
8794       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8795         {
8796           l = aopGet (left, MSB24, FALSE, FALSE);
8797           MOVA (l);
8798         }
8799       emitcode ("rlc", "a");
8800       if (sameRegs (AOP (left), AOP (result)) &&
8801           size >= MSB32 + offr && offr != LSB)
8802         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8803       else
8804         aopPut (result, "a", MSB24 + offr);
8805     }
8806
8807   if (size > MSB32 + offr)
8808     {
8809       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8810         {
8811           l = aopGet (left, MSB32, FALSE, FALSE);
8812           MOVA (l);
8813         }
8814       emitcode ("rlc", "a");
8815       aopPut (result, "a", MSB32 + offr);
8816     }
8817   if (offr != LSB)
8818     aopPut (result, zero, LSB);
8819 }
8820
8821 /*-----------------------------------------------------------------*/
8822 /* genlshFour - shift four byte by a known amount != 0             */
8823 /*-----------------------------------------------------------------*/
8824 static void
8825 genlshFour (operand * result, operand * left, int shCount)
8826 {
8827   int size;
8828
8829   D (emitcode (";", "genlshFour"));
8830
8831   size = AOP_SIZE (result);
8832
8833   /* if shifting more that 3 bytes */
8834   if (shCount >= 24)
8835     {
8836       shCount -= 24;
8837       if (shCount)
8838         /* lowest order of left goes to the highest
8839            order of the destination */
8840         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8841       else
8842         movLeft2Result (left, LSB, result, MSB32, 0);
8843       aopPut (result, zero, LSB);
8844       aopPut (result, zero, MSB16);
8845       aopPut (result, zero, MSB24);
8846       return;
8847     }
8848
8849   /* more than two bytes */
8850   else if (shCount >= 16)
8851     {
8852       /* lower order two bytes goes to higher order two bytes */
8853       shCount -= 16;
8854       /* if some more remaining */
8855       if (shCount)
8856         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8857       else
8858         {
8859           movLeft2Result (left, MSB16, result, MSB32, 0);
8860           movLeft2Result (left, LSB, result, MSB24, 0);
8861         }
8862       aopPut (result, zero, MSB16);
8863       aopPut (result, zero, LSB);
8864       return;
8865     }
8866
8867   /* if more than 1 byte */
8868   else if (shCount >= 8)
8869     {
8870       /* lower order three bytes goes to higher order  three bytes */
8871       shCount -= 8;
8872       if (size == 2)
8873         {
8874           if (shCount)
8875             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8876           else
8877             movLeft2Result (left, LSB, result, MSB16, 0);
8878         }
8879       else
8880         {                       /* size = 4 */
8881           if (shCount == 0)
8882             {
8883               movLeft2Result (left, MSB24, result, MSB32, 0);
8884               movLeft2Result (left, MSB16, result, MSB24, 0);
8885               movLeft2Result (left, LSB, result, MSB16, 0);
8886               aopPut (result, zero, LSB);
8887             }
8888           else if (shCount == 1)
8889             shiftLLong (left, result, MSB16);
8890           else
8891             {
8892               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8893               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8894               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8895               aopPut (result, zero, LSB);
8896             }
8897         }
8898     }
8899
8900   /* 1 <= shCount <= 7 */
8901   else if (shCount <= 2)
8902     {
8903       shiftLLong (left, result, LSB);
8904       if (shCount == 2)
8905         shiftLLong (result, result, LSB);
8906     }
8907   /* 3 <= shCount <= 7, optimize */
8908   else
8909     {
8910       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8911       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8912       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8913     }
8914 }
8915
8916 /*-----------------------------------------------------------------*/
8917 /* genLeftShiftLiteral - left shifting by known count              */
8918 /*-----------------------------------------------------------------*/
8919 static void
8920 genLeftShiftLiteral (operand * left,
8921                      operand * right,
8922                      operand * result,
8923                      iCode * ic)
8924 {
8925   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8926   int size;
8927
8928   D (emitcode (";", "genLeftShiftLiteral"));
8929
8930   freeAsmop (right, NULL, ic, TRUE);
8931
8932   aopOp (left, ic, FALSE);
8933   aopOp (result, ic, FALSE);
8934
8935   size = getSize (operandType (result));
8936
8937 #if VIEW_SIZE
8938   emitcode ("; shift left ", "result %d, left %d", size,
8939             AOP_SIZE (left));
8940 #endif
8941
8942   /* I suppose that the left size >= result size */
8943   if (shCount == 0)
8944     {
8945       while (size--)
8946         {
8947           movLeft2Result (left, size, result, size, 0);
8948         }
8949     }
8950   else if (shCount >= (size * 8))
8951     {
8952       while (size--)
8953         {
8954           aopPut (result, zero, size);
8955         }
8956     }
8957   else
8958     {
8959       switch (size)
8960         {
8961         case 1:
8962           genlshOne (result, left, shCount);
8963           break;
8964
8965         case 2:
8966           genlshTwo (result, left, shCount);
8967           break;
8968
8969         case 4:
8970           genlshFour (result, left, shCount);
8971           break;
8972         default:
8973           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8974                   "*** ack! mystery literal shift!\n");
8975           break;
8976         }
8977     }
8978   freeAsmop (result, NULL, ic, TRUE);
8979   freeAsmop (left, NULL, ic, TRUE);
8980 }
8981
8982 /*-----------------------------------------------------------------*/
8983 /* genLeftShift - generates code for left shifting                 */
8984 /*-----------------------------------------------------------------*/
8985 static void
8986 genLeftShift (iCode * ic)
8987 {
8988   operand *left, *right, *result;
8989   int size, offset;
8990   char *l;
8991   symbol *tlbl, *tlbl1;
8992   bool pushedB;
8993
8994   D (emitcode (";", "genLeftShift"));
8995
8996   right = IC_RIGHT (ic);
8997   left = IC_LEFT (ic);
8998   result = IC_RESULT (ic);
8999
9000   aopOp (right, ic, FALSE);
9001
9002   /* if the shift count is known then do it
9003      as efficiently as possible */
9004   if (AOP_TYPE (right) == AOP_LIT)
9005     {
9006       genLeftShiftLiteral (left, right, result, ic);
9007       return;
9008     }
9009
9010   /* shift count is unknown then we have to form
9011      a loop get the loop count in B : Note: we take
9012      only the lower order byte since shifting
9013      more that 32 bits make no sense anyway, ( the
9014      largest size of an object can be only 32 bits ) */
9015
9016   pushedB = pushB ();
9017   MOVB (aopGet (right, 0, FALSE, FALSE));
9018   emitcode ("inc", "b");
9019   freeAsmop (right, NULL, ic, TRUE);
9020   aopOp (left, ic, FALSE);
9021   aopOp (result, ic, FALSE);
9022
9023   /* now move the left to the result if they are not the same */
9024   if (!sameRegs (AOP (left), AOP (result)) &&
9025       AOP_SIZE (result) > 1)
9026     {
9027
9028       size = AOP_SIZE (result);
9029       offset = 0;
9030       while (size--)
9031         {
9032           l = aopGet (left, offset, FALSE, TRUE);
9033           if (*l == '@' && (IS_AOP_PREG (result)))
9034             {
9035
9036               emitcode ("mov", "a,%s", l);
9037               aopPut (result, "a", offset);
9038             }
9039           else
9040             aopPut (result, l, offset);
9041           offset++;
9042         }
9043     }
9044
9045   tlbl = newiTempLabel (NULL);
9046   size = AOP_SIZE (result);
9047   offset = 0;
9048   tlbl1 = newiTempLabel (NULL);
9049
9050   /* if it is only one byte then */
9051   if (size == 1)
9052     {
9053       symbol *tlbl1 = newiTempLabel (NULL);
9054
9055       l = aopGet (left, 0, FALSE, FALSE);
9056       MOVA (l);
9057       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9058       emitLabel (tlbl);
9059       emitcode ("add", "a,acc");
9060       emitLabel (tlbl1);
9061       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9062       popB (pushedB);
9063       aopPut (result, "a", 0);
9064       goto release;
9065     }
9066
9067   reAdjustPreg (AOP (result));
9068
9069   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9070   emitLabel (tlbl);
9071   l = aopGet (result, offset, FALSE, FALSE);
9072   MOVA (l);
9073   emitcode ("add", "a,acc");
9074   aopPut (result, "a", offset++);
9075   while (--size)
9076     {
9077       l = aopGet (result, offset, FALSE, FALSE);
9078       MOVA (l);
9079       emitcode ("rlc", "a");
9080       aopPut (result, "a", offset++);
9081     }
9082   reAdjustPreg (AOP (result));
9083
9084   emitLabel (tlbl1);
9085   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9086   popB (pushedB);
9087 release:
9088   freeAsmop (result, NULL, ic, TRUE);
9089   freeAsmop (left, NULL, ic, TRUE);
9090 }
9091
9092 /*-----------------------------------------------------------------*/
9093 /* genrshOne - right shift a one byte quantity by known count      */
9094 /*-----------------------------------------------------------------*/
9095 static void
9096 genrshOne (operand * result, operand * left,
9097            int shCount, int sign)
9098 {
9099   D (emitcode (";", "genrshOne"));
9100
9101   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9102 }
9103
9104 /*-----------------------------------------------------------------*/
9105 /* genrshTwo - right shift two bytes by known amount != 0          */
9106 /*-----------------------------------------------------------------*/
9107 static void
9108 genrshTwo (operand * result, operand * left,
9109            int shCount, int sign)
9110 {
9111   D (emitcode (";", "genrshTwo"));
9112
9113   /* if shCount >= 8 */
9114   if (shCount >= 8)
9115     {
9116       shCount -= 8;
9117       if (shCount)
9118         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9119       else
9120         movLeft2Result (left, MSB16, result, LSB, sign);
9121       addSign (result, MSB16, sign);
9122     }
9123
9124   /*  1 <= shCount <= 7 */
9125   else
9126     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9127 }
9128
9129 /*-----------------------------------------------------------------*/
9130 /* shiftRLong - shift right one long from left to result           */
9131 /* offl = LSB or MSB16                                             */
9132 /*-----------------------------------------------------------------*/
9133 static void
9134 shiftRLong (operand * left, int offl,
9135             operand * result, int sign)
9136 {
9137   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9138
9139   if (overlapping && offl>1)
9140     {
9141       // we are in big trouble, but this shouldn't happen
9142       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9143     }
9144
9145   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9146
9147   if (offl==MSB16)
9148     {
9149       // shift is > 8
9150       if (sign)
9151         {
9152           emitcode ("rlc", "a");
9153           emitcode ("subb", "a,acc");
9154           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9155             {
9156               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9157             }
9158           else
9159             {
9160               aopPut (result, "a", MSB32);
9161               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9162             }
9163         }
9164       else
9165         {
9166           if (aopPutUsesAcc (result, zero, MSB32))
9167             {
9168               emitcode("xch", "a,b");
9169               aopPut (result, zero, MSB32);
9170               emitcode("xch", "a,b");
9171             }
9172           else
9173             {
9174               aopPut (result, zero, MSB32);
9175             }
9176         }
9177     }
9178
9179   if (!sign)
9180     {
9181       emitcode ("clr", "c");
9182     }
9183   else
9184     {
9185       emitcode ("mov", "c,acc.7");
9186     }
9187
9188   emitcode ("rrc", "a");
9189
9190   if (overlapping && offl==MSB16 &&
9191       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9192     {
9193       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9194     }
9195   else
9196     {
9197       aopPut (result, "a", MSB32 - offl);
9198       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9199     }
9200
9201   emitcode ("rrc", "a");
9202   if (overlapping && offl==MSB16 &&
9203       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9204     {
9205       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9206     }
9207   else
9208     {
9209       aopPut (result, "a", MSB24 - offl);
9210       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9211     }
9212
9213   emitcode ("rrc", "a");
9214   if (offl != LSB)
9215     {
9216       aopPut (result, "a", MSB16 - offl);
9217     }
9218   else
9219     {
9220       if (overlapping &&
9221           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9222         {
9223           xch_a_aopGet (left, LSB, FALSE, FALSE);
9224         }
9225       else
9226         {
9227           aopPut (result, "a", MSB16 - offl);
9228           MOVA (aopGet (left, LSB, FALSE, FALSE));
9229         }
9230       emitcode ("rrc", "a");
9231       aopPut (result, "a", LSB);
9232     }
9233 }
9234
9235 /*-----------------------------------------------------------------*/
9236 /* genrshFour - shift four byte by a known amount != 0             */
9237 /*-----------------------------------------------------------------*/
9238 static void
9239 genrshFour (operand * result, operand * left,
9240             int shCount, int sign)
9241 {
9242   D (emitcode (";", "genrshFour"));
9243
9244   /* if shifting more that 3 bytes */
9245   if (shCount >= 24)
9246     {
9247       shCount -= 24;
9248       if (shCount)
9249         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9250       else
9251         movLeft2Result (left, MSB32, result, LSB, sign);
9252       addSign (result, MSB16, sign);
9253     }
9254   else if (shCount >= 16)
9255     {
9256       shCount -= 16;
9257       if (shCount)
9258         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9259       else
9260         {
9261           movLeft2Result (left, MSB24, result, LSB, 0);
9262           movLeft2Result (left, MSB32, result, MSB16, sign);
9263         }
9264       addSign (result, MSB24, sign);
9265     }
9266   else if (shCount >= 8)
9267     {
9268       shCount -= 8;
9269       if (shCount == 1)
9270         {
9271           shiftRLong (left, MSB16, result, sign);
9272         }
9273       else if (shCount == 0)
9274         {
9275           movLeft2Result (left, MSB16, result, LSB, 0);
9276           movLeft2Result (left, MSB24, result, MSB16, 0);
9277           movLeft2Result (left, MSB32, result, MSB24, sign);
9278           addSign (result, MSB32, sign);
9279         }
9280       else
9281         {
9282           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9283           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9284           /* the last shift is signed */
9285           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9286           addSign (result, MSB32, sign);
9287         }
9288     }
9289   else
9290     {
9291       /* 1 <= shCount <= 7 */
9292       if (shCount <= 2)
9293         {
9294           shiftRLong (left, LSB, result, sign);
9295           if (shCount == 2)
9296             shiftRLong (result, LSB, result, sign);
9297         }
9298       else
9299         {
9300           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9301           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9302           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9303         }
9304     }
9305 }
9306
9307 /*-----------------------------------------------------------------*/
9308 /* genRightShiftLiteral - right shifting by known count            */
9309 /*-----------------------------------------------------------------*/
9310 static void
9311 genRightShiftLiteral (operand * left,
9312                       operand * right,
9313                       operand * result,
9314                       iCode * ic,
9315                       int sign)
9316 {
9317   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9318   int size;
9319
9320   D (emitcode (";", "genRightShiftLiteral"));
9321
9322   freeAsmop (right, NULL, ic, TRUE);
9323
9324   aopOp (left, ic, FALSE);
9325   aopOp (result, ic, FALSE);
9326
9327 #if VIEW_SIZE
9328   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9329             AOP_SIZE (left));
9330 #endif
9331
9332   size = getDataSize (left);
9333   /* test the LEFT size !!! */
9334
9335   /* I suppose that the left size >= result size */
9336   if (shCount == 0)
9337     {
9338       size = getDataSize (result);
9339       while (size--)
9340         movLeft2Result (left, size, result, size, 0);
9341     }
9342
9343   else if (shCount >= (size * 8))
9344     {
9345       if (sign)
9346         {
9347           /* get sign in acc.7 */
9348           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9349         }
9350       addSign (result, LSB, sign);
9351     }
9352   else
9353     {
9354       switch (size)
9355         {
9356         case 1:
9357           genrshOne (result, left, shCount, sign);
9358           break;
9359
9360         case 2:
9361           genrshTwo (result, left, shCount, sign);
9362           break;
9363
9364         case 4:
9365           genrshFour (result, left, shCount, sign);
9366           break;
9367         default:
9368           break;
9369         }
9370     }
9371   freeAsmop (result, NULL, ic, TRUE);
9372   freeAsmop (left, NULL, ic, TRUE);
9373 }
9374
9375 /*-----------------------------------------------------------------*/
9376 /* genSignedRightShift - right shift of signed number              */
9377 /*-----------------------------------------------------------------*/
9378 static void
9379 genSignedRightShift (iCode * ic)
9380 {
9381   operand *right, *left, *result;
9382   int size, offset;
9383   char *l;
9384   symbol *tlbl, *tlbl1;
9385   bool pushedB;
9386
9387   D (emitcode (";", "genSignedRightShift"));
9388
9389   /* we do it the hard way put the shift count in b
9390      and loop thru preserving the sign */
9391
9392   right = IC_RIGHT (ic);
9393   left = IC_LEFT (ic);
9394   result = IC_RESULT (ic);
9395
9396   aopOp (right, ic, FALSE);
9397
9398
9399   if (AOP_TYPE (right) == AOP_LIT)
9400     {
9401       genRightShiftLiteral (left, right, result, ic, 1);
9402       return;
9403     }
9404   /* shift count is unknown then we have to form
9405      a loop get the loop count in B : Note: we take
9406      only the lower order byte since shifting
9407      more that 32 bits make no sense anyway, ( the
9408      largest size of an object can be only 32 bits ) */
9409
9410   pushedB = pushB ();
9411   MOVB (aopGet (right, 0, FALSE, FALSE));
9412   emitcode ("inc", "b");
9413   freeAsmop (right, NULL, ic, TRUE);
9414   aopOp (left, ic, FALSE);
9415   aopOp (result, ic, FALSE);
9416
9417   /* now move the left to the result if they are not the
9418      same */
9419   if (!sameRegs (AOP (left), AOP (result)) &&
9420       AOP_SIZE (result) > 1)
9421     {
9422
9423       size = AOP_SIZE (result);
9424       offset = 0;
9425       while (size--)
9426         {
9427           l = aopGet (left, offset, FALSE, TRUE);
9428           if (*l == '@' && IS_AOP_PREG (result))
9429             {
9430
9431               emitcode ("mov", "a,%s", l);
9432               aopPut (result, "a", offset);
9433             }
9434           else
9435             aopPut (result, l, offset);
9436           offset++;
9437         }
9438     }
9439
9440   /* mov the highest order bit to OVR */
9441   tlbl = newiTempLabel (NULL);
9442   tlbl1 = newiTempLabel (NULL);
9443
9444   size = AOP_SIZE (result);
9445   offset = size - 1;
9446   MOVA (aopGet (left, offset, FALSE, FALSE));
9447   emitcode ("rlc", "a");
9448   emitcode ("mov", "ov,c");
9449   /* if it is only one byte then */
9450   if (size == 1)
9451     {
9452       l = aopGet (left, 0, FALSE, FALSE);
9453       MOVA (l);
9454       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9455       emitLabel (tlbl);
9456       emitcode ("mov", "c,ov");
9457       emitcode ("rrc", "a");
9458       emitLabel (tlbl1);
9459       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9460       popB (pushedB);
9461       aopPut (result, "a", 0);
9462       goto release;
9463     }
9464
9465   reAdjustPreg (AOP (result));
9466   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9467   emitLabel (tlbl);
9468   emitcode ("mov", "c,ov");
9469   while (size--)
9470     {
9471       l = aopGet (result, offset, FALSE, FALSE);
9472       MOVA (l);
9473       emitcode ("rrc", "a");
9474       aopPut (result, "a", offset--);
9475     }
9476   reAdjustPreg (AOP (result));
9477   emitLabel (tlbl1);
9478   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9479   popB (pushedB);
9480
9481 release:
9482   freeAsmop (result, NULL, ic, TRUE);
9483   freeAsmop (left, NULL, ic, TRUE);
9484 }
9485
9486 /*-----------------------------------------------------------------*/
9487 /* genRightShift - generate code for right shifting                */
9488 /*-----------------------------------------------------------------*/
9489 static void
9490 genRightShift (iCode * ic)
9491 {
9492   operand *right, *left, *result;
9493   sym_link *letype;
9494   int size, offset;
9495   char *l;
9496   symbol *tlbl, *tlbl1;
9497   bool pushedB;
9498
9499   D (emitcode (";", "genRightShift"));
9500
9501   /* if signed then we do it the hard way preserve the
9502      sign bit moving it inwards */
9503   letype = getSpec (operandType (IC_LEFT (ic)));
9504
9505   if (!SPEC_USIGN (letype))
9506     {
9507       genSignedRightShift (ic);
9508       return;
9509     }
9510
9511   /* signed & unsigned types are treated the same : i.e. the
9512      signed is NOT propagated inwards : quoting from the
9513      ANSI - standard : "for E1 >> E2, is equivalent to division
9514      by 2**E2 if unsigned or if it has a non-negative value,
9515      otherwise the result is implementation defined ", MY definition
9516      is that the sign does not get propagated */
9517
9518   right = IC_RIGHT (ic);
9519   left = IC_LEFT (ic);
9520   result = IC_RESULT (ic);
9521
9522   aopOp (right, ic, FALSE);
9523
9524   /* if the shift count is known then do it
9525      as efficiently as possible */
9526   if (AOP_TYPE (right) == AOP_LIT)
9527     {
9528       genRightShiftLiteral (left, right, result, ic, 0);
9529       return;
9530     }
9531
9532   /* shift count is unknown then we have to form
9533      a loop get the loop count in B : Note: we take
9534      only the lower order byte since shifting
9535      more that 32 bits make no sense anyway, ( the
9536      largest size of an object can be only 32 bits ) */
9537
9538   pushedB = pushB ();
9539   MOVB (aopGet (right, 0, FALSE, FALSE));
9540   emitcode ("inc", "b");
9541   freeAsmop (right, NULL, ic, TRUE);
9542   aopOp (left, ic, FALSE);
9543   aopOp (result, ic, FALSE);
9544
9545   /* now move the left to the result if they are not the
9546      same */
9547   if (!sameRegs (AOP (left), AOP (result)) &&
9548       AOP_SIZE (result) > 1)
9549     {
9550       size = AOP_SIZE (result);
9551       offset = 0;
9552       while (size--)
9553         {
9554           l = aopGet (left, offset, FALSE, TRUE);
9555           if (*l == '@' && IS_AOP_PREG (result))
9556             {
9557
9558               emitcode ("mov", "a,%s", l);
9559               aopPut (result, "a", offset);
9560             }
9561           else
9562             aopPut (result, l, offset);
9563           offset++;
9564         }
9565     }
9566
9567   tlbl = newiTempLabel (NULL);
9568   tlbl1 = newiTempLabel (NULL);
9569   size = AOP_SIZE (result);
9570   offset = size - 1;
9571
9572   /* if it is only one byte then */
9573   if (size == 1)
9574     {
9575       l = aopGet (left, 0, FALSE, FALSE);
9576       MOVA (l);
9577       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9578       emitLabel (tlbl);
9579       CLRC;
9580       emitcode ("rrc", "a");
9581       emitLabel (tlbl1);
9582       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9583       popB (pushedB);
9584       aopPut (result, "a", 0);
9585       goto release;
9586     }
9587
9588   reAdjustPreg (AOP (result));
9589   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9590   emitLabel (tlbl);
9591   CLRC;
9592   while (size--)
9593     {
9594       l = aopGet (result, offset, FALSE, FALSE);
9595       MOVA (l);
9596       emitcode ("rrc", "a");
9597       aopPut (result, "a", offset--);
9598     }
9599   reAdjustPreg (AOP (result));
9600
9601   emitLabel (tlbl1);
9602   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9603   popB (pushedB);
9604
9605 release:
9606   freeAsmop (result, NULL, ic, TRUE);
9607   freeAsmop (left, NULL, ic, TRUE);
9608 }
9609
9610 /*-----------------------------------------------------------------*/
9611 /* emitPtrByteGet - emits code to get a byte into A through a      */
9612 /*                  pointer register (R0, R1, or DPTR). The        */
9613 /*                  original value of A can be preserved in B.     */
9614 /*-----------------------------------------------------------------*/
9615 static void
9616 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9617 {
9618   switch (p_type)
9619     {
9620     case IPOINTER:
9621     case POINTER:
9622       if (preserveAinB)
9623         emitcode ("mov", "b,a");
9624       emitcode ("mov", "a,@%s", rname);
9625       break;
9626
9627     case PPOINTER:
9628       if (preserveAinB)
9629         emitcode ("mov", "b,a");
9630       emitcode ("movx", "a,@%s", rname);
9631       break;
9632
9633     case FPOINTER:
9634       if (preserveAinB)
9635         emitcode ("mov", "b,a");
9636       emitcode ("movx", "a,@dptr");
9637       break;
9638
9639     case CPOINTER:
9640       if (preserveAinB)
9641         emitcode ("mov", "b,a");
9642       emitcode ("clr", "a");
9643       emitcode ("movc", "a,@a+dptr");
9644       break;
9645
9646     case GPOINTER:
9647       if (preserveAinB)
9648         {
9649           emitcode ("push", "b");
9650           emitcode ("push", "acc");
9651         }
9652       emitcode ("lcall", "__gptrget");
9653       if (preserveAinB)
9654         emitcode ("pop", "b");
9655       break;
9656     }
9657 }
9658
9659 /*-----------------------------------------------------------------*/
9660 /* emitPtrByteSet - emits code to set a byte from src through a    */
9661 /*                  pointer register (R0, R1, or DPTR).            */
9662 /*-----------------------------------------------------------------*/
9663 static void
9664 emitPtrByteSet (char *rname, int p_type, char *src)
9665 {
9666   switch (p_type)
9667     {
9668     case IPOINTER:
9669     case POINTER:
9670       if (*src=='@')
9671         {
9672           MOVA (src);
9673           emitcode ("mov", "@%s,a", rname);
9674         }
9675       else
9676         emitcode ("mov", "@%s,%s", rname, src);
9677       break;
9678
9679     case PPOINTER:
9680       MOVA (src);
9681       emitcode ("movx", "@%s,a", rname);
9682       break;
9683
9684     case FPOINTER:
9685       MOVA (src);
9686       emitcode ("movx", "@dptr,a");
9687       break;
9688
9689     case GPOINTER:
9690       MOVA (src);
9691       emitcode ("lcall", "__gptrput");
9692       break;
9693     }
9694 }
9695
9696 /*-----------------------------------------------------------------*/
9697 /* genUnpackBits - generates code for unpacking bits               */
9698 /*-----------------------------------------------------------------*/
9699 static void
9700 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9701 {
9702   int offset = 0;       /* result byte offset */
9703   int rsize;            /* result size */
9704   int rlen = 0;         /* remaining bitfield length */
9705   sym_link *etype;      /* bitfield type information */
9706   int blen;             /* bitfield length */
9707   int bstr;             /* bitfield starting bit within byte */
9708   char buffer[10];
9709
9710   D(emitcode (";     genUnpackBits",""));
9711
9712   etype = getSpec (operandType (result));
9713   rsize = getSize (operandType (result));
9714   blen = SPEC_BLEN (etype);
9715   bstr = SPEC_BSTR (etype);
9716
9717   if (ifx && blen <= 8)
9718     {
9719       emitPtrByteGet (rname, ptype, FALSE);
9720       if (blen == 1)
9721         {
9722           SNPRINTF (buffer, sizeof(buffer),
9723                     "acc.%d", bstr);
9724           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9725         }
9726       else
9727         {
9728           if (blen < 8)
9729             emitcode ("anl", "a,#0x%02x",
9730                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9731           genIfxJump (ifx, "a", NULL, NULL, NULL);
9732         }
9733       return;
9734     }
9735   wassert (!ifx);
9736
9737   /* If the bitfield length is less than a byte */
9738   if (blen < 8)
9739     {
9740       emitPtrByteGet (rname, ptype, FALSE);
9741       AccRol (8 - bstr);
9742       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9743       if (!SPEC_USIGN (etype))
9744         {
9745           /* signed bitfield */
9746           symbol *tlbl = newiTempLabel (NULL);
9747
9748           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9749           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9750           emitLabel (tlbl);
9751         }
9752       aopPut (result, "a", offset++);
9753       goto finish;
9754     }
9755
9756   /* Bit field did not fit in a byte. Copy all
9757      but the partial byte at the end.  */
9758   for (rlen=blen;rlen>=8;rlen-=8)
9759     {
9760       emitPtrByteGet (rname, ptype, FALSE);
9761       aopPut (result, "a", offset++);
9762       if (rlen>8)
9763         emitcode ("inc", "%s", rname);
9764     }
9765
9766   /* Handle the partial byte at the end */
9767   if (rlen)
9768     {
9769       emitPtrByteGet (rname, ptype, FALSE);
9770       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9771       if (!SPEC_USIGN (etype))
9772         {
9773           /* signed bitfield */
9774           symbol *tlbl = newiTempLabel (NULL);
9775
9776           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9777           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9778           emitLabel (tlbl);
9779         }
9780       aopPut (result, "a", offset++);
9781     }
9782
9783 finish:
9784   if (offset < rsize)
9785     {
9786       char *source;
9787
9788       if (SPEC_USIGN (etype))
9789         source = zero;
9790       else
9791         {
9792           /* signed bitfield: sign extension with 0x00 or 0xff */
9793           emitcode ("rlc", "a");
9794           emitcode ("subb", "a,acc");
9795
9796           source = "a";
9797         }
9798       rsize -= offset;
9799       while (rsize--)
9800         aopPut (result, source, offset++);
9801     }
9802 }
9803
9804
9805 /*-----------------------------------------------------------------*/
9806 /* genDataPointerGet - generates code when ptr offset is known     */
9807 /*-----------------------------------------------------------------*/
9808 static void
9809 genDataPointerGet (operand * left,
9810                    operand * result,
9811                    iCode * ic)
9812 {
9813   char *l;
9814   char buffer[256];
9815   int size, offset = 0;
9816
9817   D (emitcode (";", "genDataPointerGet"));
9818
9819   aopOp (result, ic, TRUE);
9820
9821   /* get the string representation of the name */
9822   l = aopGet (left, 0, FALSE, TRUE);
9823   l++; // remove #
9824   size = AOP_SIZE (result);
9825   while (size--)
9826     {
9827       if (offset)
9828         {
9829           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9830         }
9831       else
9832         {
9833           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9834         }
9835       aopPut (result, buffer, offset++);
9836     }
9837
9838   freeAsmop (result, NULL, ic, TRUE);
9839   freeAsmop (left, NULL, ic, TRUE);
9840 }
9841
9842 /*-----------------------------------------------------------------*/
9843 /* genNearPointerGet - emitcode for near pointer fetch             */
9844 /*-----------------------------------------------------------------*/
9845 static void
9846 genNearPointerGet (operand * left,
9847                    operand * result,
9848                    iCode * ic,
9849                    iCode * pi,
9850                    iCode * ifx)
9851 {
9852   asmop *aop = NULL;
9853   regs *preg = NULL;
9854   char *rname;
9855   sym_link *rtype, *retype;
9856   sym_link *ltype = operandType (left);
9857   char buffer[80];
9858
9859   D (emitcode (";", "genNearPointerGet"));
9860
9861   rtype = operandType (result);
9862   retype = getSpec (rtype);
9863
9864   aopOp (left, ic, FALSE);
9865
9866   /* if left is rematerialisable and
9867      result is not bitfield variable type and
9868      the left is pointer to data space i.e
9869      lower 128 bytes of space */
9870   if (AOP_TYPE (left) == AOP_IMMD &&
9871       !IS_BITFIELD (retype) &&
9872       DCL_TYPE (ltype) == POINTER)
9873     {
9874       genDataPointerGet (left, result, ic);
9875       return;
9876     }
9877
9878  /* if the value is already in a pointer register
9879      then don't need anything more */
9880   if (!AOP_INPREG (AOP (left)))
9881     {
9882       if (IS_AOP_PREG (left))
9883         {
9884           // Aha, it is a pointer, just in disguise.
9885           rname = aopGet (left, 0, FALSE, FALSE);
9886           if (*rname != '@')
9887             {
9888               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9889                       __FILE__, __LINE__);
9890             }
9891           else
9892             {
9893               // Expected case.
9894               emitcode ("mov", "a%s,%s", rname + 1, rname);
9895               rname++;  // skip the '@'.
9896             }
9897         }
9898       else
9899         {
9900           /* otherwise get a free pointer register */
9901           aop = newAsmop (0);
9902           preg = getFreePtr (ic, &aop, FALSE);
9903           emitcode ("mov", "%s,%s",
9904                     preg->name,
9905                     aopGet (left, 0, FALSE, TRUE));
9906           rname = preg->name;
9907         }
9908     }
9909   else
9910     rname = aopGet (left, 0, FALSE, FALSE);
9911
9912   //aopOp (result, ic, FALSE);
9913   aopOp (result, ic, result?TRUE:FALSE);
9914
9915   /* if bitfield then unpack the bits */
9916   if (IS_BITFIELD (retype))
9917     genUnpackBits (result, rname, POINTER, ifx);
9918   else
9919     {
9920       /* we have can just get the values */
9921       int size = AOP_SIZE (result);
9922       int offset = 0;
9923
9924       while (size--)
9925         {
9926           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9927             {
9928
9929               emitcode ("mov", "a,@%s", rname);
9930               if (!ifx)
9931                 aopPut (result, "a", offset);
9932             }
9933           else
9934             {
9935               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9936               aopPut (result, buffer, offset);
9937             }
9938           offset++;
9939           if (size || pi)
9940             emitcode ("inc", "%s", rname);
9941         }
9942     }
9943
9944   /* now some housekeeping stuff */
9945   if (aop)       /* we had to allocate for this iCode */
9946     {
9947       if (pi) { /* post increment present */
9948         aopPut (left, rname, 0);
9949       }
9950       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9951     }
9952   else
9953     {
9954       /* we did not allocate which means left
9955          already in a pointer register, then
9956          if size > 0 && this could be used again
9957          we have to point it back to where it
9958          belongs */
9959       if ((AOP_SIZE (result) > 1 &&
9960            !OP_SYMBOL (left)->remat &&
9961            (OP_SYMBOL (left)->liveTo > ic->seq ||
9962             ic->depth)) &&
9963           !pi)
9964         {
9965           int size = AOP_SIZE (result) - 1;
9966           while (size--)
9967             emitcode ("dec", "%s", rname);
9968         }
9969     }
9970
9971   if (ifx && !ifx->generated)
9972     {
9973       genIfxJump (ifx, "a", left, NULL, result);
9974     }
9975
9976   /* done */
9977   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9978   freeAsmop (left, NULL, ic, TRUE);
9979   if (pi) pi->generated = 1;
9980 }
9981
9982 /*-----------------------------------------------------------------*/
9983 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9984 /*-----------------------------------------------------------------*/
9985 static void
9986 genPagedPointerGet (operand * left,
9987                     operand * result,
9988                     iCode * ic,
9989                     iCode *pi,
9990                     iCode *ifx)
9991 {
9992   asmop *aop = NULL;
9993   regs *preg = NULL;
9994   char *rname;
9995   sym_link *rtype, *retype;
9996
9997   D (emitcode (";", "genPagedPointerGet"));
9998
9999   rtype = operandType (result);
10000   retype = getSpec (rtype);
10001
10002   aopOp (left, ic, FALSE);
10003
10004   /* if the value is already in a pointer register
10005      then don't need anything more */
10006   if (!AOP_INPREG (AOP (left)))
10007     {
10008       /* otherwise get a free pointer register */
10009       aop = newAsmop (0);
10010       preg = getFreePtr (ic, &aop, FALSE);
10011       emitcode ("mov", "%s,%s",
10012                 preg->name,
10013                 aopGet (left, 0, FALSE, TRUE));
10014       rname = preg->name;
10015     }
10016   else
10017     rname = aopGet (left, 0, FALSE, FALSE);
10018
10019   aopOp (result, ic, FALSE);
10020
10021   /* if bitfield then unpack the bits */
10022   if (IS_BITFIELD (retype))
10023     genUnpackBits (result, rname, PPOINTER, ifx);
10024   else
10025     {
10026       /* we have can just get the values */
10027       int size = AOP_SIZE (result);
10028       int offset = 0;
10029
10030       while (size--)
10031         {
10032
10033           emitcode ("movx", "a,@%s", rname);
10034           if (!ifx)
10035             aopPut (result, "a", offset);
10036
10037           offset++;
10038
10039           if (size || pi)
10040             emitcode ("inc", "%s", rname);
10041         }
10042     }
10043
10044   /* now some housekeeping stuff */
10045   if (aop) /* we had to allocate for this iCode */
10046     {
10047       if (pi)
10048         aopPut (left, rname, 0);
10049       freeAsmop (NULL, aop, ic, TRUE);
10050     }
10051   else
10052     {
10053       /* we did not allocate which means left
10054          already in a pointer register, then
10055          if size > 0 && this could be used again
10056          we have to point it back to where it
10057          belongs */
10058       if ((AOP_SIZE (result) > 1 &&
10059            !OP_SYMBOL (left)->remat &&
10060            (OP_SYMBOL (left)->liveTo > ic->seq ||
10061             ic->depth)) &&
10062           !pi)
10063         {
10064           int size = AOP_SIZE (result) - 1;
10065           while (size--)
10066             emitcode ("dec", "%s", rname);
10067         }
10068     }
10069
10070   if (ifx && !ifx->generated)
10071     {
10072       genIfxJump (ifx, "a", left, NULL, result);
10073     }
10074
10075   /* done */
10076   freeAsmop (result, NULL, ic, TRUE);
10077   freeAsmop (left, NULL, ic, TRUE);
10078   if (pi) pi->generated = 1;
10079 }
10080
10081 /*--------------------------------------------------------------------*/
10082 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10083 /*--------------------------------------------------------------------*/
10084 static void
10085 loadDptrFromOperand (operand *op, bool loadBToo)
10086 {
10087   if (AOP_TYPE (op) != AOP_STR)
10088     {
10089       /* if this is rematerializable */
10090       if (AOP_TYPE (op) == AOP_IMMD)
10091         {
10092           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10093           if (loadBToo)
10094             {
10095               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10096                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10097               else
10098                 {
10099                   wassertl(FALSE, "need pointerCode");
10100                   emitcode ("", "; mov b,???");
10101                   /* genPointerGet and genPointerSet originally did different
10102                   ** things for this case. Both seem wrong.
10103                   ** from genPointerGet:
10104                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10105                   ** from genPointerSet:
10106                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10107                   */
10108                 }
10109             }
10110         }
10111       else if (AOP_TYPE (op) == AOP_DPTR)
10112         {
10113           if (loadBToo)
10114             {
10115               MOVA (aopGet (op, 0, FALSE, FALSE));
10116               emitcode ("push", "acc");
10117               MOVA (aopGet (op, 1, FALSE, FALSE));
10118               emitcode ("push", "acc");
10119               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10120               emitcode ("pop", "dph");
10121               emitcode ("pop", "dpl");
10122             }
10123           else
10124             {
10125               MOVA (aopGet (op, 0, FALSE, FALSE));
10126               emitcode ("push", "acc");
10127               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10128               emitcode ("pop", "dpl");
10129             }
10130         }
10131       else
10132         {                       /* we need to get it byte by byte */
10133           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10134           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10135           if (loadBToo)
10136             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10137         }
10138     }
10139 }
10140
10141 /*-----------------------------------------------------------------*/
10142 /* genFarPointerGet - get value from far space                     */
10143 /*-----------------------------------------------------------------*/
10144 static void
10145 genFarPointerGet (operand * left,
10146                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10147 {
10148   int size, offset;
10149   sym_link *retype = getSpec (operandType (result));
10150
10151   D (emitcode (";", "genFarPointerGet"));
10152
10153   aopOp (left, ic, FALSE);
10154   loadDptrFromOperand (left, FALSE);
10155
10156   /* so dptr now contains the address */
10157   aopOp (result, ic, FALSE);
10158
10159   /* if bit then unpack */
10160   if (IS_BITFIELD (retype))
10161     genUnpackBits (result, "dptr", FPOINTER, ifx);
10162   else
10163     {
10164       size = AOP_SIZE (result);
10165       offset = 0;
10166
10167       while (size--)
10168         {
10169           emitcode ("movx", "a,@dptr");
10170           if (!ifx)
10171             aopPut (result, "a", offset++);
10172           if (size || pi)
10173             emitcode ("inc", "dptr");
10174         }
10175     }
10176
10177   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10178     {
10179       aopPut (left, "dpl", 0);
10180       aopPut (left, "dph", 1);
10181       pi->generated = 1;
10182     }
10183
10184   if (ifx && !ifx->generated)
10185     {
10186       genIfxJump (ifx, "a", left, NULL, result);
10187     }
10188
10189   freeAsmop (result, NULL, ic, TRUE);
10190   freeAsmop (left, NULL, ic, TRUE);
10191 }
10192
10193 /*-----------------------------------------------------------------*/
10194 /* genCodePointerGet - get value from code space                   */
10195 /*-----------------------------------------------------------------*/
10196 static void
10197 genCodePointerGet (operand * left,
10198                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10199 {
10200   int size, offset;
10201   sym_link *retype = getSpec (operandType (result));
10202
10203   D (emitcode (";", "genCodePointerGet"));
10204
10205   aopOp (left, ic, FALSE);
10206   loadDptrFromOperand (left, FALSE);
10207
10208   /* so dptr now contains the address */
10209   aopOp (result, ic, FALSE);
10210
10211   /* if bit then unpack */
10212   if (IS_BITFIELD (retype))
10213     genUnpackBits (result, "dptr", CPOINTER, ifx);
10214   else
10215     {
10216       size = AOP_SIZE (result);
10217       offset = 0;
10218
10219       while (size--)
10220         {
10221           emitcode ("clr", "a");
10222           emitcode ("movc", "a,@a+dptr");
10223           if (!ifx)
10224             aopPut (result, "a", offset++);
10225           if (size || pi)
10226             emitcode ("inc", "dptr");
10227         }
10228     }
10229
10230   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10231     {
10232       aopPut (left, "dpl", 0);
10233       aopPut (left, "dph", 1);
10234       pi->generated = 1;
10235     }
10236
10237   if (ifx && !ifx->generated)
10238     {
10239       genIfxJump (ifx, "a", left, NULL, result);
10240     }
10241
10242   freeAsmop (result, NULL, ic, TRUE);
10243   freeAsmop (left, NULL, ic, TRUE);
10244 }
10245
10246 /*-----------------------------------------------------------------*/
10247 /* genGenPointerGet - get value from generic pointer space         */
10248 /*-----------------------------------------------------------------*/
10249 static void
10250 genGenPointerGet (operand * left,
10251                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10252 {
10253   int size, offset;
10254   sym_link *retype = getSpec (operandType (result));
10255
10256   D (emitcode (";", "genGenPointerGet"));
10257
10258   aopOp (left, ic, FALSE);
10259   loadDptrFromOperand (left, TRUE);
10260
10261   /* so dptr now contains the address */
10262   aopOp (result, ic, FALSE);
10263
10264   /* if bit then unpack */
10265   if (IS_BITFIELD (retype))
10266     {
10267       genUnpackBits (result, "dptr", GPOINTER, ifx);
10268     }
10269   else
10270     {
10271       size = AOP_SIZE (result);
10272       offset = 0;
10273
10274       while (size--)
10275         {
10276           emitcode ("lcall", "__gptrget");
10277           if (!ifx)
10278             aopPut (result, "a", offset++);
10279           if (size || pi)
10280             emitcode ("inc", "dptr");
10281         }
10282     }
10283
10284   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10285     {
10286       aopPut (left, "dpl", 0);
10287       aopPut (left, "dph", 1);
10288       pi->generated = 1;
10289     }
10290
10291   if (ifx && !ifx->generated)
10292     {
10293       genIfxJump (ifx, "a", left, NULL, result);
10294     }
10295
10296   freeAsmop (result, NULL, ic, TRUE);
10297   freeAsmop (left, NULL, ic, TRUE);
10298 }
10299
10300 /*-----------------------------------------------------------------*/
10301 /* genPointerGet - generate code for pointer get                   */
10302 /*-----------------------------------------------------------------*/
10303 static void
10304 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10305 {
10306   operand *left, *result;
10307   sym_link *type, *etype;
10308   int p_type;
10309
10310   D (emitcode (";", "genPointerGet"));
10311
10312   left = IC_LEFT (ic);
10313   result = IC_RESULT (ic);
10314
10315   if (getSize (operandType (result))>1)
10316     ifx = NULL;
10317
10318   /* depending on the type of pointer we need to
10319      move it to the correct pointer register */
10320   type = operandType (left);
10321   etype = getSpec (type);
10322   /* if left is of type of pointer then it is simple */
10323   if (IS_PTR (type) && !IS_FUNC (type->next))
10324     p_type = DCL_TYPE (type);
10325   else
10326     {
10327       /* we have to go by the storage class */
10328       p_type = PTR_TYPE (SPEC_OCLS (etype));
10329     }
10330
10331   /* special case when cast remat */
10332   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10333       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10334     {
10335       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10336       type = operandType (left);
10337       p_type = DCL_TYPE (type);
10338     }
10339   /* now that we have the pointer type we assign
10340      the pointer values */
10341   switch (p_type)
10342     {
10343
10344     case POINTER:
10345     case IPOINTER:
10346       genNearPointerGet (left, result, ic, pi, ifx);
10347       break;
10348
10349     case PPOINTER:
10350       genPagedPointerGet (left, result, ic, pi, ifx);
10351       break;
10352
10353     case FPOINTER:
10354       genFarPointerGet (left, result, ic, pi, ifx);
10355       break;
10356
10357     case CPOINTER:
10358       genCodePointerGet (left, result, ic, pi, ifx);
10359       break;
10360
10361     case GPOINTER:
10362       genGenPointerGet (left, result, ic, pi, ifx);
10363       break;
10364     }
10365 }
10366
10367
10368 /*-----------------------------------------------------------------*/
10369 /* genPackBits - generates code for packed bit storage             */
10370 /*-----------------------------------------------------------------*/
10371 static void
10372 genPackBits (sym_link * etype,
10373              operand * right,
10374              char *rname, int p_type)
10375 {
10376   int offset = 0;       /* source byte offset */
10377   int rlen = 0;         /* remaining bitfield length */
10378   int blen;             /* bitfield length */
10379   int bstr;             /* bitfield starting bit within byte */
10380   int litval;           /* source literal value (if AOP_LIT) */
10381   unsigned char mask;   /* bitmask within current byte */
10382
10383   D(emitcode (";     genPackBits",""));
10384
10385   blen = SPEC_BLEN (etype);
10386   bstr = SPEC_BSTR (etype);
10387
10388   /* If the bitfield length is less than a byte */
10389   if (blen < 8)
10390     {
10391       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10392               (unsigned char) (0xFF >> (8 - bstr)));
10393
10394       if (AOP_TYPE (right) == AOP_LIT)
10395         {
10396           /* Case with a bitfield length <8 and literal source
10397           */
10398           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10399           litval <<= bstr;
10400           litval &= (~mask) & 0xff;
10401           emitPtrByteGet (rname, p_type, FALSE);
10402           if ((mask|litval)!=0xff)
10403             emitcode ("anl","a,#0x%02x", mask);
10404           if (litval)
10405             emitcode ("orl","a,#0x%02x", litval);
10406         }
10407       else
10408         {
10409           if ((blen==1) && (p_type!=GPOINTER))
10410             {
10411               /* Case with a bitfield length == 1 and no generic pointer
10412               */
10413               if (AOP_TYPE (right) == AOP_CRY)
10414                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10415               else
10416                 {
10417                   MOVA (aopGet (right, 0, FALSE, FALSE));
10418                   emitcode ("rrc","a");
10419                 }
10420               emitPtrByteGet (rname, p_type, FALSE);
10421               emitcode ("mov","acc.%d,c",bstr);
10422             }
10423           else
10424             {
10425               bool pushedB;
10426               /* Case with a bitfield length < 8 and arbitrary source
10427               */
10428               MOVA (aopGet (right, 0, FALSE, FALSE));
10429               /* shift and mask source value */
10430               AccLsh (bstr);
10431               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10432
10433               pushedB = pushB ();
10434               /* transfer A to B and get next byte */
10435               emitPtrByteGet (rname, p_type, TRUE);
10436
10437               emitcode ("anl", "a,#0x%02x", mask);
10438               emitcode ("orl", "a,b");
10439               if (p_type == GPOINTER)
10440                 emitcode ("pop", "b");
10441
10442               popB (pushedB);
10443            }
10444         }
10445
10446       emitPtrByteSet (rname, p_type, "a");
10447       return;
10448     }
10449
10450   /* Bit length is greater than 7 bits. In this case, copy  */
10451   /* all except the partial byte at the end                 */
10452   for (rlen=blen;rlen>=8;rlen-=8)
10453     {
10454       emitPtrByteSet (rname, p_type,
10455                       aopGet (right, offset++, FALSE, TRUE) );
10456       if (rlen>8)
10457         emitcode ("inc", "%s", rname);
10458     }
10459
10460   /* If there was a partial byte at the end */
10461   if (rlen)
10462     {
10463       mask = (((unsigned char) -1 << rlen) & 0xff);
10464
10465       if (AOP_TYPE (right) == AOP_LIT)
10466         {
10467           /* Case with partial byte and literal source
10468           */
10469           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10470           litval >>= (blen-rlen);
10471           litval &= (~mask) & 0xff;
10472           emitPtrByteGet (rname, p_type, FALSE);
10473           if ((mask|litval)!=0xff)
10474             emitcode ("anl","a,#0x%02x", mask);
10475           if (litval)
10476             emitcode ("orl","a,#0x%02x", litval);
10477         }
10478       else
10479         {
10480           bool pushedB;
10481           /* Case with partial byte and arbitrary source
10482           */
10483           MOVA (aopGet (right, offset++, FALSE, FALSE));
10484           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10485
10486           pushedB = pushB ();
10487           /* transfer A to B and get next byte */
10488           emitPtrByteGet (rname, p_type, TRUE);
10489
10490           emitcode ("anl", "a,#0x%02x", mask);
10491           emitcode ("orl", "a,b");
10492           if (p_type == GPOINTER)
10493             emitcode ("pop", "b");
10494
10495           popB (pushedB);
10496         }
10497       emitPtrByteSet (rname, p_type, "a");
10498     }
10499 }
10500
10501
10502 /*-----------------------------------------------------------------*/
10503 /* genDataPointerSet - remat pointer to data space                 */
10504 /*-----------------------------------------------------------------*/
10505 static void
10506 genDataPointerSet (operand * right,
10507                    operand * result,
10508                    iCode * ic)
10509 {
10510   int size, offset = 0;
10511   char *l, buffer[256];
10512
10513   D (emitcode (";", "genDataPointerSet"));
10514
10515   aopOp (right, ic, FALSE);
10516
10517   l = aopGet (result, 0, FALSE, TRUE);
10518   l++; //remove #
10519   size = AOP_SIZE (right);
10520   while (size--)
10521     {
10522       if (offset)
10523         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10524       else
10525         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10526       emitcode ("mov", "%s,%s", buffer,
10527                 aopGet (right, offset++, FALSE, FALSE));
10528     }
10529
10530   freeAsmop (result, NULL, ic, TRUE);
10531   freeAsmop (right, NULL, ic, TRUE);
10532 }
10533
10534 /*-----------------------------------------------------------------*/
10535 /* genNearPointerSet - emitcode for near pointer put                */
10536 /*-----------------------------------------------------------------*/
10537 static void
10538 genNearPointerSet (operand * right,
10539                    operand * result,
10540                    iCode * ic,
10541                    iCode * pi)
10542 {
10543   asmop *aop = NULL;
10544   regs *preg = NULL;
10545   char *rname, *l;
10546   sym_link *retype, *letype;
10547   sym_link *ptype = operandType (result);
10548
10549   D (emitcode (";", "genNearPointerSet"));
10550
10551   retype = getSpec (operandType (right));
10552   letype = getSpec (ptype);
10553
10554   aopOp (result, ic, FALSE);
10555
10556   /* if the result is rematerializable &
10557      in data space & not a bit variable */
10558   if (AOP_TYPE (result) == AOP_IMMD &&
10559       DCL_TYPE (ptype) == POINTER &&
10560       !IS_BITVAR (retype) &&
10561       !IS_BITVAR (letype))
10562     {
10563       genDataPointerSet (right, result, ic);
10564       return;
10565     }
10566
10567   /* if the value is already in a pointer register
10568      then don't need anything more */
10569   if (!AOP_INPREG (AOP (result)))
10570     {
10571         if (
10572             //AOP_TYPE (result) == AOP_STK
10573             IS_AOP_PREG(result)
10574             )
10575         {
10576             // Aha, it is a pointer, just in disguise.
10577             rname = aopGet (result, 0, FALSE, FALSE);
10578             if (*rname != '@')
10579             {
10580                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10581                         __FILE__, __LINE__);
10582             }
10583             else
10584             {
10585                 // Expected case.
10586                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10587                 rname++;  // skip the '@'.
10588             }
10589         }
10590         else
10591         {
10592             /* otherwise get a free pointer register */
10593             aop = newAsmop (0);
10594             preg = getFreePtr (ic, &aop, FALSE);
10595             emitcode ("mov", "%s,%s",
10596                       preg->name,
10597                       aopGet (result, 0, FALSE, TRUE));
10598             rname = preg->name;
10599         }
10600     }
10601     else
10602     {
10603         rname = aopGet (result, 0, FALSE, FALSE);
10604     }
10605
10606   aopOp (right, ic, FALSE);
10607
10608   /* if bitfield then unpack the bits */
10609   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10610     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10611   else
10612     {
10613       /* we can just get the values */
10614       int size = AOP_SIZE (right);
10615       int offset = 0;
10616
10617       while (size--)
10618         {
10619           l = aopGet (right, offset, FALSE, TRUE);
10620           if ((*l == '@') || (strcmp (l, "acc") == 0))
10621             {
10622               MOVA (l);
10623               emitcode ("mov", "@%s,a", rname);
10624             }
10625           else
10626             emitcode ("mov", "@%s,%s", rname, l);
10627           if (size || pi)
10628             emitcode ("inc", "%s", rname);
10629           offset++;
10630         }
10631     }
10632
10633   /* now some housekeeping stuff */
10634   if (aop) /* we had to allocate for this iCode */
10635     {
10636       if (pi)
10637         aopPut (result, rname, 0);
10638       freeAsmop (NULL, aop, ic, TRUE);
10639     }
10640   else
10641     {
10642       /* we did not allocate which means left
10643          already in a pointer register, then
10644          if size > 0 && this could be used again
10645          we have to point it back to where it
10646          belongs */
10647       if ((AOP_SIZE (right) > 1 &&
10648            !OP_SYMBOL (result)->remat &&
10649            (OP_SYMBOL (result)->liveTo > ic->seq ||
10650             ic->depth)) &&
10651           !pi)
10652         {
10653           int size = AOP_SIZE (right) - 1;
10654           while (size--)
10655             emitcode ("dec", "%s", rname);
10656         }
10657     }
10658
10659   /* done */
10660   if (pi) pi->generated = 1;
10661   freeAsmop (result, NULL, ic, TRUE);
10662   freeAsmop (right, NULL, ic, TRUE);
10663 }
10664
10665 /*-----------------------------------------------------------------*/
10666 /* genPagedPointerSet - emitcode for Paged pointer put             */
10667 /*-----------------------------------------------------------------*/
10668 static void
10669 genPagedPointerSet (operand * right,
10670                     operand * result,
10671                     iCode * ic,
10672                     iCode * pi)
10673 {
10674   asmop *aop = NULL;
10675   regs *preg = NULL;
10676   char *rname, *l;
10677   sym_link *retype, *letype;
10678
10679   D (emitcode (";", "genPagedPointerSet"));
10680
10681   retype = getSpec (operandType (right));
10682   letype = getSpec (operandType (result));
10683
10684   aopOp (result, ic, FALSE);
10685
10686   /* if the value is already in a pointer register
10687      then don't need anything more */
10688   if (!AOP_INPREG (AOP (result)))
10689     {
10690       /* otherwise get a free pointer register */
10691       aop = newAsmop (0);
10692       preg = getFreePtr (ic, &aop, FALSE);
10693       emitcode ("mov", "%s,%s",
10694                 preg->name,
10695                 aopGet (result, 0, FALSE, TRUE));
10696       rname = preg->name;
10697     }
10698   else
10699     rname = aopGet (result, 0, FALSE, FALSE);
10700
10701   aopOp (right, ic, FALSE);
10702
10703   /* if bitfield then unpack the bits */
10704   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10705     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10706   else
10707     {
10708       /* we have can just get the values */
10709       int size = AOP_SIZE (right);
10710       int offset = 0;
10711
10712       while (size--)
10713         {
10714           l = aopGet (right, offset, FALSE, TRUE);
10715           MOVA (l);
10716           emitcode ("movx", "@%s,a", rname);
10717
10718           if (size || pi)
10719             emitcode ("inc", "%s", rname);
10720
10721           offset++;
10722         }
10723     }
10724
10725   /* now some housekeeping stuff */
10726   if (aop) /* we had to allocate for this iCode */
10727     {
10728       if (pi)
10729         aopPut (result, rname, 0);
10730       freeAsmop (NULL, aop, ic, TRUE);
10731     }
10732   else
10733     {
10734       /* we did not allocate which means left
10735          already in a pointer register, then
10736          if size > 0 && this could be used again
10737          we have to point it back to where it
10738          belongs */
10739       if (AOP_SIZE (right) > 1 &&
10740           !OP_SYMBOL (result)->remat &&
10741           (OP_SYMBOL (result)->liveTo > ic->seq ||
10742            ic->depth))
10743         {
10744           int size = AOP_SIZE (right) - 1;
10745           while (size--)
10746             emitcode ("dec", "%s", rname);
10747         }
10748     }
10749
10750   /* done */
10751   if (pi) pi->generated = 1;
10752   freeAsmop (result, NULL, ic, TRUE);
10753   freeAsmop (right, NULL, ic, TRUE);
10754 }
10755
10756 /*-----------------------------------------------------------------*/
10757 /* genFarPointerSet - set value from far space                     */
10758 /*-----------------------------------------------------------------*/
10759 static void
10760 genFarPointerSet (operand * right,
10761                   operand * result, iCode * ic, iCode * pi)
10762 {
10763   int size, offset;
10764   sym_link *retype = getSpec (operandType (right));
10765   sym_link *letype = getSpec (operandType (result));
10766
10767   D(emitcode (";     genFarPointerSet",""));
10768
10769   aopOp (result, ic, FALSE);
10770   loadDptrFromOperand (result, FALSE);
10771
10772   /* so dptr now contains the address */
10773   aopOp (right, ic, FALSE);
10774
10775   /* if bit then unpack */
10776   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10777     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10778   else
10779     {
10780       size = AOP_SIZE (right);
10781       offset = 0;
10782
10783       while (size--)
10784         {
10785           char *l = aopGet (right, offset++, FALSE, FALSE);
10786           MOVA (l);
10787           emitcode ("movx", "@dptr,a");
10788           if (size || pi)
10789             emitcode ("inc", "dptr");
10790         }
10791     }
10792   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10793     aopPut (result, "dpl", 0);
10794     aopPut (result, "dph", 1);
10795     pi->generated=1;
10796   }
10797   freeAsmop (result, NULL, ic, TRUE);
10798   freeAsmop (right, NULL, ic, TRUE);
10799 }
10800
10801 /*-----------------------------------------------------------------*/
10802 /* genGenPointerSet - set value from generic pointer space         */
10803 /*-----------------------------------------------------------------*/
10804 static void
10805 genGenPointerSet (operand * right,
10806                   operand * result, iCode * ic, iCode * pi)
10807 {
10808   int size, offset;
10809   sym_link *retype = getSpec (operandType (right));
10810   sym_link *letype = getSpec (operandType (result));
10811
10812   D (emitcode (";", "genGenPointerSet"));
10813
10814   aopOp (result, ic, FALSE);
10815   loadDptrFromOperand (result, TRUE);
10816
10817   /* so dptr now contains the address */
10818   aopOp (right, ic, FALSE);
10819
10820   /* if bit then unpack */
10821   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10822     {
10823       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10824     }
10825   else
10826     {
10827       size = AOP_SIZE (right);
10828       offset = 0;
10829
10830       while (size--)
10831         {
10832           char *l = aopGet (right, offset++, FALSE, FALSE);
10833           MOVA (l);
10834           emitcode ("lcall", "__gptrput");
10835           if (size || pi)
10836             emitcode ("inc", "dptr");
10837         }
10838     }
10839
10840   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10841     aopPut (result, "dpl", 0);
10842     aopPut (result, "dph", 1);
10843     pi->generated=1;
10844   }
10845   freeAsmop (result, NULL, ic, TRUE);
10846   freeAsmop (right, NULL, ic, TRUE);
10847 }
10848
10849 /*-----------------------------------------------------------------*/
10850 /* genPointerSet - stores the value into a pointer location        */
10851 /*-----------------------------------------------------------------*/
10852 static void
10853 genPointerSet (iCode * ic, iCode *pi)
10854 {
10855   operand *right, *result;
10856   sym_link *type, *etype;
10857   int p_type;
10858
10859   D (emitcode (";", "genPointerSet"));
10860
10861   right = IC_RIGHT (ic);
10862   result = IC_RESULT (ic);
10863
10864   /* depending on the type of pointer we need to
10865      move it to the correct pointer register */
10866   type = operandType (result);
10867   etype = getSpec (type);
10868   /* if left is of type of pointer then it is simple */
10869   if (IS_PTR (type) && !IS_FUNC (type->next))
10870     {
10871       p_type = DCL_TYPE (type);
10872     }
10873   else
10874     {
10875       /* we have to go by the storage class */
10876       p_type = PTR_TYPE (SPEC_OCLS (etype));
10877     }
10878
10879   /* special case when cast remat */
10880   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10881       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10882           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10883           type = operandType (result);
10884           p_type = DCL_TYPE (type);
10885   }
10886
10887   /* now that we have the pointer type we assign
10888      the pointer values */
10889   switch (p_type)
10890     {
10891
10892     case POINTER:
10893     case IPOINTER:
10894       genNearPointerSet (right, result, ic, pi);
10895       break;
10896
10897     case PPOINTER:
10898       genPagedPointerSet (right, result, ic, pi);
10899       break;
10900
10901     case FPOINTER:
10902       genFarPointerSet (right, result, ic, pi);
10903       break;
10904
10905     case GPOINTER:
10906       genGenPointerSet (right, result, ic, pi);
10907       break;
10908
10909     default:
10910       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10911               "genPointerSet: illegal pointer type");
10912     }
10913 }
10914
10915 /*-----------------------------------------------------------------*/
10916 /* genIfx - generate code for Ifx statement                        */
10917 /*-----------------------------------------------------------------*/
10918 static void
10919 genIfx (iCode * ic, iCode * popIc)
10920 {
10921   operand *cond = IC_COND (ic);
10922   int isbit = 0;
10923   char *dup = NULL;
10924
10925   D (emitcode (";", "genIfx"));
10926
10927   aopOp (cond, ic, FALSE);
10928
10929   /* get the value into acc */
10930   if (AOP_TYPE (cond) != AOP_CRY)
10931     {
10932       toBoolean (cond);
10933     }
10934   else
10935     {
10936       isbit = 1;
10937       if (AOP(cond)->aopu.aop_dir)
10938         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10939     }
10940
10941   /* the result is now in the accumulator or a directly addressable bit */
10942   freeAsmop (cond, NULL, ic, TRUE);
10943
10944   /* if there was something to be popped then do it */
10945   if (popIc)
10946     genIpop (popIc);
10947
10948   /* if the condition is a bit variable */
10949   if (isbit && dup)
10950     genIfxJump(ic, dup, NULL, NULL, NULL);
10951   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10952     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10953   else if (isbit && !IS_ITEMP (cond))
10954     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10955   else
10956     genIfxJump (ic, "a", NULL, NULL, NULL);
10957
10958   ic->generated = 1;
10959 }
10960
10961 /*-----------------------------------------------------------------*/
10962 /* genAddrOf - generates code for address of                       */
10963 /*-----------------------------------------------------------------*/
10964 static void
10965 genAddrOf (iCode * ic)
10966 {
10967   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10968   int size, offset;
10969
10970   D (emitcode (";", "genAddrOf"));
10971
10972   aopOp (IC_RESULT (ic), ic, FALSE);
10973
10974   /* if the operand is on the stack then we
10975      need to get the stack offset of this
10976      variable */
10977   if (sym->onStack)
10978     {
10979       /* if it has an offset then we need to compute it */
10980       if (sym->stack)
10981         {
10982           int stack_offset = ((sym->stack < 0) ?
10983                               ((char) (sym->stack - _G.nRegsSaved)) :
10984                               ((char) sym->stack)) & 0xff;
10985           if ((abs(stack_offset) == 1) &&
10986               !AOP_NEEDSACC(IC_RESULT (ic)) &&
10987               !isOperandVolatile (IC_RESULT (ic), FALSE))
10988             {
10989               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10990               if (stack_offset > 0)
10991                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10992               else
10993                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10994             }
10995           else
10996             {
10997               emitcode ("mov", "a,%s", SYM_BP (sym));
10998               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
10999               aopPut (IC_RESULT (ic), "a", 0);
11000             }
11001         }
11002       else
11003         {
11004           /* we can just move _bp */
11005           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11006         }
11007       /* fill the result with zero */
11008       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11009
11010       offset = 1;
11011       while (size--)
11012         {
11013           aopPut (IC_RESULT (ic), zero, offset++);
11014         }
11015       goto release;
11016     }
11017
11018   /* object not on stack then we need the name */
11019   size = AOP_SIZE (IC_RESULT (ic));
11020   offset = 0;
11021
11022   while (size--)
11023     {
11024       char s[SDCC_NAME_MAX];
11025       if (offset)
11026         sprintf (s, "#(%s >> %d)",
11027                  sym->rname,
11028                  offset * 8);
11029       else
11030         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11031       aopPut (IC_RESULT (ic), s, offset++);
11032     }
11033
11034 release:
11035   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11036
11037 }
11038
11039 /*-----------------------------------------------------------------*/
11040 /* genFarFarAssign - assignment when both are in far space         */
11041 /*-----------------------------------------------------------------*/
11042 static void
11043 genFarFarAssign (operand * result, operand * right, iCode * ic)
11044 {
11045   int size = AOP_SIZE (right);
11046   int offset = 0;
11047   char *l;
11048
11049   D (emitcode (";", "genFarFarAssign"));
11050
11051   /* first push the right side on to the stack */
11052   while (size--)
11053     {
11054       l = aopGet (right, offset++, FALSE, FALSE);
11055       MOVA (l);
11056       emitcode ("push", "acc");
11057     }
11058
11059   freeAsmop (right, NULL, ic, FALSE);
11060   /* now assign DPTR to result */
11061   aopOp (result, ic, FALSE);
11062   size = AOP_SIZE (result);
11063   while (size--)
11064     {
11065       emitcode ("pop", "acc");
11066       aopPut (result, "a", --offset);
11067     }
11068   freeAsmop (result, NULL, ic, FALSE);
11069 }
11070
11071 /*-----------------------------------------------------------------*/
11072 /* genAssign - generate code for assignment                        */
11073 /*-----------------------------------------------------------------*/
11074 static void
11075 genAssign (iCode * ic)
11076 {
11077   operand *result, *right;
11078   int size, offset;
11079   unsigned long lit = 0L;
11080
11081   D (emitcode (";", "genAssign"));
11082
11083   result = IC_RESULT (ic);
11084   right = IC_RIGHT (ic);
11085
11086   /* if they are the same */
11087   if (operandsEqu (result, right) &&
11088       !isOperandVolatile (result, FALSE) &&
11089       !isOperandVolatile (right, FALSE))
11090     return;
11091
11092   aopOp (right, ic, FALSE);
11093
11094   /* special case both in far space */
11095   if (AOP_TYPE (right) == AOP_DPTR &&
11096       IS_TRUE_SYMOP (result) &&
11097       isOperandInFarSpace (result))
11098     {
11099       genFarFarAssign (result, right, ic);
11100       return;
11101     }
11102
11103   aopOp (result, ic, TRUE);
11104
11105   /* if they are the same registers */
11106   if (sameRegs (AOP (right), AOP (result)) &&
11107       !isOperandVolatile (result, FALSE) &&
11108       !isOperandVolatile (right, FALSE))
11109     goto release;
11110
11111   /* if the result is a bit */
11112   if (AOP_TYPE (result) == AOP_CRY)
11113     {
11114       assignBit (result, right);
11115       goto release;
11116     }
11117
11118   /* bit variables done */
11119   /* general case */
11120   size = AOP_SIZE (result);
11121   offset = 0;
11122   if (AOP_TYPE (right) == AOP_LIT)
11123     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11124
11125   if ((size > 1) &&
11126       (AOP_TYPE (result) != AOP_REG) &&
11127       (AOP_TYPE (right) == AOP_LIT) &&
11128       !IS_FLOAT (operandType (right)) &&
11129       (lit < 256L))
11130     {
11131       while ((size) && (lit))
11132         {
11133           aopPut (result,
11134                   aopGet (right, offset, FALSE, FALSE),
11135                   offset);
11136           lit >>= 8;
11137           offset++;
11138           size--;
11139         }
11140       /* And now fill the rest with zeros. */
11141       if (size)
11142         {
11143           emitcode ("clr", "a");
11144         }
11145       while (size--)
11146         {
11147           aopPut (result, "a", offset);
11148           offset++;
11149         }
11150     }
11151   else
11152     {
11153       while (size--)
11154         {
11155           aopPut (result,
11156                   aopGet (right, offset, FALSE, FALSE),
11157                   offset);
11158           offset++;
11159         }
11160     }
11161
11162 release:
11163   freeAsmop (result, NULL, ic, TRUE);
11164   freeAsmop (right, NULL, ic, TRUE);
11165 }
11166
11167 /*-----------------------------------------------------------------*/
11168 /* genJumpTab - generates code for jump table                      */
11169 /*-----------------------------------------------------------------*/
11170 static void
11171 genJumpTab (iCode * ic)
11172 {
11173   symbol *jtab,*jtablo,*jtabhi;
11174   char *l;
11175   unsigned int count;
11176
11177   D (emitcode (";", "genJumpTab"));
11178
11179   count = elementsInSet( IC_JTLABELS (ic) );
11180
11181   if( count <= 16 )
11182     {
11183       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11184          if the switch argument is in a register.
11185          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11186       /* Peephole may not convert ljmp to sjmp or ret
11187          labelIsReturnOnly & labelInRange must check
11188          currPl->ic->op != JUMPTABLE */
11189       aopOp (IC_JTCOND (ic), ic, FALSE);
11190       /* get the condition into accumulator */
11191       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11192       MOVA (l);
11193       /* multiply by three */
11194       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11195         {
11196           emitcode ("mov", "b,#3");
11197           emitcode ("mul", "ab");
11198         }
11199       else
11200         {
11201           emitcode ("add", "a,acc");
11202           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11203         }
11204       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11205
11206       jtab = newiTempLabel (NULL);
11207       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11208       emitcode ("jmp", "@a+dptr");
11209       emitLabel (jtab);
11210       /* now generate the jump labels */
11211       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11212            jtab = setNextItem (IC_JTLABELS (ic)))
11213         emitcode ("ljmp", "%05d$", jtab->key + 100);
11214     }
11215   else
11216     {
11217       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11218          if the switch argument is in a register.
11219          For n>6 this algorithm may be more compact */
11220       jtablo = newiTempLabel (NULL);
11221       jtabhi = newiTempLabel (NULL);
11222
11223       /* get the condition into accumulator.
11224          Using b as temporary storage, if register push/pop is needed */
11225       aopOp (IC_JTCOND (ic), ic, FALSE);
11226       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11227       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11228           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11229         {
11230           // (MB) what if B is in use???
11231           wassertl(!BINUSE, "B was in use");
11232           emitcode ("mov", "b,%s", l);
11233           l = "b";
11234         }
11235       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11236       MOVA (l);
11237       if( count <= 112 )
11238         {
11239           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11240           emitcode ("movc", "a,@a+pc");
11241           emitcode ("push", "acc");
11242
11243           MOVA (l);
11244           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11245           emitcode ("movc", "a,@a+pc");
11246           emitcode ("push", "acc");
11247         }
11248       else
11249         {
11250           /* this scales up to n<=255, but needs two more bytes
11251              and changes dptr */
11252           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11253           emitcode ("movc", "a,@a+dptr");
11254           emitcode ("push", "acc");
11255
11256           MOVA (l);
11257           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11258           emitcode ("movc", "a,@a+dptr");
11259           emitcode ("push", "acc");
11260         }
11261
11262       emitcode ("ret", "");
11263
11264       /* now generate jump table, LSB */
11265       emitLabel (jtablo);
11266       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11267            jtab = setNextItem (IC_JTLABELS (ic)))
11268         emitcode (".db", "%05d$", jtab->key + 100);
11269
11270       /* now generate jump table, MSB */
11271       emitLabel (jtabhi);
11272       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11273            jtab = setNextItem (IC_JTLABELS (ic)))
11274          emitcode (".db", "%05d$>>8", jtab->key + 100);
11275     }
11276 }
11277
11278 /*-----------------------------------------------------------------*/
11279 /* genCast - gen code for casting                                  */
11280 /*-----------------------------------------------------------------*/
11281 static void
11282 genCast (iCode * ic)
11283 {
11284   operand *result = IC_RESULT (ic);
11285   sym_link *ctype = operandType (IC_LEFT (ic));
11286   sym_link *rtype = operandType (IC_RIGHT (ic));
11287   operand *right = IC_RIGHT (ic);
11288   int size, offset;
11289
11290   D (emitcode (";", "genCast"));
11291
11292   /* if they are equivalent then do nothing */
11293   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11294     return;
11295
11296   aopOp (right, ic, FALSE);
11297   aopOp (result, ic, FALSE);
11298
11299   /* if the result is a bit (and not a bitfield) */
11300   if (IS_BIT (OP_SYMBOL (result)->type))
11301     {
11302       assignBit (result, right);
11303       goto release;
11304     }
11305
11306   /* if they are the same size : or less */
11307   if (AOP_SIZE (result) <= AOP_SIZE (right))
11308     {
11309
11310       /* if they are in the same place */
11311       if (sameRegs (AOP (right), AOP (result)))
11312         goto release;
11313
11314       /* if they in different places then copy */
11315       size = AOP_SIZE (result);
11316       offset = 0;
11317       while (size--)
11318         {
11319           aopPut (result,
11320                   aopGet (right, offset, FALSE, FALSE),
11321                   offset);
11322           offset++;
11323         }
11324       goto release;
11325     }
11326
11327   /* if the result is of type pointer */
11328   if (IS_PTR (ctype))
11329     {
11330
11331       int p_type;
11332       sym_link *type = operandType (right);
11333       sym_link *etype = getSpec (type);
11334
11335       /* pointer to generic pointer */
11336       if (IS_GENPTR (ctype))
11337         {
11338           if (IS_PTR (type))
11339             {
11340               p_type = DCL_TYPE (type);
11341             }
11342           else
11343             {
11344               if (SPEC_SCLS(etype)==S_REGISTER) {
11345                 // let's assume it is a generic pointer
11346                 p_type=GPOINTER;
11347               } else {
11348                 /* we have to go by the storage class */
11349                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11350               }
11351             }
11352
11353           /* the first two bytes are known */
11354           size = GPTRSIZE - 1;
11355           offset = 0;
11356           while (size--)
11357             {
11358               aopPut (result,
11359                       aopGet (right, offset, FALSE, FALSE),
11360                       offset);
11361               offset++;
11362             }
11363           /* the last byte depending on type */
11364             {
11365                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11366                 char gpValStr[10];
11367
11368                 if (gpVal == -1)
11369                 {
11370                     // pointerTypeToGPByte will have bitched.
11371                     exit(1);
11372                 }
11373
11374                 sprintf(gpValStr, "#0x%x", gpVal);
11375                 aopPut (result, gpValStr, GPTRSIZE - 1);
11376             }
11377           goto release;
11378         }
11379
11380       /* just copy the pointers */
11381       size = AOP_SIZE (result);
11382       offset = 0;
11383       while (size--)
11384         {
11385           aopPut (result,
11386                   aopGet (right, offset, FALSE, FALSE),
11387                   offset);
11388           offset++;
11389         }
11390       goto release;
11391     }
11392
11393   /* so we now know that the size of destination is greater
11394      than the size of the source */
11395   /* we move to result for the size of source */
11396   size = AOP_SIZE (right);
11397   offset = 0;
11398   while (size--)
11399     {
11400       aopPut (result,
11401               aopGet (right, offset, FALSE, FALSE),
11402               offset);
11403       offset++;
11404     }
11405
11406   /* now depending on the sign of the source && destination */
11407   size = AOP_SIZE (result) - AOP_SIZE (right);
11408   /* if unsigned or not an integral type */
11409   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11410     {
11411       while (size--)
11412         aopPut (result, zero, offset++);
11413     }
11414   else
11415     {
11416       /* we need to extend the sign :{ */
11417       char *l = aopGet (right, AOP_SIZE (right) - 1,
11418                         FALSE, FALSE);
11419       MOVA (l);
11420       emitcode ("rlc", "a");
11421       emitcode ("subb", "a,acc");
11422       while (size--)
11423         aopPut (result, "a", offset++);
11424     }
11425
11426   /* we are done hurray !!!! */
11427
11428 release:
11429   freeAsmop (result, NULL, ic, TRUE);
11430   freeAsmop (right, NULL, ic, TRUE);
11431 }
11432
11433 /*-----------------------------------------------------------------*/
11434 /* genDjnz - generate decrement & jump if not zero instrucion      */
11435 /*-----------------------------------------------------------------*/
11436 static int
11437 genDjnz (iCode * ic, iCode * ifx)
11438 {
11439   symbol *lbl, *lbl1;
11440   if (!ifx)
11441     return 0;
11442
11443   /* if the if condition has a false label
11444      then we cannot save */
11445   if (IC_FALSE (ifx))
11446     return 0;
11447
11448   /* if the minus is not of the form a = a - 1 */
11449   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11450       !IS_OP_LITERAL (IC_RIGHT (ic)))
11451     return 0;
11452
11453   if (operandLitValue (IC_RIGHT (ic)) != 1)
11454     return 0;
11455
11456   /* if the size of this greater than one then no
11457      saving */
11458   if (getSize (operandType (IC_RESULT (ic))) > 1)
11459     return 0;
11460
11461   /* otherwise we can save BIG */
11462
11463   D (emitcode (";", "genDjnz"));
11464
11465   lbl = newiTempLabel (NULL);
11466   lbl1 = newiTempLabel (NULL);
11467
11468   aopOp (IC_RESULT (ic), ic, FALSE);
11469
11470   if (AOP_NEEDSACC(IC_RESULT(ic)))
11471   {
11472       /* If the result is accessed indirectly via
11473        * the accumulator, we must explicitly write
11474        * it back after the decrement.
11475        */
11476       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11477
11478       if (strcmp(rByte, "a"))
11479       {
11480            /* Something is hopelessly wrong */
11481            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11482                    __FILE__, __LINE__);
11483            /* We can just give up; the generated code will be inefficient,
11484             * but what the hey.
11485             */
11486            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11487            return 0;
11488       }
11489       emitcode ("dec", "%s", rByte);
11490       aopPut (IC_RESULT (ic), rByte, 0);
11491       emitcode ("jnz", "%05d$", lbl->key + 100);
11492   }
11493   else if (IS_AOP_PREG (IC_RESULT (ic)))
11494     {
11495       emitcode ("dec", "%s",
11496                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11497       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11498       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11499       ifx->generated = 1;
11500       emitcode ("jnz", "%05d$", lbl->key + 100);
11501     }
11502   else
11503     {
11504       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11505                 lbl->key + 100);
11506     }
11507   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11508   emitLabel (lbl);
11509   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11510   emitLabel (lbl1);
11511
11512   if (!ifx->generated)
11513       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11514   ifx->generated = 1;
11515   return 1;
11516 }
11517
11518 /*-----------------------------------------------------------------*/
11519 /* genReceive - generate code for a receive iCode                  */
11520 /*-----------------------------------------------------------------*/
11521 static void
11522 genReceive (iCode * ic)
11523 {
11524   int size = getSize (operandType (IC_RESULT (ic)));
11525   int offset = 0;
11526
11527   D (emitcode (";", "genReceive"));
11528
11529   if (ic->argreg == 1)
11530     { /* first parameter */
11531       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11532            isOperandInPagedSpace (IC_RESULT (ic))) &&
11533           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11534            IS_TRUE_SYMOP (IC_RESULT (ic))))
11535         {
11536           regs *tempRegs[4];
11537           int receivingA = 0;
11538           int roffset = 0;
11539
11540           for (offset = 0; offset<size; offset++)
11541             if (!strcmp (fReturn[offset], "a"))
11542               receivingA = 1;
11543
11544           if (!receivingA)
11545             {
11546               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11547                 {
11548                   for (offset = size-1; offset>0; offset--)
11549                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11550                   emitcode("mov","a,%s", fReturn[0]);
11551                   _G.accInUse++;
11552                   aopOp (IC_RESULT (ic), ic, FALSE);
11553                   _G.accInUse--;
11554                   aopPut (IC_RESULT (ic), "a", offset);
11555                   for (offset = 1; offset<size; offset++)
11556                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11557                   goto release;
11558                 }
11559             }
11560           else
11561             {
11562               if (getTempRegs(tempRegs, size, ic))
11563                 {
11564                   for (offset = 0; offset<size; offset++)
11565                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11566                   aopOp (IC_RESULT (ic), ic, FALSE);
11567                   for (offset = 0; offset<size; offset++)
11568                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11569                   goto release;
11570                 }
11571             }
11572
11573           offset = fReturnSizeMCS51 - size;
11574           while (size--)
11575             {
11576               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11577                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11578               offset++;
11579             }
11580           aopOp (IC_RESULT (ic), ic, FALSE);
11581           size = AOP_SIZE (IC_RESULT (ic));
11582           offset = 0;
11583           while (size--)
11584             {
11585               emitcode ("pop", "acc");
11586               aopPut (IC_RESULT (ic), "a", offset++);
11587             }
11588         }
11589       else
11590         {
11591           _G.accInUse++;
11592           aopOp (IC_RESULT (ic), ic, FALSE);
11593           _G.accInUse--;
11594           assignResultValue (IC_RESULT (ic), NULL);
11595         }
11596     }
11597   else if (ic->argreg > 12)
11598     { /* bit parameters */
11599       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11600         {
11601           aopOp (IC_RESULT (ic), ic, FALSE);
11602           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11603           outBitC(IC_RESULT (ic));
11604         }
11605     }
11606   else
11607     { /* other parameters */
11608       int rb1off ;
11609       aopOp (IC_RESULT (ic), ic, FALSE);
11610       rb1off = ic->argreg;
11611       while (size--)
11612         {
11613           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11614         }
11615     }
11616
11617 release:
11618   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11619 }
11620
11621 /*-----------------------------------------------------------------*/
11622 /* genDummyRead - generate code for dummy read of volatiles        */
11623 /*-----------------------------------------------------------------*/
11624 static void
11625 genDummyRead (iCode * ic)
11626 {
11627   operand *op;
11628   int size, offset;
11629
11630   D (emitcode(";", "genDummyRead"));
11631
11632   op = IC_RIGHT (ic);
11633   if (op && IS_SYMOP (op))
11634     {
11635       aopOp (op, ic, FALSE);
11636
11637       /* if the result is a bit */
11638       if (AOP_TYPE (op) == AOP_CRY)
11639         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11640       else
11641         {
11642           /* bit variables done */
11643           /* general case */
11644           size = AOP_SIZE (op);
11645           offset = 0;
11646           while (size--)
11647           {
11648             MOVA (aopGet (op, offset, FALSE, FALSE));
11649             offset++;
11650           }
11651         }
11652
11653       freeAsmop (op, NULL, ic, TRUE);
11654     }
11655
11656   op = IC_LEFT (ic);
11657   if (op && IS_SYMOP (op))
11658     {
11659       aopOp (op, ic, FALSE);
11660
11661       /* if the result is a bit */
11662       if (AOP_TYPE (op) == AOP_CRY)
11663         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11664       else
11665         {
11666           /* bit variables done */
11667           /* general case */
11668           size = AOP_SIZE (op);
11669           offset = 0;
11670           while (size--)
11671           {
11672             MOVA (aopGet (op, offset, FALSE, FALSE));
11673             offset++;
11674           }
11675         }
11676
11677       freeAsmop (op, NULL, ic, TRUE);
11678     }
11679 }
11680
11681 /*-----------------------------------------------------------------*/
11682 /* genCritical - generate code for start of a critical sequence    */
11683 /*-----------------------------------------------------------------*/
11684 static void
11685 genCritical (iCode *ic)
11686 {
11687   symbol *tlbl = newiTempLabel (NULL);
11688
11689   D (emitcode(";", "genCritical"));
11690
11691   if (IC_RESULT (ic))
11692     {
11693       aopOp (IC_RESULT (ic), ic, TRUE);
11694       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11695       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11696       aopPut (IC_RESULT (ic), zero, 0);
11697       emitLabel (tlbl);
11698       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11699     }
11700   else
11701     {
11702       emitcode ("setb", "c");
11703       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11704       emitcode ("clr", "c");
11705       emitLabel (tlbl);
11706       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11707     }
11708 }
11709
11710 /*-----------------------------------------------------------------*/
11711 /* genEndCritical - generate code for end of a critical sequence   */
11712 /*-----------------------------------------------------------------*/
11713 static void
11714 genEndCritical (iCode *ic)
11715 {
11716   D(emitcode(";     genEndCritical",""));
11717
11718   if (IC_RIGHT (ic))
11719     {
11720       aopOp (IC_RIGHT (ic), ic, FALSE);
11721       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11722         {
11723           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11724           emitcode ("mov", "ea,c");
11725         }
11726       else
11727         {
11728           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11729             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11730           emitcode ("rrc", "a");
11731           emitcode ("mov", "ea,c");
11732         }
11733       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11734     }
11735   else
11736     {
11737       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11738       emitcode ("mov", "ea,c");
11739     }
11740 }
11741
11742 /*-----------------------------------------------------------------*/
11743 /* gen51Code - generate code for 8051 based controllers            */
11744 /*-----------------------------------------------------------------*/
11745 void
11746 gen51Code (iCode * lic)
11747 {
11748   iCode *ic;
11749   int cln = 0;
11750   /* int cseq = 0; */
11751
11752   _G.currentFunc = NULL;
11753   lineHead = lineCurr = NULL;
11754
11755   /* print the allocation information */
11756   if (allocInfo && currFunc)
11757     printAllocInfo (currFunc, codeOutBuf);
11758   /* if debug information required */
11759   if (options.debug && currFunc)
11760     {
11761       debugFile->writeFunction (currFunc, lic);
11762     }
11763   /* stack pointer name */
11764   if (options.useXstack)
11765     spname = "_spx";
11766   else
11767     spname = "sp";
11768
11769
11770   for (ic = lic; ic; ic = ic->next)
11771     {
11772       _G.current_iCode = ic;
11773
11774       if (ic->lineno && cln != ic->lineno)
11775         {
11776           if (options.debug)
11777             {
11778               debugFile->writeCLine (ic);
11779             }
11780           if (!options.noCcodeInAsm) {
11781             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
11782                       printCLine(ic->filename, ic->lineno));
11783           }
11784           cln = ic->lineno;
11785         }
11786       #if 0
11787       if (ic->seqPoint && ic->seqPoint != cseq)
11788         {
11789           emitcode ("", "; sequence point %d", ic->seqPoint);
11790           cseq = ic->seqPoint;
11791         }
11792       #endif
11793       if (options.iCodeInAsm) {
11794         char regsInUse[80];
11795         int i;
11796         char *iLine;
11797
11798         #if 0
11799         for (i=0; i<8; i++) {
11800           sprintf (&regsInUse[i],
11801                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11802         regsInUse[i]=0;
11803         #else
11804         strcpy (regsInUse, "--------");
11805         for (i=0; i < 8; i++) {
11806           if (bitVectBitValue (ic->rMask, i))
11807             {
11808               int offset = regs8051[i].offset;
11809               regsInUse[offset] = offset + '0'; /* show rMask */
11810             }
11811         #endif
11812         }
11813         iLine = printILine(ic);
11814         emitcode("", "; [%s] ic:%d: %s", regsInUse, ic->seq, printILine(ic));
11815         dbuf_free(iLine);
11816       }
11817       /* if the result is marked as
11818          spilt and rematerializable or code for
11819          this has already been generated then
11820          do nothing */
11821       if (resultRemat (ic) || ic->generated)
11822         continue;
11823
11824       /* depending on the operation */
11825       switch (ic->op)
11826         {
11827         case '!':
11828           genNot (ic);
11829           break;
11830
11831         case '~':
11832           genCpl (ic);
11833           break;
11834
11835         case UNARYMINUS:
11836           genUminus (ic);
11837           break;
11838
11839         case IPUSH:
11840           genIpush (ic);
11841           break;
11842
11843         case IPOP:
11844           /* IPOP happens only when trying to restore a
11845              spilt live range, if there is an ifx statement
11846              following this pop then the if statement might
11847              be using some of the registers being popped which
11848              would destory the contents of the register so
11849              we need to check for this condition and handle it */
11850           if (ic->next &&
11851               ic->next->op == IFX &&
11852               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11853             genIfx (ic->next, ic);
11854           else
11855             genIpop (ic);
11856           break;
11857
11858         case CALL:
11859           genCall (ic);
11860           break;
11861
11862         case PCALL:
11863           genPcall (ic);
11864           break;
11865
11866         case FUNCTION:
11867           genFunction (ic);
11868           break;
11869
11870         case ENDFUNCTION:
11871           genEndFunction (ic);
11872           break;
11873
11874         case RETURN:
11875           genRet (ic);
11876           break;
11877
11878         case LABEL:
11879           genLabel (ic);
11880           break;
11881
11882         case GOTO:
11883           genGoto (ic);
11884           break;
11885
11886         case '+':
11887           genPlus (ic);
11888           break;
11889
11890         case '-':
11891           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11892             genMinus (ic);
11893           break;
11894
11895         case '*':
11896           genMult (ic);
11897           break;
11898
11899         case '/':
11900           genDiv (ic);
11901           break;
11902
11903         case '%':
11904           genMod (ic);
11905           break;
11906
11907         case '>':
11908           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11909           break;
11910
11911         case '<':
11912           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11913           break;
11914
11915         case LE_OP:
11916         case GE_OP:
11917         case NE_OP:
11918
11919           /* note these two are xlated by algebraic equivalence
11920              in decorateType() in SDCCast.c */
11921           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11922                   "got '>=' or '<=' shouldn't have come here");
11923           break;
11924
11925         case EQ_OP:
11926           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11927           break;
11928
11929         case AND_OP:
11930           genAndOp (ic);
11931           break;
11932
11933         case OR_OP:
11934           genOrOp (ic);
11935           break;
11936
11937         case '^':
11938           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11939           break;
11940
11941         case '|':
11942           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11943           break;
11944
11945         case BITWISEAND:
11946           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11947           break;
11948
11949         case INLINEASM:
11950           genInline (ic);
11951           break;
11952
11953         case RRC:
11954           genRRC (ic);
11955           break;
11956
11957         case RLC:
11958           genRLC (ic);
11959           break;
11960
11961         case GETHBIT:
11962           genGetHbit (ic);
11963           break;
11964
11965         case GETABIT:
11966           genGetAbit (ic);
11967           break;
11968
11969         case GETBYTE:
11970           genGetByte (ic);
11971           break;
11972
11973         case GETWORD:
11974           genGetWord (ic);
11975           break;
11976
11977         case LEFT_OP:
11978           genLeftShift (ic);
11979           break;
11980
11981         case RIGHT_OP:
11982           genRightShift (ic);
11983           break;
11984
11985         case GET_VALUE_AT_ADDRESS:
11986           genPointerGet (ic,
11987                          hasInc (IC_LEFT (ic), ic,
11988                                  getSize (operandType (IC_RESULT (ic)))),
11989                          ifxForOp (IC_RESULT (ic), ic) );
11990           break;
11991
11992         case '=':
11993           if (POINTER_SET (ic))
11994             genPointerSet (ic,
11995                            hasInc (IC_RESULT (ic), ic,
11996                                    getSize (operandType (IC_RIGHT (ic)))));
11997           else
11998             genAssign (ic);
11999           break;
12000
12001         case IFX:
12002           genIfx (ic, NULL);
12003           break;
12004
12005         case ADDRESS_OF:
12006           genAddrOf (ic);
12007           break;
12008
12009         case JUMPTABLE:
12010           genJumpTab (ic);
12011           break;
12012
12013         case CAST:
12014           genCast (ic);
12015           break;
12016
12017         case RECEIVE:
12018           genReceive (ic);
12019           break;
12020
12021         case SEND:
12022           addSet (&_G.sendSet, ic);
12023           break;
12024
12025         case DUMMY_READ_VOLATILE:
12026           genDummyRead (ic);
12027           break;
12028
12029         case CRITICAL:
12030           genCritical (ic);
12031           break;
12032
12033         case ENDCRITICAL:
12034           genEndCritical (ic);
12035           break;
12036
12037         case SWAP:
12038           genSwap (ic);
12039           break;
12040
12041         default:
12042           ic = ic;
12043         }
12044     }
12045
12046   _G.current_iCode = NULL;
12047
12048   /* now we are ready to call the
12049      peep hole optimizer */
12050   if (!options.nopeep)
12051     peepHole (&lineHead);
12052
12053   /* now do the actual printing */
12054   printLine (lineHead, codeOutBuf);
12055   return;
12056 }