957d58dca8dcff26bb363f35348308b930bc40fd
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 #define D(x) do if (options.verboseAsm) {x;} while(0)
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include "SDCCglobl.h"
38 #include "newalloc.h"
39
40 #include "common.h"
41 #include "SDCCpeeph.h"
42 #include "ralloc.h"
43 #include "rtrack.h"
44 #include "gen.h"
45 #include "dbuf_string.h"
46
47 char *aopLiteral (value * val, int offset);
48 char *aopLiteralLong (value * val, int offset, int size);
49 extern int allocInfo;
50
51 /* this is the down and dirty file with all kinds of
52    kludgy & hacky stuff. This is what it is all about
53    CODE GENERATION for a specific MCU . some of the
54    routines may be reusable, will have to see */
55
56 static char *zero = "#0x00";
57 static char *one = "#0x01";
58 static char *spname;
59
60 char *fReturn8051[] =
61 {"dpl", "dph", "b", "a"};
62 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
63 char **fReturn = fReturn8051;
64 static char *accUse[] =
65 {"a", "b"};
66
67 static unsigned short rbank = -1;
68
69 #define REG_WITH_INDEX   mcs51_regWithIdx
70
71 #define AOP(op) op->aop
72 #define AOP_TYPE(op) AOP(op)->type
73 #define AOP_SIZE(op) AOP(op)->size
74 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
75                         AOP_TYPE(x) == AOP_R0))
76
77 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
78                          AOP_TYPE(x) == AOP_DPTR || \
79                          AOP(x)->paged))
80
81 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
82                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
83                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
84
85 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
86
87 #define R0INB   _G.bu.bs.r0InB
88 #define R1INB   _G.bu.bs.r1InB
89 #define OPINB   _G.bu.bs.OpInB
90 #define BINUSE  _G.bu.BInUse
91
92 static struct
93   {
94     short r0Pushed;
95     short r1Pushed;
96     union
97       {
98         struct
99           {
100             short r0InB : 2;//2 so we can see it overflow
101             short r1InB : 2;//2 so we can see it overflow
102             short OpInB : 2;//2 so we can see it overflow
103           } bs;
104         short BInUse;
105       } bu;
106     short accInUse;
107     short inLine;
108     short debugLine;
109     short nRegsSaved;
110     set *sendSet;
111     iCode *current_iCode;
112     symbol *currentFunc;
113   }
114 _G;
115
116 static char *rb1regs[] = {
117     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
118     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
119 };
120
121 extern struct dbuf_s *codeOutBuf;
122
123 #define RESULTONSTACK(x) \
124                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
125                          IC_RESULT(x)->aop->type == AOP_STK )
126
127 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
128 #define MOVB(x)  movb(x)
129
130 #define CLRC     emitcode("clr","c")
131 #define SETC     emitcode("setb","c")
132
133 static lineNode *lineHead = NULL;
134 static lineNode *lineCurr = NULL;
135
136 static unsigned char SLMask[] =
137 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
138  0xE0, 0xC0, 0x80, 0x00};
139 static unsigned char SRMask[] =
140 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
141  0x07, 0x03, 0x01, 0x00};
142
143 #define LSB     0
144 #define MSB16   1
145 #define MSB24   2
146 #define MSB32   3
147
148 /*-----------------------------------------------------------------*/
149 /* emitcode - writes the code into a file : for now it is simple    */
150 /*-----------------------------------------------------------------*/
151 void
152 emitcode (const char *inst, const char *fmt,...)
153 {
154   va_list ap;
155   struct dbuf_s dbuf;
156   const char *lbp, *lb;
157
158   dbuf_init (&dbuf, INITIAL_INLINEASM);
159
160   va_start (ap, fmt);
161
162   if (inst && *inst)
163     {
164       dbuf_append_str (&dbuf, inst);
165
166       if (fmt && *fmt)
167         {
168           dbuf_append_char (&dbuf, '\t');
169           dbuf_tvprintf (&dbuf, fmt, ap);
170         }
171     }
172   else
173     {
174       dbuf_tvprintf (&dbuf, fmt, ap);
175     }
176
177   lbp = lb = dbuf_c_str(&dbuf);
178
179   while (isspace ((unsigned char)*lbp))
180     {
181       lbp++;
182     }
183
184   if (lbp)
185     {
186       rtrackUpdate (lbp);
187
188       lineCurr = (lineCurr ?
189                   connectLine (lineCurr, newLineNode (lb)) :
190                   (lineHead = newLineNode (lb)));
191
192       lineCurr->isInline = _G.inLine;
193       lineCurr->isDebug = _G.debugLine;
194       lineCurr->ic = _G.current_iCode;
195       lineCurr->isComment = (*lbp==';');
196     }
197
198   va_end (ap);
199
200   dbuf_destroy(&dbuf);
201 }
202
203 static void
204 emitLabel (symbol *tlbl)
205 {
206   emitcode ("", "%05d$:", tlbl->key + 100);
207   lineCurr->isLabel = 1;
208 }
209
210 /*-----------------------------------------------------------------*/
211 /* mcs51_emitDebuggerSymbol - associate the current code location  */
212 /*   with a debugger symbol                                        */
213 /*-----------------------------------------------------------------*/
214 void
215 mcs51_emitDebuggerSymbol (char * debugSym)
216 {
217   _G.debugLine = 1;
218   emitcode ("", "%s ==.", debugSym);
219   _G.debugLine = 0;
220 }
221
222 /*-----------------------------------------------------------------*/
223 /* mova - moves specified value into accumulator                   */
224 /*-----------------------------------------------------------------*/
225 static void
226 mova (const char *x)
227 {
228   /* do some early peephole optimization */
229   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
230     return;
231
232   /* if it is a literal mov try to get it cheaper */
233   if (*x == '#' &&
234       rtrackMoveALit(x))
235     return;
236
237   emitcode("mov", "a,%s", x);
238 }
239
240 /*-----------------------------------------------------------------*/
241 /* movb - moves specified value into register b                    */
242 /*-----------------------------------------------------------------*/
243 static void
244 movb (const char *x)
245 {
246   /* do some early peephole optimization */
247   if (!strncmp(x, "b", 2))
248     return;
249
250   /* if it is a literal mov try to get it cheaper */
251   if (*x == '#')
252     {
253       emitcode("mov","b,%s", rtrackGetLit(x));
254       return;
255     }
256
257   emitcode("mov","b,%s", x);
258 }
259
260 /*-----------------------------------------------------------------*/
261 /* pushB - saves register B if necessary                           */
262 /*-----------------------------------------------------------------*/
263 static bool
264 pushB (void)
265 {
266   bool pushedB = FALSE;
267
268   if (BINUSE)
269     {
270       emitcode ("push", "b");
271 //    printf("B was in use !\n");
272       pushedB = TRUE;
273     }
274   else
275     {
276       OPINB++;
277     }
278   return pushedB;
279 }
280
281 /*-----------------------------------------------------------------*/
282 /* popB - restores value of register B if necessary                */
283 /*-----------------------------------------------------------------*/
284 static void
285 popB (bool pushedB)
286 {
287   if (pushedB)
288     {
289       emitcode ("pop", "b");
290     }
291   else
292     {
293       OPINB--;
294     }
295 }
296
297 /*-----------------------------------------------------------------*/
298 /* pushReg - saves register                                        */
299 /*-----------------------------------------------------------------*/
300 static bool
301 pushReg (int index, bool bits_pushed)
302 {
303   regs * reg = REG_WITH_INDEX (index);
304   if (reg->type == REG_BIT)
305     {
306       if (!bits_pushed)
307         emitcode ("push", "%s", reg->base);
308       return TRUE;
309     }
310   else
311     emitcode ("push", "%s", reg->dname);
312   return bits_pushed;
313 }
314
315 /*-----------------------------------------------------------------*/
316 /* popReg - restores register                                      */
317 /*-----------------------------------------------------------------*/
318 static bool
319 popReg (int index, bool bits_popped)
320 {
321   regs * reg = REG_WITH_INDEX (index);
322   if (reg->type == REG_BIT)
323     {
324       if (!bits_popped)
325         emitcode ("pop", "%s", reg->base);
326       return TRUE;
327     }
328   else
329     emitcode ("pop", "%s", reg->dname);
330   return bits_popped;
331 }
332
333 /*-----------------------------------------------------------------*/
334 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
335 /*-----------------------------------------------------------------*/
336 static regs *
337 getFreePtr (iCode * ic, asmop ** aopp, bool result)
338 {
339   bool r0iu, r1iu;
340   bool r0ou, r1ou;
341
342   /* the logic: if r0 & r1 used in the instruction
343      then we are in trouble otherwise */
344
345   /* first check if r0 & r1 are used by this
346      instruction, in which case we are in trouble */
347   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
348   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
349   if (r0iu && r1iu) {
350       goto endOfWorld;
351     }
352
353   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
354   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
355
356   /* if no usage of r0 then return it */
357   if (!r0iu && !r0ou)
358     {
359       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
360       (*aopp)->type = AOP_R0;
361
362       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
363     }
364
365   /* if no usage of r1 then return it */
366   if (!r1iu && !r1ou)
367     {
368       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
369       (*aopp)->type = AOP_R1;
370
371       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
372     }
373
374   /* now we know they both have usage */
375   /* if r0 not used in this instruction */
376   if (!r0iu)
377     {
378       /* push it if not already pushed */
379       if (ic->op == IPUSH)
380         {
381           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
382           R0INB++;
383         }
384       else if (!_G.r0Pushed)
385         {
386           emitcode ("push", "%s",
387                     REG_WITH_INDEX (R0_IDX)->dname);
388           _G.r0Pushed++;
389         }
390
391       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
392       (*aopp)->type = AOP_R0;
393
394       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
395     }
396
397   /* if r1 not used then */
398
399   if (!r1iu)
400     {
401       /* push it if not already pushed */
402       if (ic->op == IPUSH)
403         {
404           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
405           R1INB++;
406         }
407       else if (!_G.r1Pushed)
408         {
409           emitcode ("push", "%s",
410                     REG_WITH_INDEX (R1_IDX)->dname);
411           _G.r1Pushed++;
412         }
413
414       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
415       (*aopp)->type = AOP_R1;
416       return REG_WITH_INDEX (R1_IDX);
417     }
418
419 endOfWorld:
420   /* I said end of world, but not quite end of world yet */
421   /* if this is a result then we can push it on the stack */
422   if (result)
423     {
424       (*aopp)->type = AOP_STK;
425       return NULL;
426     }
427   /* in the case that result AND left AND right needs a pointer reg
428      we can safely use the result's */
429   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
430     {
431       (*aopp)->type = AOP_R0;
432       return REG_WITH_INDEX (R0_IDX);
433     }
434   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
435     {
436       (*aopp)->type = AOP_R1;
437       return REG_WITH_INDEX (R1_IDX);
438     }
439
440   /* now this is REALLY the end of the world */
441   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
442           "getFreePtr should never reach here");
443   exit (1);
444 }
445
446
447 /*-----------------------------------------------------------------*/
448 /* getTempRegs - initialize an array of pointers to GPR registers */
449 /*               that are not in use. Returns 1 if the requested   */
450 /*               number of registers were available, 0 otherwise.  */
451 /*-----------------------------------------------------------------*/
452 int
453 getTempRegs(regs **tempRegs, int size, iCode *ic)
454 {
455   bitVect * freeRegs;
456   int i;
457   int offset;
458
459   if (!ic)
460     ic = _G.current_iCode;
461   if (!ic)
462     return 0;
463   if (!_G.currentFunc)
464     return 0;
465
466   freeRegs = newBitVect(8);
467   bitVectSetBit (freeRegs, R2_IDX);
468   bitVectSetBit (freeRegs, R3_IDX);
469   bitVectSetBit (freeRegs, R4_IDX);
470   bitVectSetBit (freeRegs, R5_IDX);
471   bitVectSetBit (freeRegs, R6_IDX);
472   bitVectSetBit (freeRegs, R7_IDX);
473
474   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
475     {
476       bitVect * newfreeRegs;
477       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
478       freeBitVect(freeRegs);
479       freeRegs = newfreeRegs;
480     }
481   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
482
483   offset = 0;
484   for (i=0; i<freeRegs->size; i++)
485     {
486       if (bitVectBitValue(freeRegs,i))
487         tempRegs[offset++] = REG_WITH_INDEX(i);
488       if (offset>=size)
489         {
490           freeBitVect(freeRegs);
491           return 1;
492         }
493     }
494
495   freeBitVect(freeRegs);
496   return 0;
497 }
498
499
500 /*-----------------------------------------------------------------*/
501 /* newAsmop - creates a new asmOp                                  */
502 /*-----------------------------------------------------------------*/
503 static asmop *
504 newAsmop (short type)
505 {
506   asmop *aop;
507
508   aop = Safe_calloc (1, sizeof (asmop));
509   aop->type = type;
510   aop->allocated = 1;
511   return aop;
512 }
513
514 /*-----------------------------------------------------------------*/
515 /* pointerCode - returns the code for a pointer type               */
516 /*-----------------------------------------------------------------*/
517 static int
518 pointerCode (sym_link * etype)
519 {
520
521   return PTR_TYPE (SPEC_OCLS (etype));
522
523 }
524
525 /*-----------------------------------------------------------------*/
526 /* leftRightUseAcc - returns size of accumulator use by operands   */
527 /*-----------------------------------------------------------------*/
528 static int
529 leftRightUseAcc(iCode *ic)
530 {
531   operand *op;
532   int size;
533   int accuseSize = 0;
534   int accuse = 0;
535
536   if (!ic)
537     {
538       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
539               "null iCode pointer");
540       return 0;
541     }
542
543   if (ic->op == IFX)
544     {
545       op = IC_COND (ic);
546       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
547         {
548           accuse = 1;
549           size = getSize (OP_SYMBOL (op)->type);
550           if (size>accuseSize)
551             accuseSize = size;
552         }
553     }
554   else if (ic->op == JUMPTABLE)
555     {
556       op = IC_JTCOND (ic);
557       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
558         {
559           accuse = 1;
560           size = getSize (OP_SYMBOL (op)->type);
561           if (size>accuseSize)
562             accuseSize = size;
563         }
564     }
565   else
566     {
567       op = IC_LEFT (ic);
568       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
569         {
570           accuse = 1;
571           size = getSize (OP_SYMBOL (op)->type);
572           if (size>accuseSize)
573             accuseSize = size;
574         }
575       op = IC_RIGHT (ic);
576       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
577         {
578           accuse = 1;
579           size = getSize (OP_SYMBOL (op)->type);
580           if (size>accuseSize)
581             accuseSize = size;
582         }
583     }
584
585   if (accuseSize)
586     return accuseSize;
587   else
588     return accuse;
589 }
590
591 /*-----------------------------------------------------------------*/
592 /* aopForSym - for a true symbol                                   */
593 /*-----------------------------------------------------------------*/
594 static asmop *
595 aopForSym (iCode * ic, symbol * sym, bool result)
596 {
597   asmop *aop;
598   memmap *space;
599   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
600
601   wassertl (ic != NULL, "Got a null iCode");
602   wassertl (sym != NULL, "Got a null symbol");
603
604   space = SPEC_OCLS (sym->etype);
605
606   /* if already has one */
607   if (sym->aop)
608     {
609       sym->aop->allocated++;
610       return sym->aop;
611     }
612
613   /* assign depending on the storage class */
614   /* if it is on the stack or indirectly addressable */
615   /* space we need to assign either r0 or r1 to it   */
616   if (sym->onStack || sym->iaccess)
617     {
618       sym->aop = aop = newAsmop (0);
619       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
620       aop->size = getSize (sym->type);
621
622       /* now assign the address of the variable to
623          the pointer register */
624       if (aop->type != AOP_STK)
625         {
626           if (sym->onStack)
627             {
628               signed char offset = ((sym->stack < 0) ?
629                          ((signed char) (sym->stack - _G.nRegsSaved)) :
630                          ((signed char) sym->stack)) & 0xff;
631
632               if ((abs(offset) <= 3) ||
633                   (accuse && (abs(offset) <= 7)))
634                 {
635                   emitcode ("mov", "%s,%s",
636                             aop->aopu.aop_ptr->name, SYM_BP (sym));
637                   while (offset < 0)
638                     {
639                       emitcode ("dec", aop->aopu.aop_ptr->name);
640                       offset++;
641                     }
642                   while (offset > 0)
643                     {
644                       emitcode ("inc", aop->aopu.aop_ptr->name);
645                       offset--;
646                     }
647                 }
648               else
649                 {
650                   if (accuse)
651                     emitcode ("push", "acc");
652                   emitcode ("mov", "a,%s", SYM_BP (sym));
653                   emitcode ("add", "a,#0x%02x", offset & 0xff);
654                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
655                   if (accuse)
656                     emitcode ("pop", "acc");
657                 }
658             }
659           else
660             {
661               emitcode ("mov", "%s,#%s",
662                         aop->aopu.aop_ptr->name,
663                         sym->rname);
664             }
665           aop->paged = space->paged;
666         }
667       else
668         aop->aopu.aop_stk = sym->stack;
669       return aop;
670     }
671
672   /* if in bit space */
673   if (IN_BITSPACE (space))
674     {
675       sym->aop = aop = newAsmop (AOP_CRY);
676       aop->aopu.aop_dir = sym->rname;
677       aop->size = getSize (sym->type);
678       return aop;
679     }
680   /* if it is in direct space */
681   if (IN_DIRSPACE (space))
682     {
683       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
684       //printTypeChainRaw(sym->type, NULL);
685       //printf("space = %s\n", space ? space->sname : "NULL");
686       sym->aop = aop = newAsmop (AOP_DIR);
687       aop->aopu.aop_dir = sym->rname;
688       aop->size = getSize (sym->type);
689       return aop;
690     }
691
692   /* special case for a function */
693   if (IS_FUNC (sym->type))
694     {
695       sym->aop = aop = newAsmop (AOP_IMMD);
696       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
697       aop->size = getSize (sym->type);
698       return aop;
699     }
700
701   /* only remaining is far space */
702   /* in which case DPTR gets the address */
703   sym->aop = aop = newAsmop (AOP_DPTR);
704   emitcode ("mov", "dptr,#%s", sym->rname);
705   aop->size = getSize (sym->type);
706
707   /* if it is in code space */
708   if (IN_CODESPACE (space))
709     aop->code = 1;
710
711   return aop;
712 }
713
714 /*-----------------------------------------------------------------*/
715 /* aopForRemat - rematerialzes an object                           */
716 /*-----------------------------------------------------------------*/
717 static asmop *
718 aopForRemat (symbol * sym)
719 {
720   iCode *ic = sym->rematiCode;
721   asmop *aop = newAsmop (AOP_IMMD);
722   int ptr_type = 0;
723   int val = 0;
724
725   for (;;)
726     {
727       if (ic->op == '+')
728         val += (int) operandLitValue (IC_RIGHT (ic));
729       else if (ic->op == '-')
730         val -= (int) operandLitValue (IC_RIGHT (ic));
731       else if (IS_CAST_ICODE(ic)) {
732               sym_link *from_type = operandType(IC_RIGHT(ic));
733               aop->aopu.aop_immd.from_cast_remat = 1;
734               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
735               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
736               continue;
737       } else break;
738
739       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
740     }
741
742   if (val)
743     {
744       SNPRINTF (buffer, sizeof(buffer),
745                 "(%s %c 0x%04x)",
746                 OP_SYMBOL (IC_LEFT (ic))->rname,
747                 val >= 0 ? '+' : '-',
748                 abs (val) & 0xffff);
749     }
750   else
751     {
752       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
753     }
754
755   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
756   /* set immd2 field if required */
757   if (aop->aopu.aop_immd.from_cast_remat)
758     {
759       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
760       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
761     }
762
763   return aop;
764 }
765
766 /*-----------------------------------------------------------------*/
767 /* regsInCommon - two operands have some registers in common       */
768 /*-----------------------------------------------------------------*/
769 static bool
770 regsInCommon (operand * op1, operand * op2)
771 {
772   symbol *sym1, *sym2;
773   int i;
774
775   /* if they have registers in common */
776   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
777     return FALSE;
778
779   sym1 = OP_SYMBOL (op1);
780   sym2 = OP_SYMBOL (op2);
781
782   if (sym1->nRegs == 0 || sym2->nRegs == 0)
783     return FALSE;
784
785   for (i = 0; i < sym1->nRegs; i++)
786     {
787       int j;
788       if (!sym1->regs[i])
789         continue;
790
791       for (j = 0; j < sym2->nRegs; j++)
792         {
793           if (!sym2->regs[j])
794             continue;
795
796           if (sym2->regs[j] == sym1->regs[i])
797             return TRUE;
798         }
799     }
800
801   return FALSE;
802 }
803
804 /*-----------------------------------------------------------------*/
805 /* operandsEqu - equivalent                                        */
806 /*-----------------------------------------------------------------*/
807 static bool
808 operandsEqu (operand * op1, operand * op2)
809 {
810   symbol *sym1, *sym2;
811
812   /* if they're not symbols */
813   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
814     return FALSE;
815
816   sym1 = OP_SYMBOL (op1);
817   sym2 = OP_SYMBOL (op2);
818
819   /* if both are itemps & one is spilt
820      and the other is not then false */
821   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
822       sym1->isspilt != sym2->isspilt)
823     return FALSE;
824
825   /* if they are the same */
826   if (sym1 == sym2)
827     return TRUE;
828
829   /* if they have the same rname */
830   if (sym1->rname[0] && sym2->rname[0] &&
831       strcmp (sym1->rname, sym2->rname) == 0 &&
832       !(IS_PARM (op2) && IS_ITEMP (op1)))
833     return TRUE;
834
835   /* if left is a tmp & right is not */
836   if (IS_ITEMP (op1) &&
837       !IS_ITEMP (op2) &&
838       sym1->isspilt &&
839       (sym1->usl.spillLoc == sym2))
840     return TRUE;
841
842   if (IS_ITEMP (op2) &&
843       !IS_ITEMP (op1) &&
844       sym2->isspilt &&
845       sym1->level > 0 &&
846       (sym2->usl.spillLoc == sym1))
847     return TRUE;
848
849   return FALSE;
850 }
851
852 /*-----------------------------------------------------------------*/
853 /* sameByte - two asmops have the same address at given offsets    */
854 /*-----------------------------------------------------------------*/
855 static bool
856 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
857 {
858   if (aop1 == aop2 && off1 == off2)
859     return TRUE;
860
861   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
862     return FALSE;
863
864   if (aop1->type != aop2->type)
865     return FALSE;
866
867   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
868     return FALSE;
869
870   return TRUE;
871 }
872
873 /*-----------------------------------------------------------------*/
874 /* sameRegs - two asmops have the same registers                   */
875 /*-----------------------------------------------------------------*/
876 static bool
877 sameRegs (asmop * aop1, asmop * aop2)
878 {
879   int i;
880
881   if (aop1 == aop2)
882     return TRUE;
883
884   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
885     return FALSE;
886
887   if (aop1->type != aop2->type)
888     return FALSE;
889
890   if (aop1->size != aop2->size)
891     return FALSE;
892
893   for (i = 0; i < aop1->size; i++)
894     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
895       return FALSE;
896
897   return TRUE;
898 }
899
900 /*-----------------------------------------------------------------*/
901 /* aopOp - allocates an asmop for an operand  :                    */
902 /*-----------------------------------------------------------------*/
903 static void
904 aopOp (operand * op, iCode * ic, bool result)
905 {
906   asmop *aop;
907   symbol *sym;
908   int i;
909
910   if (!op)
911     return;
912
913   /* if this a literal */
914   if (IS_OP_LITERAL (op))
915     {
916       op->aop = aop = newAsmop (AOP_LIT);
917       aop->aopu.aop_lit = op->operand.valOperand;
918       aop->size = getSize (operandType (op));
919       return;
920     }
921
922   /* if already has a asmop then continue */
923   if (op->aop)
924     {
925       op->aop->allocated++;
926       return;
927     }
928
929   /* if the underlying symbol has a aop */
930   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
931     {
932       op->aop = OP_SYMBOL (op)->aop;
933       op->aop->allocated++;
934       return;
935     }
936
937   /* if this is a true symbol */
938   if (IS_TRUE_SYMOP (op))
939     {
940       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
941       return;
942     }
943
944   /* this is a temporary : this has
945      only five choices :
946      a) register
947      b) spillocation
948      c) rematerialize
949      d) conditional
950      e) can be a return use only */
951
952   sym = OP_SYMBOL (op);
953
954   /* if the type is a conditional */
955   if (sym->regType == REG_CND)
956     {
957       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
958       aop->size = sym->ruonly ? 1 : 0;
959       return;
960     }
961
962   /* if it is spilt then two situations
963      a) is rematerialize
964      b) has a spill location */
965   if (sym->isspilt || sym->nRegs == 0)
966     {
967
968       /* rematerialize it NOW */
969       if (sym->remat)
970         {
971           sym->aop = op->aop = aop = aopForRemat (sym);
972           aop->size = getSize (sym->type);
973           return;
974         }
975
976       if (sym->accuse)
977         {
978           int i;
979           sym->aop = op->aop = aop = newAsmop (AOP_ACC);
980           aop->size = getSize (sym->type);
981           for (i = 0; i < 2; i++)
982             aop->aopu.aop_str[i] = accUse[i];
983           return;
984         }
985
986       if (sym->ruonly)
987         {
988           unsigned i;
989
990           sym->aop = op->aop = aop = newAsmop (AOP_STR);
991           aop->size = getSize (sym->type);
992           for (i = 0; i < fReturnSizeMCS51; i++)
993             aop->aopu.aop_str[i] = fReturn[i];
994           return;
995         }
996
997       if (sym->usl.spillLoc)
998         {
999           asmop *oldAsmOp = NULL;
1000
1001           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1002             {
1003               /* force a new aop if sizes differ */
1004               oldAsmOp = sym->usl.spillLoc->aop;
1005               sym->usl.spillLoc->aop = NULL;
1006             }
1007           sym->aop = op->aop = aop =
1008                      aopForSym (ic, sym->usl.spillLoc, result);
1009           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1010             {
1011               /* Don't reuse the new aop, go with the last one */
1012               sym->usl.spillLoc->aop = oldAsmOp;
1013             }
1014           aop->size = getSize (sym->type);
1015           return;
1016         }
1017
1018       /* else must be a dummy iTemp */
1019       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1020       aop->size = getSize (sym->type);
1021       return;
1022     }
1023
1024   /* if the type is a bit register */
1025   if (sym->regType == REG_BIT)
1026     {
1027       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1028       aop->size = sym->nRegs;//1???
1029       aop->aopu.aop_reg[0] = sym->regs[0];
1030       aop->aopu.aop_dir = sym->regs[0]->name;
1031       return;
1032     }
1033
1034   /* must be in a register */
1035   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1036   aop->size = sym->nRegs;
1037   for (i = 0; i < sym->nRegs; i++)
1038     aop->aopu.aop_reg[i] = sym->regs[i];
1039 }
1040
1041 /*-----------------------------------------------------------------*/
1042 /* freeAsmop - free up the asmop given to an operand               */
1043 /*----------------------------------------------------------------*/
1044 static void
1045 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1046 {
1047   asmop *aop;
1048
1049   if (!op)
1050     aop = aaop;
1051   else
1052     aop = op->aop;
1053
1054   if (!aop)
1055     return;
1056
1057   aop->allocated--;
1058
1059   if (aop->allocated)
1060     goto dealloc;
1061
1062   /* depending on the asmop type only three cases need work
1063      AOP_R0, AOP_R1 & AOP_STK */
1064   switch (aop->type)
1065     {
1066     case AOP_R0:
1067       if (R0INB)
1068         {
1069           emitcode ("mov", "r0,b");
1070           R0INB--;
1071         }
1072       else if (_G.r0Pushed)
1073         {
1074           if (pop)
1075             {
1076               emitcode ("pop", "ar0");
1077               _G.r0Pushed--;
1078             }
1079         }
1080       bitVectUnSetBit (ic->rUsed, R0_IDX);
1081       break;
1082
1083     case AOP_R1:
1084       if (R1INB)
1085         {
1086           emitcode ("mov", "r1,b");
1087           R1INB--;
1088         }
1089       else if (_G.r1Pushed)
1090         {
1091           if (pop)
1092             {
1093               emitcode ("pop", "ar1");
1094               _G.r1Pushed--;
1095             }
1096         }
1097       bitVectUnSetBit (ic->rUsed, R1_IDX);
1098       break;
1099
1100     case AOP_STK:
1101       {
1102         int sz = aop->size;
1103         int stk = aop->aopu.aop_stk + aop->size - 1;
1104         bitVectUnSetBit (ic->rUsed, R0_IDX);
1105         bitVectUnSetBit (ic->rUsed, R1_IDX);
1106
1107         getFreePtr (ic, &aop, FALSE);
1108
1109         if (stk)
1110           {
1111             emitcode ("mov", "a,_bp");
1112             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1113             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1114           }
1115         else
1116           {
1117             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1118           }
1119
1120         while (sz--)
1121           {
1122             emitcode ("pop", "acc");
1123             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1124             if (!sz)
1125               break;
1126             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1127           }
1128         op->aop = aop;
1129         freeAsmop (op, NULL, ic, TRUE);
1130         if (_G.r1Pushed)
1131           {
1132             emitcode ("pop", "ar1");
1133             _G.r1Pushed--;
1134           }
1135         if (_G.r0Pushed)
1136           {
1137             emitcode ("pop", "ar0");
1138             _G.r0Pushed--;
1139           }
1140       }
1141       break;
1142     }
1143
1144 dealloc:
1145   /* all other cases just dealloc */
1146   if (op)
1147     {
1148       op->aop = NULL;
1149       if (IS_SYMOP (op))
1150         {
1151           OP_SYMBOL (op)->aop = NULL;
1152           /* if the symbol has a spill */
1153           if (SPIL_LOC (op))
1154             SPIL_LOC (op)->aop = NULL;
1155         }
1156     }
1157 }
1158
1159 /*------------------------------------------------------------------*/
1160 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1161 /*                      pop r0 or r1 off stack if pushed            */
1162 /*------------------------------------------------------------------*/
1163 static void
1164 freeForBranchAsmop (operand * op)
1165 {
1166   asmop *aop;
1167
1168   if (!op)
1169     return;
1170
1171   aop = op->aop;
1172
1173   if (!aop)
1174     return;
1175
1176   if (!aop->allocated)
1177     return;
1178
1179   switch (aop->type)
1180     {
1181     case AOP_R0:
1182       if (R0INB)
1183         {
1184           emitcode ("mov", "r0,b");
1185         }
1186       else if (_G.r0Pushed)
1187         {
1188           emitcode ("pop", "ar0");
1189         }
1190       break;
1191
1192     case AOP_R1:
1193       if (R1INB)
1194         {
1195           emitcode ("mov", "r1,b");
1196         }
1197       else if (_G.r1Pushed)
1198         {
1199           emitcode ("pop", "ar1");
1200         }
1201       break;
1202
1203     case AOP_STK:
1204       {
1205         int sz = aop->size;
1206         int stk = aop->aopu.aop_stk + aop->size - 1;
1207
1208         emitcode ("mov", "b,r0");
1209         if (stk)
1210           {
1211             emitcode ("mov", "a,_bp");
1212             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1213             emitcode ("mov", "r0,a");
1214           }
1215         else
1216           {
1217             emitcode ("mov", "r0,_bp");
1218           }
1219
1220         while (sz--)
1221           {
1222             emitcode ("pop", "acc");
1223             emitcode ("mov", "@r0,a");
1224             if (!sz)
1225               break;
1226             emitcode ("dec", "r0");
1227           }
1228         emitcode ("mov", "r0,b");
1229       }
1230     }
1231
1232 }
1233
1234 /*-----------------------------------------------------------------*/
1235 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1236 /*                 clobber the accumulator                         */
1237 /*-----------------------------------------------------------------*/
1238 static bool
1239 aopGetUsesAcc (operand * oper, int offset)
1240 {
1241   asmop * aop = AOP (oper);
1242
1243   if (offset > (aop->size - 1))
1244     return FALSE;
1245
1246   switch (aop->type)
1247     {
1248
1249     case AOP_R0:
1250     case AOP_R1:
1251       if (aop->paged)
1252         return TRUE;
1253       return FALSE;
1254     case AOP_DPTR:
1255       return TRUE;
1256     case AOP_IMMD:
1257       return FALSE;
1258     case AOP_DIR:
1259       return FALSE;
1260     case AOP_REG:
1261       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1262       return FALSE;
1263     case AOP_CRY:
1264       return TRUE;
1265     case AOP_ACC:
1266       if (offset)
1267         return FALSE;
1268       return TRUE;
1269     case AOP_LIT:
1270       return FALSE;
1271     case AOP_STR:
1272       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1273         return TRUE;
1274       return FALSE;
1275     case AOP_DUMMY:
1276       return FALSE;
1277     default:
1278       /* Error case --- will have been caught already */
1279       wassert(0);
1280       return FALSE;
1281     }
1282 }
1283
1284 /*-------------------------------------------------------------------*/
1285 /* aopGet - for fetching value of the aop                            */
1286 /*-------------------------------------------------------------------*/
1287 static char *
1288 aopGet (operand * oper, int offset, bool bit16, bool dname)
1289 {
1290   asmop * aop = AOP (oper);
1291
1292   /* offset is greater than
1293      size then zero */
1294   if (offset > (aop->size - 1) &&
1295       aop->type != AOP_LIT)
1296     return zero;
1297
1298   /* depending on type */
1299   switch (aop->type)
1300     {
1301     case AOP_DUMMY:
1302       return zero;
1303
1304     case AOP_R0:
1305     case AOP_R1:
1306       /* if we need to increment it */
1307       while (offset > aop->coff)
1308         {
1309           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1310           aop->coff++;
1311         }
1312
1313       while (offset < aop->coff)
1314         {
1315           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1316           aop->coff--;
1317         }
1318
1319       aop->coff = offset;
1320       if (aop->paged)
1321         {
1322           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1323           return (dname ? "acc" : "a");
1324         }
1325       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1326       return Safe_strdup(buffer);
1327
1328     case AOP_DPTR:
1329       if (aop->code && aop->coff==0 && offset>=1) {
1330         emitcode ("mov", "a,#0x%02x", offset);
1331         emitcode ("movc", "a,@a+dptr");
1332         return (dname ? "acc" : "a");
1333       }
1334
1335       while (offset > aop->coff)
1336         {
1337           emitcode ("inc", "dptr");
1338           aop->coff++;
1339         }
1340
1341       while (offset < aop->coff)
1342         {
1343           emitcode ("lcall", "__decdptr");
1344           aop->coff--;
1345         }
1346
1347       aop->coff = offset;
1348       if (aop->code)
1349         {
1350           emitcode ("clr", "a");
1351           emitcode ("movc", "a,@a+dptr");
1352         }
1353       else
1354         {
1355           emitcode ("movx", "a,@dptr");
1356         }
1357       return (dname ? "acc" : "a");
1358
1359     case AOP_IMMD:
1360       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1361         {
1362           SNPRINTF(buffer, sizeof(buffer),
1363                    "%s",aop->aopu.aop_immd.aop_immd2);
1364         }
1365       else if (bit16)
1366         {
1367           SNPRINTF(buffer, sizeof(buffer),
1368                    "#%s", aop->aopu.aop_immd.aop_immd1);
1369         }
1370       else if (offset)
1371         {
1372           SNPRINTF (buffer, sizeof(buffer),
1373                     "#(%s >> %d)",
1374                     aop->aopu.aop_immd.aop_immd1,
1375                     offset * 8);
1376         }
1377       else
1378         {
1379           SNPRINTF (buffer, sizeof(buffer),
1380                     "#%s",
1381                     aop->aopu.aop_immd.aop_immd1);
1382         }
1383       return Safe_strdup(buffer);
1384
1385     case AOP_DIR:
1386       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1387         {
1388           SNPRINTF (buffer, sizeof(buffer),
1389                     "(%s >> %d)",
1390                     aop->aopu.aop_dir, offset * 8);
1391         }
1392       else if (offset)
1393         {
1394           SNPRINTF (buffer, sizeof(buffer),
1395                     "(%s + %d)",
1396                     aop->aopu.aop_dir,
1397                     offset);
1398         }
1399       else
1400         {
1401           SNPRINTF (buffer, sizeof(buffer),
1402                     "%s",
1403                     aop->aopu.aop_dir);
1404         }
1405
1406       return Safe_strdup(buffer);
1407
1408     case AOP_REG:
1409       if (dname)
1410         return aop->aopu.aop_reg[offset]->dname;
1411       else
1412         return aop->aopu.aop_reg[offset]->name;
1413
1414     case AOP_CRY:
1415       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1416       emitcode ("clr", "a");
1417       emitcode ("rlc", "a");
1418       return (dname ? "acc" : "a");
1419
1420     case AOP_ACC:
1421       if (!offset && dname)
1422         return "acc";
1423       return aop->aopu.aop_str[offset];
1424
1425     case AOP_LIT:
1426       return aopLiteral (aop->aopu.aop_lit, offset);
1427
1428     case AOP_STR:
1429       aop->coff = offset;
1430       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1431           dname)
1432         return "acc";
1433
1434       return aop->aopu.aop_str[offset];
1435
1436     }
1437
1438   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1439           "aopget got unsupported aop->type");
1440   exit (1);
1441 }
1442
1443 /*-----------------------------------------------------------------*/
1444 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1445 /*                 clobber the accumulator                         */
1446 /*-----------------------------------------------------------------*/
1447 static bool
1448 aopPutUsesAcc (operand * oper, const char *s, int offset)
1449 {
1450   asmop * aop = AOP (oper);
1451
1452   if (offset > (aop->size - 1))
1453     return FALSE;
1454
1455   switch (aop->type)
1456     {
1457     case AOP_DUMMY:
1458       return TRUE;
1459     case AOP_DIR:
1460       return FALSE;
1461     case AOP_REG:
1462       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1463       return FALSE;
1464     case AOP_DPTR:
1465       return TRUE;
1466     case AOP_R0:
1467     case AOP_R1:
1468       return ((aop->paged) || (*s == '@'));
1469     case AOP_STK:
1470       return (*s == '@');
1471     case AOP_CRY:
1472       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1473     case AOP_STR:
1474       return FALSE;
1475     case AOP_IMMD:
1476       return FALSE;
1477     case AOP_ACC:
1478       return FALSE;
1479     default:
1480       /* Error case --- will have been caught already */
1481       wassert(0);
1482       return FALSE;
1483     }
1484 }
1485
1486 /*-----------------------------------------------------------------*/
1487 /* aopPut - puts a string for a aop and indicates if acc is in use */
1488 /*-----------------------------------------------------------------*/
1489 static bool
1490 aopPut (operand * result, const char *s, int offset)
1491 {
1492   bool bvolatile = isOperandVolatile (result, FALSE);
1493   bool accuse = FALSE;
1494   asmop * aop = AOP (result);
1495   const char *d = NULL;
1496
1497   if (aop->size && offset > (aop->size - 1))
1498     {
1499       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1500               "aopPut got offset > aop->size");
1501       exit (1);
1502     }
1503
1504   /* will assign value to value */
1505   /* depending on where it is ofcourse */
1506   switch (aop->type)
1507     {
1508     case AOP_DUMMY:
1509       MOVA (s);         /* read s in case it was volatile */
1510       accuse = TRUE;
1511       break;
1512
1513     case AOP_DIR:
1514       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1515         {
1516           SNPRINTF (buffer, sizeof(buffer),
1517                     "(%s >> %d)",
1518                     aop->aopu.aop_dir, offset * 8);
1519         }
1520       else if (offset)
1521         {
1522           SNPRINTF (buffer, sizeof(buffer),
1523                     "(%s + %d)",
1524                     aop->aopu.aop_dir, offset);
1525         }
1526       else
1527         {
1528           SNPRINTF (buffer, sizeof(buffer),
1529                     "%s",
1530                     aop->aopu.aop_dir);
1531         }
1532
1533       if (strcmp (buffer, s) || bvolatile)
1534         {
1535           emitcode ("mov", "%s,%s", buffer, s);
1536         }
1537       if (!strcmp (buffer, "acc"))
1538         {
1539           accuse = TRUE;
1540         }
1541       break;
1542
1543     case AOP_REG:
1544       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1545           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1546         {
1547           if (*s == '@' ||
1548               strcmp (s, "r0") == 0 ||
1549               strcmp (s, "r1") == 0 ||
1550               strcmp (s, "r2") == 0 ||
1551               strcmp (s, "r3") == 0 ||
1552               strcmp (s, "r4") == 0 ||
1553               strcmp (s, "r5") == 0 ||
1554               strcmp (s, "r6") == 0 ||
1555               strcmp (s, "r7") == 0)
1556             {
1557               emitcode ("mov", "%s,%s",
1558                         aop->aopu.aop_reg[offset]->dname, s);
1559             }
1560           else
1561             {
1562               emitcode ("mov", "%s,%s",
1563                         aop->aopu.aop_reg[offset]->name, s);
1564             }
1565         }
1566       break;
1567
1568     case AOP_DPTR:
1569       if (aop->code)
1570         {
1571           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1572                   "aopPut writing to code space");
1573           exit (1);
1574         }
1575
1576       while (offset > aop->coff)
1577         {
1578           aop->coff++;
1579           emitcode ("inc", "dptr");
1580         }
1581
1582       while (offset < aop->coff)
1583         {
1584           aop->coff--;
1585           emitcode ("lcall", "__decdptr");
1586         }
1587
1588       aop->coff = offset;
1589
1590       /* if not in accumulator */
1591       MOVA (s);
1592
1593       emitcode ("movx", "@dptr,a");
1594       break;
1595
1596     case AOP_R0:
1597     case AOP_R1:
1598       while (offset > aop->coff)
1599         {
1600           aop->coff++;
1601           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1602         }
1603       while (offset < aop->coff)
1604         {
1605           aop->coff--;
1606           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1607         }
1608       aop->coff = offset;
1609
1610       if (aop->paged)
1611         {
1612           MOVA (s);
1613           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1614         }
1615       else if (*s == '@')
1616         {
1617           MOVA (s);
1618           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1619         }
1620       else if (strcmp (s, "r0") == 0 ||
1621                strcmp (s, "r1") == 0 ||
1622                strcmp (s, "r2") == 0 ||
1623                strcmp (s, "r3") == 0 ||
1624                strcmp (s, "r4") == 0 ||
1625                strcmp (s, "r5") == 0 ||
1626                strcmp (s, "r6") == 0 ||
1627                strcmp (s, "r7") == 0)
1628         {
1629           char buffer[10];
1630           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1631           emitcode ("mov", "@%s,%s",
1632                     aop->aopu.aop_ptr->name, buffer);
1633         }
1634       else
1635         {
1636           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1637         }
1638       break;
1639
1640     case AOP_STK:
1641       if (strcmp (s, "a") == 0)
1642         {
1643           emitcode ("push", "acc");
1644         }
1645       else if (*s=='@')
1646         {
1647           MOVA(s);
1648           emitcode ("push", "acc");
1649         }
1650       else if (strcmp (s, "r0") == 0 ||
1651                strcmp (s, "r1") == 0 ||
1652                strcmp (s, "r2") == 0 ||
1653                strcmp (s, "r3") == 0 ||
1654                strcmp (s, "r4") == 0 ||
1655                strcmp (s, "r5") == 0 ||
1656                strcmp (s, "r6") == 0 ||
1657                strcmp (s, "r7") == 0)
1658         {
1659           char buffer[10];
1660           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1661           emitcode ("push", buffer);
1662         }
1663       else
1664         {
1665           emitcode ("push", s);
1666         }
1667
1668       break;
1669
1670     case AOP_CRY:
1671       // destination is carry for return-use-only
1672       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1673       // source is no literal and not in carry
1674       if ((s != zero) && (s != one) && strcmp (s, "c"))
1675         {
1676           MOVA (s);
1677           /* set C, if a >= 1 */
1678           emitcode ("add", "a,#0xff");
1679           s = "c";
1680         }
1681       // now source is zero, one or carry
1682
1683       /* if result no bit variable */
1684       if (!d)
1685         {
1686           if (!strcmp (s, "c"))
1687             {
1688               /* inefficient: move carry into A and use jz/jnz */
1689               emitcode ("clr", "a");
1690               emitcode ("rlc", "a");
1691               accuse = TRUE;
1692             }
1693           else
1694             {
1695               MOVA (s);
1696               accuse = TRUE;
1697             }
1698         }
1699       else if (s == zero)
1700           emitcode ("clr", "%s", d);
1701       else if (s == one)
1702           emitcode ("setb", "%s", d);
1703       else if (strcmp (s, d))
1704           emitcode ("mov", "%s,c", d);
1705       break;
1706
1707     case AOP_STR:
1708       aop->coff = offset;
1709       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1710         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1711       break;
1712
1713     case AOP_ACC:
1714       accuse = TRUE;
1715       aop->coff = offset;
1716       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1717         break;
1718
1719       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1720         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1721       break;
1722
1723     default:
1724       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1725               "aopPut got unsupported aop->type");
1726       exit (1);
1727     }
1728
1729     return accuse;
1730 }
1731
1732
1733 #if 0
1734 /*-----------------------------------------------------------------*/
1735 /* pointToEnd :- points to the last byte of the operand            */
1736 /*-----------------------------------------------------------------*/
1737 static void
1738 pointToEnd (asmop * aop)
1739 {
1740   int count;
1741   if (!aop)
1742     return;
1743
1744   aop->coff = count = (aop->size - 1);
1745   switch (aop->type)
1746     {
1747     case AOP_R0:
1748     case AOP_R1:
1749       while (count--)
1750         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1751       break;
1752     case AOP_DPTR:
1753       while (count--)
1754         emitcode ("inc", "dptr");
1755       break;
1756     }
1757
1758 }
1759 #endif
1760
1761 /*-----------------------------------------------------------------*/
1762 /* reAdjustPreg - points a register back to where it should        */
1763 /*-----------------------------------------------------------------*/
1764 static void
1765 reAdjustPreg (asmop * aop)
1766 {
1767   if ((aop->coff==0) || (aop->size <= 1))
1768     return;
1769
1770   switch (aop->type)
1771     {
1772     case AOP_R0:
1773     case AOP_R1:
1774       while (aop->coff--)
1775         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1776       break;
1777     case AOP_DPTR:
1778       while (aop->coff--)
1779         {
1780           emitcode ("lcall", "__decdptr");
1781         }
1782       break;
1783     }
1784   aop->coff = 0;
1785 }
1786
1787 /*-----------------------------------------------------------------*/
1788 /* opIsGptr: returns non-zero if the passed operand is       */
1789 /* a generic pointer type.             */
1790 /*-----------------------------------------------------------------*/
1791 static int
1792 opIsGptr (operand * op)
1793 {
1794   sym_link *type = operandType (op);
1795
1796   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1797     {
1798       return 1;
1799     }
1800   return 0;
1801 }
1802
1803 /*-----------------------------------------------------------------*/
1804 /* getDataSize - get the operand data size                         */
1805 /*-----------------------------------------------------------------*/
1806 static int
1807 getDataSize (operand * op)
1808 {
1809   int size;
1810   size = AOP_SIZE (op);
1811   if (size == GPTRSIZE)
1812     {
1813       sym_link *type = operandType (op);
1814       if (IS_GENPTR (type))
1815         {
1816           /* generic pointer; arithmetic operations
1817            * should ignore the high byte (pointer type).
1818            */
1819           size--;
1820         }
1821     }
1822   return size;
1823 }
1824
1825 /*-----------------------------------------------------------------*/
1826 /* outAcc - output Acc                                             */
1827 /*-----------------------------------------------------------------*/
1828 static void
1829 outAcc (operand * result)
1830 {
1831   int size, offset;
1832   size = getDataSize (result);
1833   if (size)
1834     {
1835       aopPut (result, "a", 0);
1836       size--;
1837       offset = 1;
1838       /* unsigned or positive */
1839       while (size--)
1840         {
1841           aopPut (result, zero, offset++);
1842         }
1843     }
1844 }
1845
1846 /*-----------------------------------------------------------------*/
1847 /* outBitC - output a bit C                                        */
1848 /*-----------------------------------------------------------------*/
1849 static void
1850 outBitC (operand * result)
1851 {
1852   /* if the result is bit */
1853   if (AOP_TYPE (result) == AOP_CRY)
1854     {
1855       if (!IS_OP_RUONLY (result))
1856         aopPut (result, "c", 0);
1857     }
1858   else
1859     {
1860       emitcode ("clr", "a");
1861       emitcode ("rlc", "a");
1862       outAcc (result);
1863     }
1864 }
1865
1866 /*-----------------------------------------------------------------*/
1867 /* toBoolean - emit code for orl a,operator(sizeop)                */
1868 /*-----------------------------------------------------------------*/
1869 static void
1870 toBoolean (operand * oper)
1871 {
1872   int size = AOP_SIZE (oper) - 1;
1873   int offset = 1;
1874   bool AccUsed = FALSE;
1875   bool pushedB;
1876
1877   while (!AccUsed && size--)
1878     {
1879       AccUsed |= aopGetUsesAcc(oper, offset++);
1880     }
1881
1882   size = AOP_SIZE (oper) - 1;
1883   offset = 1;
1884   MOVA (aopGet (oper, 0, FALSE, FALSE));
1885   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1886     {
1887       pushedB = pushB ();
1888       emitcode("mov", "b,a");
1889       while (--size)
1890         {
1891           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1892           emitcode ("orl", "b,a");
1893         }
1894       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1895       emitcode ("orl", "a,b");
1896       popB (pushedB);
1897     }
1898   else
1899     {
1900       while (size--)
1901         {
1902           emitcode ("orl", "a,%s",
1903                     aopGet (oper, offset++, FALSE, FALSE));
1904         }
1905     }
1906 }
1907
1908 /*-----------------------------------------------------------------*/
1909 /* toCarry - make boolean and move into carry                      */
1910 /*-----------------------------------------------------------------*/
1911 static void
1912 toCarry (operand * oper)
1913 {
1914   /* if the operand is a literal then
1915      we know what the value is */
1916   if (AOP_TYPE (oper) == AOP_LIT)
1917     {
1918       if ((int) operandLitValue (oper))
1919         SETC;
1920       else
1921         CLRC;
1922     }
1923   else if (AOP_TYPE (oper) == AOP_CRY)
1924     {
1925       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1926     }
1927   else
1928     {
1929       /* or the operand into a */
1930       toBoolean (oper);
1931       /* set C, if a >= 1 */
1932       emitcode ("add", "a,#0xff");
1933     }
1934 }
1935
1936 /*-----------------------------------------------------------------*/
1937 /* assignBit - assign operand to bit operand                       */
1938 /*-----------------------------------------------------------------*/
1939 static void
1940 assignBit (operand * result, operand * right)
1941 {
1942   /* if the right side is a literal then
1943      we know what the value is */
1944   if (AOP_TYPE (right) == AOP_LIT)
1945     {
1946       if ((int) operandLitValue (right))
1947         aopPut (result, one, 0);
1948       else
1949         aopPut (result, zero, 0);
1950     }
1951   else
1952     {
1953       toCarry (right);
1954       aopPut (result, "c", 0);
1955     }
1956 }
1957
1958
1959 /*-------------------------------------------------------------------*/
1960 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1961 /*-------------------------------------------------------------------*/
1962 static char *
1963 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1964 {
1965   char * l;
1966
1967   if (aopGetUsesAcc (oper, offset))
1968     {
1969       emitcode("mov", "b,a");
1970       MOVA (aopGet (oper, offset, bit16, dname));
1971       emitcode("xch", "a,b");
1972       aopPut (oper, "a", offset);
1973       emitcode("xch", "a,b");
1974       l = "b";
1975     }
1976   else
1977     {
1978       l = aopGet (oper, offset, bit16, dname);
1979       emitcode("xch", "a,%s", l);
1980     }
1981   return l;
1982 }
1983
1984
1985 /*-----------------------------------------------------------------*/
1986 /* genNot - generate code for ! operation                          */
1987 /*-----------------------------------------------------------------*/
1988 static void
1989 genNot (iCode * ic)
1990 {
1991   symbol *tlbl;
1992
1993   D (emitcode (";", "genNot"));
1994
1995   /* assign asmOps to operand & result */
1996   aopOp (IC_LEFT (ic), ic, FALSE);
1997   aopOp (IC_RESULT (ic), ic, TRUE);
1998
1999   /* if in bit space then a special case */
2000   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2001     {
2002       /* if left==result then cpl bit */
2003       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2004         {
2005           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2006         }
2007       else
2008         {
2009           toCarry (IC_LEFT (ic));
2010           emitcode ("cpl", "c");
2011           outBitC (IC_RESULT (ic));
2012         }
2013       goto release;
2014     }
2015
2016   toBoolean (IC_LEFT (ic));
2017
2018   /* set C, if a == 0 */
2019   tlbl = newiTempLabel (NULL);
2020   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2021   emitLabel (tlbl);
2022   outBitC (IC_RESULT (ic));
2023
2024 release:
2025   /* release the aops */
2026   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2027   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2028 }
2029
2030
2031 /*-----------------------------------------------------------------*/
2032 /* genCpl - generate code for complement                           */
2033 /*-----------------------------------------------------------------*/
2034 static void
2035 genCpl (iCode * ic)
2036 {
2037   int offset = 0;
2038   int size;
2039   symbol *tlbl;
2040   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2041
2042   D(emitcode (";", "genCpl"));
2043
2044   /* assign asmOps to operand & result */
2045   aopOp (IC_LEFT (ic), ic, FALSE);
2046   aopOp (IC_RESULT (ic), ic, TRUE);
2047
2048   /* special case if in bit space */
2049   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2050     {
2051       char *l;
2052
2053       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2054           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2055         {
2056           /* promotion rules are responsible for this strange result:
2057              bit -> int -> ~int -> bit
2058              uchar -> int -> ~int -> bit
2059           */
2060           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2061           goto release;
2062         }
2063
2064       tlbl=newiTempLabel(NULL);
2065       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2066       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2067           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2068           IS_AOP_PREG (IC_LEFT (ic)))
2069         {
2070           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2071         }
2072       else
2073         {
2074           MOVA (l);
2075           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2076         }
2077       emitLabel (tlbl);
2078       outBitC (IC_RESULT(ic));
2079       goto release;
2080     }
2081
2082   size = AOP_SIZE (IC_RESULT (ic));
2083   while (size--)
2084     {
2085       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2086       MOVA (l);
2087       emitcode ("cpl", "a");
2088       aopPut (IC_RESULT (ic), "a", offset++);
2089     }
2090
2091
2092 release:
2093   /* release the aops */
2094   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2095   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2096 }
2097
2098 /*-----------------------------------------------------------------*/
2099 /* genUminusFloat - unary minus for floating points                */
2100 /*-----------------------------------------------------------------*/
2101 static void
2102 genUminusFloat (operand * op, operand * result)
2103 {
2104   int size, offset = 0;
2105   char *l;
2106
2107   D (emitcode (";", "genUminusFloat"));
2108
2109   /* for this we just copy and then flip the bit */
2110
2111   size = AOP_SIZE (op) - 1;
2112
2113   while (size--)
2114     {
2115       aopPut (result,
2116               aopGet (op, offset, FALSE, FALSE),
2117               offset);
2118       offset++;
2119     }
2120
2121   l = aopGet (op, offset, FALSE, FALSE);
2122   MOVA (l);
2123
2124   emitcode ("cpl", "acc.7");
2125   aopPut (result, "a", offset);
2126 }
2127
2128 /*-----------------------------------------------------------------*/
2129 /* genUminus - unary minus code generation                         */
2130 /*-----------------------------------------------------------------*/
2131 static void
2132 genUminus (iCode * ic)
2133 {
2134   int offset, size;
2135   sym_link *optype;
2136
2137   D (emitcode (";", "genUminus"));
2138
2139   /* assign asmops */
2140   aopOp (IC_LEFT (ic), ic, FALSE);
2141   aopOp (IC_RESULT (ic), ic, TRUE);
2142
2143   /* if both in bit space then special
2144      case */
2145   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2146       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2147     {
2148
2149       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2150       emitcode ("cpl", "c");
2151       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2152       goto release;
2153     }
2154
2155   optype = operandType (IC_LEFT (ic));
2156
2157   /* if float then do float stuff */
2158   if (IS_FLOAT (optype))
2159     {
2160       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2161       goto release;
2162     }
2163
2164   /* otherwise subtract from zero */
2165   size = AOP_SIZE (IC_LEFT (ic));
2166   offset = 0;
2167   while (size--)
2168     {
2169       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2170       if (!strcmp (l, "a"))
2171         {
2172           if (offset == 0)
2173             SETC;
2174           emitcode ("cpl", "a");
2175           emitcode ("addc", "a,#0");
2176         }
2177       else
2178         {
2179           if (offset == 0)
2180             CLRC;
2181           emitcode ("clr", "a");
2182           emitcode ("subb", "a,%s", l);
2183         }
2184       aopPut (IC_RESULT (ic), "a", offset++);
2185     }
2186
2187   /* if any remaining bytes in the result */
2188   /* we just need to propagate the sign   */
2189   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2190     {
2191       emitcode ("rlc", "a");
2192       emitcode ("subb", "a,acc");
2193       while (size--)
2194         aopPut (IC_RESULT (ic), "a", offset++);
2195     }
2196
2197 release:
2198   /* release the aops */
2199   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2200   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2201 }
2202
2203 /*-----------------------------------------------------------------*/
2204 /* saveRegisters - will look for a call and save the registers     */
2205 /*-----------------------------------------------------------------*/
2206 static void
2207 saveRegisters (iCode * lic)
2208 {
2209   int i;
2210   iCode *ic;
2211   bitVect *rsave;
2212
2213   /* look for call */
2214   for (ic = lic; ic; ic = ic->next)
2215     if (ic->op == CALL || ic->op == PCALL)
2216       break;
2217
2218   if (!ic)
2219     {
2220       fprintf (stderr, "found parameter push with no function call\n");
2221       return;
2222     }
2223
2224   /* if the registers have been saved already or don't need to be then
2225      do nothing */
2226   if (ic->regsSaved)
2227     return;
2228   if (IS_SYMOP(IC_LEFT(ic)) &&
2229       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2230        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2231     return;
2232
2233   /* save the registers in use at this time but skip the
2234      ones for the result */
2235   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2236                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2237
2238   ic->regsSaved = 1;
2239   if (options.useXstack)
2240     {
2241       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2242       int nBits = bitVectnBitsOn (rsavebits);
2243       int count = bitVectnBitsOn (rsave);
2244
2245       if (nBits != 0)
2246         {
2247           count = count - nBits + 1;
2248           /* remove all but the first bits as they are pushed all at once */
2249           rsave = bitVectCplAnd (rsave, rsavebits);
2250           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2251         }
2252       freeBitVect (rsavebits);
2253
2254       if (count == 1)
2255         {
2256           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2257           if (reg->type == REG_BIT)
2258             {
2259               emitcode ("mov", "a,%s", reg->base);
2260             }
2261           else
2262             {
2263               emitcode ("mov", "a,%s", reg->name);
2264             }
2265           emitcode ("mov", "r0,%s", spname);
2266           emitcode ("inc", "%s", spname);// allocate before use
2267           emitcode ("movx", "@r0,a");
2268           if (bitVectBitValue (rsave, R0_IDX))
2269             emitcode ("mov", "r0,a");
2270         }
2271       else if (count != 0)
2272         {
2273           if (bitVectBitValue (rsave, R0_IDX))
2274             {
2275               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2276             }
2277           emitcode ("mov", "r0,%s", spname);
2278           MOVA ("r0");
2279           emitcode ("add", "a,#%d", count);
2280           emitcode ("mov", "%s,a", spname);
2281           for (i = 0; i < mcs51_nRegs; i++)
2282             {
2283               if (bitVectBitValue (rsave, i))
2284                 {
2285                   regs * reg = REG_WITH_INDEX (i);
2286                   if (i == R0_IDX)
2287                     {
2288                       emitcode ("pop", "acc");
2289                       emitcode ("push", "acc");
2290                     }
2291                   else if (reg->type == REG_BIT)
2292                     {
2293                       emitcode ("mov", "a,%s", reg->base);
2294                     }
2295                   else
2296                     {
2297                       emitcode ("mov", "a,%s", reg->name);
2298                     }
2299                   emitcode ("movx", "@r0,a");
2300                   if (--count)
2301                     {
2302                       emitcode ("inc", "r0");
2303                     }
2304                 }
2305             }
2306           if (bitVectBitValue (rsave, R0_IDX))
2307             {
2308               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2309             }
2310         }
2311     }
2312   else
2313     {
2314       bool bits_pushed = FALSE;
2315       for (i = 0; i < mcs51_nRegs; i++)
2316         {
2317           if (bitVectBitValue (rsave, i))
2318             {
2319               bits_pushed = pushReg (i, bits_pushed);
2320             }
2321         }
2322     }
2323   freeBitVect (rsave);
2324 }
2325
2326 /*-----------------------------------------------------------------*/
2327 /* unsaveRegisters - pop the pushed registers                      */
2328 /*-----------------------------------------------------------------*/
2329 static void
2330 unsaveRegisters (iCode * ic)
2331 {
2332   int i;
2333   bitVect *rsave;
2334
2335   /* restore the registers in use at this time but skip the
2336      ones for the result */
2337   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2338                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2339
2340   if (options.useXstack)
2341     {
2342       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2343       int nBits = bitVectnBitsOn (rsavebits);
2344       int count = bitVectnBitsOn (rsave);
2345
2346       if (nBits != 0)
2347         {
2348           count = count - nBits + 1;
2349           /* remove all but the first bits as they are popped all at once */
2350           rsave = bitVectCplAnd (rsave, rsavebits);
2351           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2352         }
2353       freeBitVect (rsavebits);
2354
2355       if (count == 1)
2356         {
2357           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2358           emitcode ("mov", "r0,%s", spname);
2359           emitcode ("dec", "r0");
2360           emitcode ("movx", "a,@r0");
2361           if (reg->type == REG_BIT)
2362             {
2363               emitcode ("mov", "%s,a", reg->base);
2364             }
2365           else
2366             {
2367               emitcode ("mov", "%s,a", reg->name);
2368             }
2369           emitcode ("dec", "%s", spname);
2370         }
2371       else if (count != 0)
2372         {
2373           emitcode ("mov", "r0,%s", spname);
2374           for (i = mcs51_nRegs; i >= 0; i--)
2375             {
2376               if (bitVectBitValue (rsave, i))
2377                 {
2378                   regs * reg = REG_WITH_INDEX (i);
2379                   emitcode ("dec", "r0");
2380                   emitcode ("movx", "a,@r0");
2381                   if (i == R0_IDX)
2382                     {
2383                       emitcode ("push", "acc");
2384                     }
2385                   else if (reg->type == REG_BIT)
2386                     {
2387                       emitcode ("mov", "%s,a", reg->base);
2388                     }
2389                   else
2390                     {
2391                       emitcode ("mov", "%s,a", reg->name);
2392                     }
2393                 }
2394             }
2395           emitcode ("mov", "%s,r0", spname);
2396           if (bitVectBitValue (rsave, R0_IDX))
2397             {
2398               emitcode ("pop", "ar0");
2399             }
2400         }
2401     }
2402   else
2403     {
2404       bool bits_popped = FALSE;
2405       for (i = mcs51_nRegs; i >= 0; i--)
2406         {
2407           if (bitVectBitValue (rsave, i))
2408             {
2409               bits_popped = popReg (i, bits_popped);
2410             }
2411         }
2412     }
2413   freeBitVect (rsave);
2414 }
2415
2416
2417 /*-----------------------------------------------------------------*/
2418 /* pushSide -                                                      */
2419 /*-----------------------------------------------------------------*/
2420 static void
2421 pushSide (operand * oper, int size)
2422 {
2423   int offset = 0;
2424   while (size--)
2425     {
2426       char *l = aopGet (oper, offset++, FALSE, TRUE);
2427       if (AOP_TYPE (oper) != AOP_REG &&
2428           AOP_TYPE (oper) != AOP_DIR &&
2429           strcmp (l, "a"))
2430         {
2431           MOVA (l);
2432           emitcode ("push", "acc");
2433         }
2434       else
2435         {
2436           emitcode ("push", "%s", l);
2437         }
2438     }
2439 }
2440
2441 /*-----------------------------------------------------------------*/
2442 /* assignResultValue - also indicates if acc is in use afterwards  */
2443 /*-----------------------------------------------------------------*/
2444 static bool
2445 assignResultValue (operand * oper, operand * func)
2446 {
2447   int offset = 0;
2448   int size = AOP_SIZE (oper);
2449   bool accuse = FALSE;
2450   bool pushedA = FALSE;
2451
2452   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2453     {
2454       outBitC (oper);
2455       return FALSE;
2456     }
2457
2458   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2459     {
2460       emitcode ("push", "acc");
2461       pushedA = TRUE;
2462     }
2463   while (size--)
2464     {
2465       if ((offset == 3) && pushedA)
2466         emitcode ("pop", "acc");
2467       accuse |= aopPut (oper, fReturn[offset], offset);
2468       offset++;
2469     }
2470   return accuse;
2471 }
2472
2473
2474 /*-----------------------------------------------------------------*/
2475 /* genXpush - pushes onto the external stack                       */
2476 /*-----------------------------------------------------------------*/
2477 static void
2478 genXpush (iCode * ic)
2479 {
2480   asmop *aop = newAsmop (0);
2481   regs *r;
2482   int size, offset = 0;
2483
2484   D (emitcode (";", "genXpush"));
2485
2486   aopOp (IC_LEFT (ic), ic, FALSE);
2487   r = getFreePtr (ic, &aop, FALSE);
2488
2489   size = AOP_SIZE (IC_LEFT (ic));
2490
2491   if (size == 1)
2492     {
2493       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2494       emitcode ("mov", "%s,%s", r->name, spname);
2495       emitcode ("inc", "%s", spname); // allocate space first
2496       emitcode ("movx", "@%s,a", r->name);
2497     }
2498   else
2499     {
2500       // allocate space first
2501       emitcode ("mov", "%s,%s", r->name, spname);
2502       MOVA (r->name);
2503       emitcode ("add", "a,#%d", size);
2504       emitcode ("mov", "%s,a", spname);
2505
2506       while (size--)
2507         {
2508           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2509           emitcode ("movx", "@%s,a", r->name);
2510           emitcode ("inc", "%s", r->name);
2511         }
2512     }
2513
2514   freeAsmop (NULL, aop, ic, TRUE);
2515   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2516 }
2517
2518 /*-----------------------------------------------------------------*/
2519 /* genIpush - generate code for pushing this gets a little complex */
2520 /*-----------------------------------------------------------------*/
2521 static void
2522 genIpush (iCode * ic)
2523 {
2524   int size, offset = 0;
2525   char *l;
2526   char *prev = "";
2527
2528   D (emitcode (";", "genIpush"));
2529
2530   /* if this is not a parm push : ie. it is spill push
2531      and spill push is always done on the local stack */
2532   if (!ic->parmPush)
2533     {
2534
2535       /* and the item is spilt then do nothing */
2536       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2537         return;
2538
2539       aopOp (IC_LEFT (ic), ic, FALSE);
2540       size = AOP_SIZE (IC_LEFT (ic));
2541       /* push it on the stack */
2542       while (size--)
2543         {
2544           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2545           if (*l == '#')
2546             {
2547               MOVA (l);
2548               l = "acc";
2549             }
2550           emitcode ("push", "%s", l);
2551         }
2552       return;
2553     }
2554
2555   /* this is a parameter push: in this case we call
2556      the routine to find the call and save those
2557      registers that need to be saved */
2558   saveRegisters (ic);
2559
2560   /* if use external stack then call the external
2561      stack pushing routine */
2562   if (options.useXstack)
2563     {
2564       genXpush (ic);
2565       return;
2566     }
2567
2568   /* then do the push */
2569   aopOp (IC_LEFT (ic), ic, FALSE);
2570
2571   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2572   size = AOP_SIZE (IC_LEFT (ic));
2573
2574   while (size--)
2575     {
2576       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2577       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2578           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2579         {
2580           if (strcmp (l, prev) || *l == '@')
2581             MOVA (l);
2582           emitcode ("push", "acc");
2583         }
2584       else
2585         {
2586           emitcode ("push", "%s", l);
2587         }
2588       prev = l;
2589     }
2590
2591   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2592 }
2593
2594 /*-----------------------------------------------------------------*/
2595 /* genIpop - recover the registers: can happen only for spilling   */
2596 /*-----------------------------------------------------------------*/
2597 static void
2598 genIpop (iCode * ic)
2599 {
2600   int size, offset;
2601
2602   D (emitcode (";", "genIpop"));
2603
2604   /* if the temp was not pushed then */
2605   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2606     return;
2607
2608   aopOp (IC_LEFT (ic), ic, FALSE);
2609   size = AOP_SIZE (IC_LEFT (ic));
2610   offset = (size - 1);
2611   while (size--)
2612     {
2613       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2614                                      FALSE, TRUE));
2615     }
2616
2617   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2618 }
2619
2620 /*-----------------------------------------------------------------*/
2621 /* saveRBank - saves an entire register bank on the stack          */
2622 /*-----------------------------------------------------------------*/
2623 static void
2624 saveRBank (int bank, iCode * ic, bool pushPsw)
2625 {
2626   int i;
2627   int count = 8 + (pushPsw ? 1 : 0);
2628   asmop *aop = NULL;
2629   regs *r = NULL;
2630
2631   if (options.useXstack)
2632     {
2633       if (!ic)
2634         {
2635           /* Assume r0 is available for use. */
2636           r = REG_WITH_INDEX (R0_IDX);
2637         }
2638       else
2639         {
2640           aop = newAsmop (0);
2641           r = getFreePtr (ic, &aop, FALSE);
2642         }
2643       // allocate space first
2644       emitcode ("mov", "%s,%s", r->name, spname);
2645       MOVA (r->name);
2646       emitcode ("add", "a,#%d", count);
2647       emitcode ("mov", "%s,a", spname);
2648     }
2649
2650   for (i = 0; i < 8; i++)
2651     {
2652       if (options.useXstack)
2653         {
2654           emitcode ("mov", "a,(%s+%d)",
2655                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2656           emitcode ("movx", "@%s,a", r->name);
2657           if (--count)
2658             emitcode ("inc", "%s", r->name);
2659         }
2660       else
2661         emitcode ("push", "(%s+%d)",
2662                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2663     }
2664
2665   if (pushPsw)
2666     {
2667       if (options.useXstack)
2668         {
2669           emitcode ("mov", "a,psw");
2670           emitcode ("movx", "@%s,a", r->name);
2671         }
2672       else
2673         {
2674           emitcode ("push", "psw");
2675         }
2676
2677       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2678     }
2679
2680   if (aop)
2681     {
2682       freeAsmop (NULL, aop, ic, TRUE);
2683     }
2684
2685   if (ic)
2686     {
2687       ic->bankSaved = 1;
2688     }
2689 }
2690
2691 /*-----------------------------------------------------------------*/
2692 /* unsaveRBank - restores the register bank from stack             */
2693 /*-----------------------------------------------------------------*/
2694 static void
2695 unsaveRBank (int bank, iCode * ic, bool popPsw)
2696 {
2697   int i;
2698   asmop *aop = NULL;
2699   regs *r = NULL;
2700
2701   if (options.useXstack)
2702     {
2703       if (!ic)
2704         {
2705           /* Assume r0 is available for use. */
2706           r = REG_WITH_INDEX (R0_IDX);;
2707         }
2708       else
2709         {
2710           aop = newAsmop (0);
2711           r = getFreePtr (ic, &aop, FALSE);
2712         }
2713       emitcode ("mov", "%s,%s", r->name, spname);
2714     }
2715
2716   if (popPsw)
2717     {
2718       if (options.useXstack)
2719         {
2720           emitcode ("dec", "%s", r->name);
2721           emitcode ("movx", "a,@%s", r->name);
2722           emitcode ("mov", "psw,a");
2723         }
2724       else
2725         {
2726           emitcode ("pop", "psw");
2727         }
2728     }
2729
2730   for (i = 7; i >= 0; i--)
2731     {
2732       if (options.useXstack)
2733         {
2734           emitcode ("dec", "%s", r->name);
2735           emitcode ("movx", "a,@%s", r->name);
2736           emitcode ("mov", "(%s+%d),a",
2737                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2738         }
2739       else
2740         {
2741           emitcode ("pop", "(%s+%d)",
2742                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2743         }
2744     }
2745
2746   if (options.useXstack)
2747     {
2748       emitcode ("mov", "%s,%s", spname, r->name);
2749     }
2750
2751   if (aop)
2752     {
2753       freeAsmop (NULL, aop, ic, TRUE);
2754     }
2755 }
2756
2757 /*-----------------------------------------------------------------*/
2758 /* genSend - gen code for SEND                                     */
2759 /*-----------------------------------------------------------------*/
2760 static void genSend(set *sendSet)
2761 {
2762   iCode *sic;
2763   int bit_count = 0;
2764
2765   /* first we do all bit parameters */
2766   for (sic = setFirstItem (sendSet); sic;
2767        sic = setNextItem (sendSet))
2768     {
2769       if (sic->argreg > 12)
2770         {
2771           int bit = sic->argreg-13;
2772
2773           aopOp (IC_LEFT (sic), sic, FALSE);
2774
2775           /* if left is a literal then
2776              we know what the value is */
2777           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2778             {
2779               if (((int) operandLitValue (IC_LEFT (sic))))
2780                   emitcode ("setb", "b[%d]", bit);
2781               else
2782                   emitcode ("clr", "b[%d]", bit);
2783             }
2784           else
2785             {
2786               /* we need to or */
2787               toCarry (IC_LEFT (sic));
2788               emitcode ("mov", "b[%d],c", bit);
2789             }
2790           bit_count++;
2791           BitBankUsed = 1;
2792
2793           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2794         }
2795     }
2796
2797   if (bit_count)
2798     {
2799       saveRegisters (setFirstItem (sendSet));
2800       emitcode ("mov", "bits,b");
2801     }
2802
2803   /* then we do all other parameters */
2804   for (sic = setFirstItem (sendSet); sic;
2805        sic = setNextItem (sendSet))
2806     {
2807       if (sic->argreg <= 12)
2808         {
2809           int size, offset = 0;
2810           aopOp (IC_LEFT (sic), sic, FALSE);
2811           size = AOP_SIZE (IC_LEFT (sic));
2812
2813           if (sic->argreg == 1)
2814             {
2815               while (size--)
2816                 {
2817                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2818                   if (strcmp (l, fReturn[offset]))
2819                     {
2820                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2821                     }
2822                   offset++;
2823                 }
2824             }
2825           else
2826             {
2827               while (size--)
2828                 {
2829                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2830                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2831                   offset++;
2832                 }
2833             }
2834           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2835         }
2836     }
2837 }
2838
2839 /*-----------------------------------------------------------------*/
2840 /* selectRegBank - emit code to select the register bank           */
2841 /*-----------------------------------------------------------------*/
2842 static void
2843 selectRegBank (short bank, bool keepFlags)
2844 {
2845   /* if f.e. result is in carry */
2846   if (keepFlags)
2847     {
2848       emitcode ("anl", "psw,#0xE7");
2849       if (bank)
2850         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2851     }
2852   else
2853     {
2854       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2855     }
2856 }
2857
2858 /*-----------------------------------------------------------------*/
2859 /* genCall - generates a call statement                            */
2860 /*-----------------------------------------------------------------*/
2861 static void
2862 genCall (iCode * ic)
2863 {
2864   sym_link *dtype;
2865   sym_link *etype;
2866 //  bool restoreBank = FALSE;
2867   bool swapBanks = FALSE;
2868   bool accuse = FALSE;
2869   bool accPushed = FALSE;
2870   bool resultInF0 = FALSE;
2871   bool assignResultGenerated = FALSE;
2872
2873   D (emitcode (";", "genCall"));
2874
2875   dtype = operandType (IC_LEFT (ic));
2876   etype = getSpec(dtype);
2877   /* if send set is not empty then assign */
2878   if (_G.sendSet)
2879     {
2880         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2881             genSend(reverseSet(_G.sendSet));
2882         } else {
2883             genSend(_G.sendSet);
2884         }
2885       _G.sendSet = NULL;
2886     }
2887
2888   /* if we are calling a not _naked function that is not using
2889      the same register bank then we need to save the
2890      destination registers on the stack */
2891   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2892       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2893        !IFFUNC_ISISR (dtype))
2894     {
2895       swapBanks = TRUE;
2896     }
2897
2898   /* if caller saves & we have not saved then */
2899   if (!ic->regsSaved)
2900       saveRegisters (ic);
2901
2902   if (swapBanks)
2903     {
2904         emitcode ("mov", "psw,#0x%02x",
2905            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2906     }
2907
2908   /* make the call */
2909   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2910     {
2911       if (IFFUNC_CALLEESAVES(dtype))
2912         {
2913           werror (E_BANKED_WITH_CALLEESAVES);
2914         }
2915       else
2916         {
2917           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2918                      OP_SYMBOL (IC_LEFT (ic))->rname :
2919                      OP_SYMBOL (IC_LEFT (ic))->name);
2920
2921           emitcode ("mov", "r0,#%s", l);
2922           emitcode ("mov", "r1,#(%s >> 8)", l);
2923           emitcode ("mov", "r2,#(%s >> 16)", l);
2924           emitcode ("lcall", "__sdcc_banked_call");
2925         }
2926     }
2927   else
2928     {
2929       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2930                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2931                                 OP_SYMBOL (IC_LEFT (ic))->name));
2932     }
2933
2934   if (swapBanks)
2935     {
2936       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2937     }
2938
2939   /* if we need assign a result value */
2940   if ((IS_ITEMP (IC_RESULT (ic)) &&
2941        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2942        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2943         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2944         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2945       IS_TRUE_SYMOP (IC_RESULT (ic)))
2946     {
2947
2948       _G.accInUse++;
2949       aopOp (IC_RESULT (ic), ic, FALSE);
2950       _G.accInUse--;
2951
2952       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2953       assignResultGenerated = TRUE;
2954
2955       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2956     }
2957
2958   /* adjust the stack for parameters if required */
2959   if (ic->parmBytes)
2960     {
2961       int i;
2962       if (ic->parmBytes > 3)
2963         {
2964           if (accuse)
2965             {
2966               emitcode ("push", "acc");
2967               accPushed = TRUE;
2968             }
2969           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2970               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2971               !assignResultGenerated)
2972             {
2973               emitcode ("mov", "F0,c");
2974               resultInF0 = TRUE;
2975             }
2976
2977           emitcode ("mov", "a,%s", spname);
2978           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2979           emitcode ("mov", "%s,a", spname);
2980
2981           /* unsaveRegisters from xstack needs acc, but */
2982           /* unsaveRegisters from stack needs this popped */
2983           if (accPushed && !options.useXstack)
2984             {
2985               emitcode ("pop", "acc");
2986               accPushed = FALSE;
2987             }
2988         }
2989       else
2990         for (i = 0; i < ic->parmBytes; i++)
2991           emitcode ("dec", "%s", spname);
2992     }
2993
2994   /* if we had saved some registers then unsave them */
2995   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2996     {
2997       if (accuse && !accPushed && options.useXstack)
2998         {
2999           /* xstack needs acc, but doesn't touch normal stack */
3000           emitcode ("push", "acc");
3001           accPushed = TRUE;
3002         }
3003       unsaveRegisters (ic);
3004     }
3005
3006 //  /* if register bank was saved then pop them */
3007 //  if (restoreBank)
3008 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3009
3010   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3011     {
3012       if (resultInF0)
3013           emitcode ("mov", "c,F0");
3014
3015       aopOp (IC_RESULT (ic), ic, FALSE);
3016       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3017       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3018     }
3019
3020   if (accPushed)
3021     emitcode ("pop", "acc");
3022 }
3023
3024 /*-----------------------------------------------------------------*/
3025 /* genPcall - generates a call by pointer statement                */
3026 /*-----------------------------------------------------------------*/
3027 static void
3028 genPcall (iCode * ic)
3029 {
3030   sym_link *dtype;
3031   sym_link *etype;
3032   symbol *rlbl = newiTempLabel (NULL);
3033 //  bool restoreBank=FALSE;
3034   bool swapBanks = FALSE;
3035   bool resultInF0 = FALSE;
3036
3037   D (emitcode (";", "genPcall"));
3038
3039   dtype = operandType (IC_LEFT (ic))->next;
3040   etype = getSpec(dtype);
3041   /* if caller saves & we have not saved then */
3042   if (!ic->regsSaved)
3043     saveRegisters (ic);
3044
3045   /* if we are calling a not _naked function that is not using
3046      the same register bank then we need to save the
3047      destination registers on the stack */
3048   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3049       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3050       !IFFUNC_ISISR (dtype))
3051     {
3052 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3053 //    restoreBank=TRUE;
3054       swapBanks = TRUE;
3055       // need caution message to user here
3056     }
3057
3058   if (IS_LITERAL (etype))
3059     {
3060       /* if send set is not empty then assign */
3061       if (_G.sendSet)
3062         {
3063           genSend(reverseSet(_G.sendSet));
3064           _G.sendSet = NULL;
3065         }
3066
3067       if (swapBanks)
3068         {
3069           emitcode ("mov", "psw,#0x%02x",
3070            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3071         }
3072
3073       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3074         {
3075           if (IFFUNC_CALLEESAVES (dtype))
3076             {
3077               werror (E_BANKED_WITH_CALLEESAVES);
3078             }
3079           else
3080             {
3081               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3082
3083               emitcode ("mov", "r0,#%s", l);
3084               emitcode ("mov", "r1,#(%s >> 8)", l);
3085               emitcode ("mov", "r2,#(%s >> 16)", l);
3086               emitcode ("lcall", "__sdcc_banked_call");
3087             }
3088         }
3089       else
3090         {
3091           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3092         }
3093     }
3094   else
3095     {
3096       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3097         {
3098           if (IFFUNC_CALLEESAVES (dtype))
3099             {
3100               werror (E_BANKED_WITH_CALLEESAVES);
3101             }
3102           else
3103             {
3104               aopOp (IC_LEFT (ic), ic, FALSE);
3105
3106               if (!swapBanks)
3107                 {
3108                   /* what if aopGet needs r0 or r1 ??? */
3109                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3110                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3111                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3112                 }
3113               else
3114                 {
3115                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3116                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3117                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3118                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3119                 }
3120
3121               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3122
3123               /* if send set is not empty then assign */
3124               if (_G.sendSet)
3125                 {
3126                   genSend(reverseSet(_G.sendSet));
3127                   _G.sendSet = NULL;
3128                 }
3129
3130               if (swapBanks)
3131                 {
3132                   emitcode ("mov", "psw,#0x%02x",
3133                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3134                 }
3135
3136               /* make the call */
3137               emitcode ("lcall", "__sdcc_banked_call");
3138             }
3139         }
3140       else if (_G.sendSet)
3141         {
3142           /* push the return address on to the stack */
3143           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3144           emitcode ("push", "acc");
3145           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3146           emitcode ("push", "acc");
3147
3148           /* now push the calling address */
3149           aopOp (IC_LEFT (ic), ic, FALSE);
3150
3151           pushSide (IC_LEFT (ic), FPTRSIZE);
3152
3153           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3154
3155           /* if send set is not empty the assign */
3156           if (_G.sendSet)
3157             {
3158               genSend(reverseSet(_G.sendSet));
3159               _G.sendSet = NULL;
3160             }
3161
3162           if (swapBanks)
3163             {
3164               emitcode ("mov", "psw,#0x%02x",
3165                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3166             }
3167
3168           /* make the call */
3169           emitcode ("ret", "");
3170           emitLabel (rlbl);
3171         }
3172       else /* the send set is empty */
3173         {
3174           char *l;
3175           /* now get the calling address into dptr */
3176           aopOp (IC_LEFT (ic), ic, FALSE);
3177
3178           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3179           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3180             {
3181               emitcode ("mov", "r0,%s", l);
3182               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3183               emitcode ("mov", "dph,%s", l);
3184               emitcode ("mov", "dpl,r0");
3185             }
3186           else
3187             {
3188               emitcode ("mov", "dpl,%s", l);
3189               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3190               emitcode ("mov", "dph,%s", l);
3191             }
3192
3193           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3194
3195           if (swapBanks)
3196             {
3197               emitcode ("mov", "psw,#0x%02x",
3198                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3199             }
3200
3201           /* make the call */
3202           emitcode ("lcall", "__sdcc_call_dptr");
3203         }
3204     }
3205   if (swapBanks)
3206     {
3207       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3208     }
3209
3210   /* if we need assign a result value */
3211   if ((IS_ITEMP (IC_RESULT (ic)) &&
3212        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3213        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3214         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3215       IS_TRUE_SYMOP (IC_RESULT (ic)))
3216     {
3217
3218       _G.accInUse++;
3219       aopOp (IC_RESULT (ic), ic, FALSE);
3220       _G.accInUse--;
3221
3222       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3223
3224       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3225     }
3226
3227   /* adjust the stack for parameters if required */
3228   if (ic->parmBytes)
3229     {
3230       int i;
3231       if (ic->parmBytes > 3)
3232         {
3233           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3234               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3235             {
3236               emitcode ("mov", "F0,c");
3237               resultInF0 = TRUE;
3238             }
3239
3240           emitcode ("mov", "a,%s", spname);
3241           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3242           emitcode ("mov", "%s,a", spname);
3243         }
3244       else
3245         for (i = 0; i < ic->parmBytes; i++)
3246           emitcode ("dec", "%s", spname);
3247     }
3248
3249 //  /* if register bank was saved then unsave them */
3250 //  if (restoreBank)
3251 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3252
3253   /* if we had saved some registers then unsave them */
3254   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3255     unsaveRegisters (ic);
3256
3257   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3258     {
3259       if (resultInF0)
3260           emitcode ("mov", "c,F0");
3261
3262       aopOp (IC_RESULT (ic), ic, FALSE);
3263       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3264       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3265     }
3266 }
3267
3268 /*-----------------------------------------------------------------*/
3269 /* resultRemat - result  is rematerializable                       */
3270 /*-----------------------------------------------------------------*/
3271 static int
3272 resultRemat (iCode * ic)
3273 {
3274   if (SKIP_IC (ic) || ic->op == IFX)
3275     return 0;
3276
3277   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3278     {
3279       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3280       if (sym->remat && !POINTER_SET (ic))
3281         return 1;
3282     }
3283
3284   return 0;
3285 }
3286
3287 /*-----------------------------------------------------------------*/
3288 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3289 /*-----------------------------------------------------------------*/
3290 static int
3291 regsCmp(void *p1, void *p2)
3292 {
3293   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3294 }
3295
3296 static bool
3297 inExcludeList (char *s)
3298 {
3299   const char *p = setFirstItem(options.excludeRegsSet);
3300
3301   if (p == NULL || STRCASECMP(p, "none") == 0)
3302     return FALSE;
3303
3304
3305   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3306 }
3307
3308 /*-----------------------------------------------------------------*/
3309 /* genFunction - generated code for function entry                 */
3310 /*-----------------------------------------------------------------*/
3311 static void
3312 genFunction (iCode * ic)
3313 {
3314   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3315   sym_link *ftype;
3316   bool     switchedPSW = FALSE;
3317   int      calleesaves_saved_register = -1;
3318   int      stackAdjust = sym->stack;
3319   int      accIsFree = sym->recvSize < 4;
3320   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3321   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3322
3323   _G.nRegsSaved = 0;
3324   /* create the function header */
3325   emitcode (";", "-----------------------------------------");
3326   emitcode (";", " function %s", sym->name);
3327   emitcode (";", "-----------------------------------------");
3328
3329   emitcode ("", "%s:", sym->rname);
3330   lineCurr->isLabel = 1;
3331   ftype = operandType (IC_LEFT (ic));
3332   _G.currentFunc = sym;
3333
3334   if (IFFUNC_ISNAKED(ftype))
3335   {
3336       emitcode(";", "naked function: no prologue.");
3337       return;
3338   }
3339
3340   /* here we need to generate the equates for the
3341      register bank if required */
3342   if (FUNC_REGBANK (ftype) != rbank)
3343     {
3344       int i;
3345
3346       rbank = FUNC_REGBANK (ftype);
3347       for (i = 0; i < mcs51_nRegs; i++)
3348         {
3349           if (regs8051[i].type != REG_BIT)
3350             {
3351               if (strcmp (regs8051[i].base, "0") == 0)
3352                 emitcode ("", "%s = 0x%02x",
3353                           regs8051[i].dname,
3354                           8 * rbank + regs8051[i].offset);
3355               else
3356                 emitcode ("", "%s = %s + 0x%02x",
3357                           regs8051[i].dname,
3358                           regs8051[i].base,
3359                           8 * rbank + regs8051[i].offset);
3360             }
3361         }
3362     }
3363
3364   /* if this is an interrupt service routine then
3365      save acc, b, dpl, dph  */
3366   if (IFFUNC_ISISR (sym->type))
3367     {
3368       bitVect *rsavebits;
3369
3370       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3371       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3372         {
3373           emitcode ("push", "bits");
3374           BitBankUsed = 1;
3375         }
3376       freeBitVect (rsavebits);
3377
3378       if (!inExcludeList ("acc"))
3379         emitcode ("push", "acc");
3380       if (!inExcludeList ("b"))
3381         emitcode ("push", "b");
3382       if (!inExcludeList ("dpl"))
3383         emitcode ("push", "dpl");
3384       if (!inExcludeList ("dph"))
3385         emitcode ("push", "dph");
3386       /* if this isr has no bank i.e. is going to
3387          run with bank 0 , then we need to save more
3388          registers :-) */
3389       if (!FUNC_REGBANK (sym->type))
3390         {
3391           int i;
3392
3393           /* if this function does not call any other
3394              function then we can be economical and
3395              save only those registers that are used */
3396           if (!IFFUNC_HASFCALL(sym->type))
3397             {
3398               /* if any registers used */
3399               if (sym->regsUsed)
3400                 {
3401                   /* save the registers used */
3402                   for (i = 0; i < sym->regsUsed->size; i++)
3403                     {
3404                       if (bitVectBitValue (sym->regsUsed, i))
3405                         pushReg (i, TRUE);
3406                     }
3407                 }
3408             }
3409           else
3410             {
3411               /* this function has a function call. We cannot
3412                  determine register usage so we will have to push the
3413                  entire bank */
3414                 saveRBank (0, ic, FALSE);
3415                 if (options.parms_in_bank1) {
3416                     for (i=0; i < 8 ; i++ ) {
3417                         emitcode ("push","%s",rb1regs[i]);
3418                     }
3419                 }
3420             }
3421         }
3422       else
3423         {
3424             /* This ISR uses a non-zero bank.
3425              *
3426              * We assume that the bank is available for our
3427              * exclusive use.
3428              *
3429              * However, if this ISR calls a function which uses some
3430              * other bank, we must save that bank entirely.
3431              */
3432             unsigned long banksToSave = 0;
3433
3434             if (IFFUNC_HASFCALL(sym->type))
3435             {
3436
3437 #define MAX_REGISTER_BANKS 4
3438
3439                 iCode *i;
3440                 int ix;
3441
3442                 for (i = ic; i; i = i->next)
3443                 {
3444                     if (i->op == ENDFUNCTION)
3445                     {
3446                         /* we got to the end OK. */
3447                         break;
3448                     }
3449
3450                     if (i->op == CALL)
3451                     {
3452                         sym_link *dtype;
3453
3454                         dtype = operandType (IC_LEFT(i));
3455                         if (dtype
3456                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3457                         {
3458                              /* Mark this bank for saving. */
3459                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3460                              {
3461                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3462                              }
3463                              else
3464                              {
3465                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3466                              }
3467
3468                              /* And note that we don't need to do it in
3469                               * genCall.
3470                               */
3471                              i->bankSaved = 1;
3472                         }
3473                     }
3474                     if (i->op == PCALL)
3475                     {
3476                         /* This is a mess; we have no idea what
3477                          * register bank the called function might
3478                          * use.
3479                          *
3480                          * The only thing I can think of to do is
3481                          * throw a warning and hope.
3482                          */
3483                         werror(W_FUNCPTR_IN_USING_ISR);
3484                     }
3485                 }
3486
3487                 if (banksToSave && options.useXstack)
3488                 {
3489                     /* Since we aren't passing it an ic,
3490                      * saveRBank will assume r0 is available to abuse.
3491                      *
3492                      * So switch to our (trashable) bank now, so
3493                      * the caller's R0 isn't trashed.
3494                      */
3495                     emitcode ("push", "psw");
3496                     emitcode ("mov", "psw,#0x%02x",
3497                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3498                     switchedPSW = TRUE;
3499                 }
3500
3501                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3502                 {
3503                      if (banksToSave & (1 << ix))
3504                      {
3505                          saveRBank(ix, NULL, FALSE);
3506                      }
3507                 }
3508             }
3509             // TODO: this needs a closer look
3510             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3511         }
3512
3513       /* Set the register bank to the desired value if nothing else */
3514       /* has done so yet. */
3515       if (!switchedPSW)
3516         {
3517           emitcode ("push", "psw");
3518           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3519         }
3520     }
3521   else
3522     {
3523       /* This is a non-ISR function. The caller has already switched register */
3524       /* banks, if necessary, so just handle the callee-saves option. */
3525
3526       /* if callee-save to be used for this function
3527          then save the registers being used in this function */
3528       if (IFFUNC_CALLEESAVES(sym->type))
3529         {
3530           int i;
3531
3532           /* if any registers used */
3533           if (sym->regsUsed)
3534             {
3535               bool bits_pushed = FALSE;
3536               /* save the registers used */
3537               for (i = 0; i < sym->regsUsed->size; i++)
3538                 {
3539                   if (bitVectBitValue (sym->regsUsed, i))
3540                     {
3541                       /* remember one saved register for later usage */
3542                       if (calleesaves_saved_register < 0)
3543                         calleesaves_saved_register = i;
3544                       bits_pushed = pushReg (i, bits_pushed);
3545                       _G.nRegsSaved++;
3546                     }
3547                 }
3548             }
3549         }
3550     }
3551
3552   if (fReentrant)
3553     {
3554       if (options.useXstack)
3555         {
3556           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3557             {
3558               emitcode ("mov", "r0,%s", spname);
3559               emitcode ("inc", "%s", spname);
3560               emitcode ("xch", "a,_bpx");
3561               emitcode ("movx", "@r0,a");
3562               emitcode ("inc", "r0");
3563               emitcode ("mov", "a,r0");
3564               emitcode ("xch", "a,_bpx");
3565             }
3566           if (sym->stack)
3567             {
3568               emitcode ("push", "_bp");     /* save the callers stack  */
3569               emitcode ("mov", "_bp,sp");
3570             }
3571         }
3572       else
3573         {
3574           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3575             {
3576               /* set up the stack */
3577               emitcode ("push", "_bp");     /* save the callers stack  */
3578               emitcode ("mov", "_bp,sp");
3579             }
3580         }
3581     }
3582
3583   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3584   /* before setting up the stack frame completely. */
3585   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3586     {
3587       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3588
3589       if (rsym->isitmp)
3590         {
3591           if (rsym && rsym->regType == REG_CND)
3592             rsym = NULL;
3593           if (rsym && (rsym->accuse || rsym->ruonly))
3594             rsym = NULL;
3595           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3596             rsym = rsym->usl.spillLoc;
3597         }
3598
3599       /* If the RECEIVE operand immediately spills to the first entry on the */
3600       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3601       /* rather than the usual @r0/r1 machinations. */
3602       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3603         {
3604           int ofs;
3605
3606           _G.current_iCode = ric;
3607           D(emitcode (";", "genReceive"));
3608           for (ofs=0; ofs < sym->recvSize; ofs++)
3609             {
3610               if (!strcmp (fReturn[ofs], "a"))
3611                 emitcode ("push", "acc");
3612               else
3613                 emitcode ("push", fReturn[ofs]);
3614             }
3615           stackAdjust -= sym->recvSize;
3616           if (stackAdjust<0)
3617             {
3618               assert (stackAdjust>=0);
3619               stackAdjust = 0;
3620             }
3621           _G.current_iCode = ic;
3622           ric->generated = 1;
3623           accIsFree = 1;
3624         }
3625       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3626       /* to free up the accumulator. */
3627       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3628         {
3629           int ofs;
3630
3631           _G.current_iCode = ric;
3632           D(emitcode (";", "genReceive"));
3633           for (ofs=0; ofs < sym->recvSize; ofs++)
3634             {
3635               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3636             }
3637           _G.current_iCode = ic;
3638           ric->generated = 1;
3639           accIsFree = 1;
3640         }
3641     }
3642
3643   /* adjust the stack for the function */
3644   if (stackAdjust)
3645     {
3646       int i = stackAdjust;
3647       if (i > 256)
3648         werror (W_STACK_OVERFLOW, sym->name);
3649
3650       if (i > 3 && accIsFree)
3651         {
3652           emitcode ("mov", "a,sp");
3653           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3654           emitcode ("mov", "sp,a");
3655         }
3656       else if (i > 5)
3657         {
3658           /* The accumulator is not free, so we will need another register */
3659           /* to clobber. No need to worry about a possible conflict with */
3660           /* the above early RECEIVE optimizations since they would have */
3661           /* freed the accumulator if they were generated. */
3662
3663           if (IFFUNC_CALLEESAVES(sym->type))
3664             {
3665               /* if it's a callee-saves function we need a saved register */
3666               if (calleesaves_saved_register >= 0)
3667                 {
3668                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3669                   emitcode ("mov", "a,sp");
3670                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3671                   emitcode ("mov", "sp,a");
3672                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3673                 }
3674               else
3675                 /* do it the hard way */
3676                 while (i--)
3677                   emitcode ("inc", "sp");
3678             }
3679           else
3680             {
3681               /* not callee-saves, we can clobber r0 */
3682               emitcode ("mov", "r0,a");
3683               emitcode ("mov", "a,sp");
3684               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3685               emitcode ("mov", "sp,a");
3686               emitcode ("mov", "a,r0");
3687             }
3688         }
3689       else
3690         while (i--)
3691           emitcode ("inc", "sp");
3692     }
3693
3694   if (sym->xstack)
3695     {
3696       char i = ((char) sym->xstack & 0xff);
3697
3698       if (i > 3 && accIsFree)
3699         {
3700           emitcode ("mov", "a,_spx");
3701           emitcode ("add", "a,#0x%02x", i & 0xff);
3702           emitcode ("mov", "_spx,a");
3703         }
3704       else if (i > 5)
3705         {
3706           emitcode ("push", "acc");
3707           emitcode ("mov", "a,_spx");
3708           emitcode ("add", "a,#0x%02x", i & 0xff);
3709           emitcode ("mov", "_spx,a");
3710           emitcode ("pop", "acc");
3711         }
3712       else
3713         {
3714           while (i--)
3715             emitcode ("inc", "_spx");
3716         }
3717     }
3718
3719   /* if critical function then turn interrupts off */
3720   if (IFFUNC_ISCRITICAL (ftype))
3721     {
3722       symbol *tlbl = newiTempLabel (NULL);
3723       emitcode ("setb", "c");
3724       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3725       emitcode ("clr", "c");
3726       emitLabel (tlbl);
3727       emitcode ("push", "psw"); /* save old ea via c in psw */
3728     }
3729 }
3730
3731 /*-----------------------------------------------------------------*/
3732 /* genEndFunction - generates epilogue for functions               */
3733 /*-----------------------------------------------------------------*/
3734 static void
3735 genEndFunction (iCode * ic)
3736 {
3737   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3738   lineNode *lnp = lineCurr;
3739   bitVect  *regsUsed;
3740   bitVect  *regsUsedPrologue;
3741   bitVect  *regsUnneeded;
3742   int      idx;
3743
3744   _G.currentFunc = NULL;
3745   if (IFFUNC_ISNAKED(sym->type))
3746   {
3747       emitcode(";", "naked function: no epilogue.");
3748       if (options.debug && currFunc)
3749         debugFile->writeEndFunction (currFunc, ic, 0);
3750       return;
3751   }
3752
3753   if (IFFUNC_ISCRITICAL (sym->type))
3754     {
3755       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3756         {
3757           emitcode ("rlc", "a");   /* save c in a */
3758           emitcode ("pop", "psw"); /* restore ea via c in psw */
3759           emitcode ("mov", "ea,c");
3760           emitcode ("rrc", "a");   /* restore c from a */
3761         }
3762       else
3763         {
3764           emitcode ("pop", "psw"); /* restore ea via c in psw */
3765           emitcode ("mov", "ea,c");
3766         }
3767     }
3768
3769   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3770     {
3771       if (options.useXstack)
3772         {
3773           if (sym->stack)
3774             {
3775               emitcode ("mov", "sp,_bp");
3776               emitcode ("pop", "_bp");
3777             }
3778           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3779             {
3780               emitcode ("xch", "a,_bpx");
3781               emitcode ("mov", "r0,a");
3782               emitcode ("dec", "r0");
3783               emitcode ("movx", "a,@r0");
3784               emitcode ("xch", "a,_bpx");
3785               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3786             }
3787         }
3788       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3789         {
3790           if (sym->stack)
3791             emitcode ("mov", "sp,_bp");
3792           emitcode ("pop", "_bp");
3793         }
3794     }
3795
3796   /* restore the register bank  */
3797   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3798   {
3799     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3800      || !options.useXstack)
3801     {
3802         /* Special case of ISR using non-zero bank with useXstack
3803          * is handled below.
3804          */
3805         emitcode ("pop", "psw");
3806     }
3807   }
3808
3809   if (IFFUNC_ISISR (sym->type))
3810     {
3811       bitVect *rsavebits;
3812
3813       /* now we need to restore the registers */
3814       /* if this isr has no bank i.e. is going to
3815          run with bank 0 , then we need to save more
3816          registers :-) */
3817       if (!FUNC_REGBANK (sym->type))
3818         {
3819           int i;
3820           /* if this function does not call any other
3821              function then we can be economical and
3822              save only those registers that are used */
3823           if (!IFFUNC_HASFCALL(sym->type))
3824             {
3825               /* if any registers used */
3826               if (sym->regsUsed)
3827                 {
3828                   /* save the registers used */
3829                   for (i = sym->regsUsed->size; i >= 0; i--)
3830                     {
3831                       if (bitVectBitValue (sym->regsUsed, i))
3832                         popReg (i, TRUE);
3833                     }
3834                 }
3835             }
3836           else
3837             {
3838               if (options.parms_in_bank1) {
3839                   for (i = 7 ; i >= 0 ; i-- ) {
3840                       emitcode ("pop","%s",rb1regs[i]);
3841                   }
3842               }
3843               /* this function has a function call. We cannot
3844                  determine register usage so we will have to pop the
3845                  entire bank */
3846               unsaveRBank (0, ic, FALSE);
3847             }
3848         }
3849         else
3850         {
3851             /* This ISR uses a non-zero bank.
3852              *
3853              * Restore any register banks saved by genFunction
3854              * in reverse order.
3855              */
3856             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3857             int ix;
3858
3859             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3860             {
3861                 if (savedBanks & (1 << ix))
3862                 {
3863                     unsaveRBank(ix, NULL, FALSE);
3864                 }
3865             }
3866
3867             if (options.useXstack)
3868             {
3869                 /* Restore bank AFTER calling unsaveRBank,
3870                  * since it can trash r0.
3871                  */
3872                 emitcode ("pop", "psw");
3873             }
3874         }
3875
3876       if (!inExcludeList ("dph"))
3877         emitcode ("pop", "dph");
3878       if (!inExcludeList ("dpl"))
3879         emitcode ("pop", "dpl");
3880       if (!inExcludeList ("b"))
3881         emitcode ("pop", "b");
3882       if (!inExcludeList ("acc"))
3883         emitcode ("pop", "acc");
3884
3885       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3886       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3887         emitcode ("pop", "bits");
3888       freeBitVect (rsavebits);
3889
3890       /* if debug then send end of function */
3891       if (options.debug && currFunc)
3892         {
3893           debugFile->writeEndFunction (currFunc, ic, 1);
3894         }
3895
3896       emitcode ("reti", "");
3897     }
3898   else
3899     {
3900       if (IFFUNC_CALLEESAVES(sym->type))
3901         {
3902           int i;
3903
3904           /* if any registers used */
3905           if (sym->regsUsed)
3906             {
3907               /* save the registers used */
3908               for (i = sym->regsUsed->size; i >= 0; i--)
3909                 {
3910                   if (bitVectBitValue (sym->regsUsed, i) ||
3911                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3912                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3913                 }
3914             }
3915           else if (mcs51_ptrRegReq)
3916             {
3917               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3918               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3919             }
3920
3921         }
3922
3923       /* if debug then send end of function */
3924       if (options.debug && currFunc)
3925         {
3926           debugFile->writeEndFunction (currFunc, ic, 1);
3927         }
3928
3929       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3930         {
3931           emitcode ("ljmp", "__sdcc_banked_ret");
3932         }
3933       else
3934         {
3935           emitcode ("ret", "");
3936         }
3937     }
3938
3939   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3940     return;
3941
3942   /* If this was an interrupt handler using bank 0 that called another */
3943   /* function, then all registers must be saved; nothing to optimized. */
3944   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3945       && !FUNC_REGBANK(sym->type))
3946     return;
3947
3948   /* There are no push/pops to optimize if not callee-saves or ISR */
3949   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3950     return;
3951
3952   /* If there were stack parameters, we cannot optimize without also    */
3953   /* fixing all of the stack offsets; this is too dificult to consider. */
3954   if (FUNC_HASSTACKPARM(sym->type))
3955     return;
3956
3957   /* Compute the registers actually used */
3958   regsUsed = newBitVect (mcs51_nRegs);
3959   regsUsedPrologue = newBitVect (mcs51_nRegs);
3960   while (lnp)
3961     {
3962       if (lnp->ic && lnp->ic->op == FUNCTION)
3963         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3964       else
3965         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3966
3967       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3968           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3969         break;
3970       if (!lnp->prev)
3971         break;
3972       lnp = lnp->prev;
3973     }
3974
3975   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3976       && !bitVectBitValue (regsUsed, CND_IDX))
3977     {
3978       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3979       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3980           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3981         bitVectUnSetBit (regsUsed, CND_IDX);
3982     }
3983   else
3984     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3985
3986   /* If this was an interrupt handler that called another function */
3987   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3988   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3989     {
3990       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3991       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3992       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3993       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3995     }
3996
3997   /* Remove the unneeded push/pops */
3998   regsUnneeded = newBitVect (mcs51_nRegs);
3999   while (lnp)
4000     {
4001       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4002         {
4003           if (!strncmp(lnp->line, "push", 4))
4004             {
4005               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4006               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4007                 {
4008                   connectLine (lnp->prev, lnp->next);
4009                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4010                 }
4011             }
4012           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4013             {
4014               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4015               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4016                 {
4017                   connectLine (lnp->prev, lnp->next);
4018                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4019                 }
4020             }
4021         }
4022       lnp = lnp->next;
4023     }
4024
4025   for (idx = 0; idx < regsUnneeded->size; idx++)
4026     if (bitVectBitValue (regsUnneeded, idx))
4027       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4028
4029   freeBitVect (regsUnneeded);
4030   freeBitVect (regsUsed);
4031   freeBitVect (regsUsedPrologue);
4032 }
4033
4034 /*-----------------------------------------------------------------*/
4035 /* genRet - generate code for return statement                     */
4036 /*-----------------------------------------------------------------*/
4037 static void
4038 genRet (iCode * ic)
4039 {
4040   int size, offset = 0, pushed = 0;
4041
4042   D (emitcode (";", "genRet"));
4043
4044   /* if we have no return value then
4045      just generate the "ret" */
4046   if (!IC_LEFT (ic))
4047     goto jumpret;
4048
4049   /* we have something to return then
4050      move the return value into place */
4051   aopOp (IC_LEFT (ic), ic, FALSE);
4052   size = AOP_SIZE (IC_LEFT (ic));
4053
4054   if (IS_BIT(_G.currentFunc->etype))
4055     {
4056       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4057         toCarry (IC_LEFT (ic));
4058     }
4059   else
4060     {
4061       while (size--)
4062         {
4063           char *l;
4064           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4065             {
4066               /* #NOCHANGE */
4067               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4068               emitcode ("push", "%s", l);
4069               pushed++;
4070             }
4071           else
4072             {
4073               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4074               if (strcmp (fReturn[offset], l))
4075                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4076             }
4077         }
4078
4079       while (pushed)
4080         {
4081           pushed--;
4082           if (strcmp (fReturn[pushed], "a"))
4083             emitcode ("pop", fReturn[pushed]);
4084           else
4085             emitcode ("pop", "acc");
4086         }
4087     }
4088   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4089
4090 jumpret:
4091   /* generate a jump to the return label
4092      if the next is not the return statement */
4093   if (!(ic->next && ic->next->op == LABEL &&
4094         IC_LABEL (ic->next) == returnLabel))
4095
4096     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4097
4098 }
4099
4100 /*-----------------------------------------------------------------*/
4101 /* genLabel - generates a label                                    */
4102 /*-----------------------------------------------------------------*/
4103 static void
4104 genLabel (iCode * ic)
4105 {
4106   /* special case never generate */
4107   if (IC_LABEL (ic) == entryLabel)
4108     return;
4109
4110   emitLabel (IC_LABEL (ic));
4111 }
4112
4113 /*-----------------------------------------------------------------*/
4114 /* genGoto - generates a ljmp                                      */
4115 /*-----------------------------------------------------------------*/
4116 static void
4117 genGoto (iCode * ic)
4118 {
4119   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4120 }
4121
4122 /*-----------------------------------------------------------------*/
4123 /* findLabelBackwards: walks back through the iCode chain looking  */
4124 /* for the given label. Returns number of iCode instructions     */
4125 /* between that label and given ic.          */
4126 /* Returns zero if label not found.          */
4127 /*-----------------------------------------------------------------*/
4128 static int
4129 findLabelBackwards (iCode * ic, int key)
4130 {
4131   int count = 0;
4132
4133   while (ic->prev)
4134     {
4135       ic = ic->prev;
4136       count++;
4137
4138       /* If we have any pushes or pops, we cannot predict the distance.
4139          I don't like this at all, this should be dealt with in the
4140          back-end */
4141       if (ic->op == IPUSH || ic->op == IPOP) {
4142         return 0;
4143       }
4144
4145       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4146         {
4147           return count;
4148         }
4149     }
4150
4151   return 0;
4152 }
4153
4154 /*-----------------------------------------------------------------*/
4155 /* genPlusIncr :- does addition with increment if possible         */
4156 /*-----------------------------------------------------------------*/
4157 static bool
4158 genPlusIncr (iCode * ic)
4159 {
4160   unsigned int icount;
4161   unsigned int size = getDataSize (IC_RESULT (ic));
4162
4163   /* will try to generate an increment */
4164   /* if the right side is not a literal
4165      we cannot */
4166   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4167     return FALSE;
4168
4169   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4170
4171   D(emitcode (";","genPlusIncr"));
4172
4173   /* if increment >=16 bits in register or direct space */
4174   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4175         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4176         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4177       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4178       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4179       (size > 1) &&
4180       (icount == 1))
4181     {
4182       symbol *tlbl;
4183       int emitTlbl;
4184       int labelRange;
4185
4186       /* If the next instruction is a goto and the goto target
4187        * is < 10 instructions previous to this, we can generate
4188        * jumps straight to that target.
4189        */
4190       if (ic->next && ic->next->op == GOTO
4191           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4192           && labelRange <= 10)
4193         {
4194           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4195           tlbl = IC_LABEL (ic->next);
4196           emitTlbl = 0;
4197         }
4198       else
4199         {
4200           tlbl = newiTempLabel (NULL);
4201           emitTlbl = 1;
4202         }
4203       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4204       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4205           IS_AOP_PREG (IC_RESULT (ic)))
4206         emitcode ("cjne", "%s,#0x00,%05d$",
4207                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4208                   tlbl->key + 100);
4209       else
4210         {
4211           emitcode ("clr", "a");
4212           emitcode ("cjne", "a,%s,%05d$",
4213                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4214                     tlbl->key + 100);
4215         }
4216
4217       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4218       if (size > 2)
4219         {
4220           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4221               IS_AOP_PREG (IC_RESULT (ic)))
4222             emitcode ("cjne", "%s,#0x00,%05d$",
4223                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4224                       tlbl->key + 100);
4225           else
4226             emitcode ("cjne", "a,%s,%05d$",
4227                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4228                       tlbl->key + 100);
4229
4230           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4231         }
4232       if (size > 3)
4233         {
4234           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4235               IS_AOP_PREG (IC_RESULT (ic)))
4236             emitcode ("cjne", "%s,#0x00,%05d$",
4237                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4238                       tlbl->key + 100);
4239           else
4240             {
4241               emitcode ("cjne", "a,%s,%05d$",
4242                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4243                         tlbl->key + 100);
4244             }
4245           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4246         }
4247
4248       if (emitTlbl)
4249         {
4250           emitLabel (tlbl);
4251         }
4252       return TRUE;
4253     }
4254
4255   /* if result is dptr */
4256   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4257       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4258       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4259       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4260     {
4261       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4262         return FALSE;
4263
4264       if (icount > 9)
4265         return FALSE;
4266
4267       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4268         return FALSE;
4269
4270       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4271       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4272       while (icount--)
4273         emitcode ("inc", "dptr");
4274
4275       return TRUE;
4276     }
4277
4278   /* if the literal value of the right hand side
4279      is greater than 4 then it is not worth it */
4280   if (icount > 4)
4281     return FALSE;
4282
4283   /* if the sizes are greater than 1 then we cannot */
4284   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4285       AOP_SIZE (IC_LEFT (ic)) > 1)
4286     return FALSE;
4287
4288   /* we can if the aops of the left & result match or
4289      if they are in registers and the registers are the
4290      same */
4291   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4292     {
4293       if (icount > 3)
4294         {
4295           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4296           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4297           aopPut (IC_RESULT (ic), "a", 0);
4298         }
4299       else
4300         {
4301           while (icount--)
4302             {
4303               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4304             }
4305         }
4306
4307       return TRUE;
4308     }
4309
4310   if (icount == 1)
4311     {
4312       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4313       emitcode ("inc", "a");
4314       aopPut (IC_RESULT (ic), "a", 0);
4315       return TRUE;
4316     }
4317
4318   return FALSE;
4319 }
4320
4321 /*-----------------------------------------------------------------*/
4322 /* outBitAcc - output a bit in acc                                 */
4323 /*-----------------------------------------------------------------*/
4324 static void
4325 outBitAcc (operand * result)
4326 {
4327   symbol *tlbl = newiTempLabel (NULL);
4328   /* if the result is a bit */
4329   if (AOP_TYPE (result) == AOP_CRY)
4330     {
4331       aopPut (result, "a", 0);
4332     }
4333   else
4334     {
4335       emitcode ("jz", "%05d$", tlbl->key + 100);
4336       emitcode ("mov", "a,%s", one);
4337       emitLabel (tlbl);
4338       outAcc (result);
4339     }
4340 }
4341
4342 /*-----------------------------------------------------------------*/
4343 /* genPlusBits - generates code for addition of two bits           */
4344 /*-----------------------------------------------------------------*/
4345 static void
4346 genPlusBits (iCode * ic)
4347 {
4348   D (emitcode (";", "genPlusBits"));
4349
4350   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4351   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4352     {
4353       symbol *lbl = newiTempLabel (NULL);
4354       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4355       emitcode ("cpl", "c");
4356       emitLabel (lbl);
4357       outBitC (IC_RESULT (ic));
4358     }
4359   else
4360     {
4361       emitcode ("clr", "a");
4362       emitcode ("rlc", "a");
4363       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4364       emitcode ("addc", "a,%s", zero);
4365       outAcc (IC_RESULT (ic));
4366     }
4367 }
4368
4369 #if 0
4370 /* This is the original version of this code.
4371
4372  * This is being kept around for reference,
4373  * because I am not entirely sure I got it right...
4374  */
4375 static void
4376 adjustArithmeticResult (iCode * ic)
4377 {
4378   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4379       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4380       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4381     aopPut (IC_RESULT (ic),
4382             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4383             2);
4384
4385   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4386       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4387       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4388     aopPut (IC_RESULT (ic),
4389             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4390             2);
4391
4392   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4393       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4394       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4395       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4396       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4397     {
4398       char buffer[5];
4399       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4400       aopPut (IC_RESULT (ic), buffer, 2);
4401     }
4402 }
4403 #else
4404 /* This is the pure and virtuous version of this code.
4405  * I'm pretty certain it's right, but not enough to toss the old
4406  * code just yet...
4407  */
4408 static void
4409 adjustArithmeticResult (iCode * ic)
4410 {
4411   if (opIsGptr (IC_RESULT (ic)) &&
4412       opIsGptr (IC_LEFT (ic)) &&
4413       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4414     {
4415       aopPut (IC_RESULT (ic),
4416               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4417               GPTRSIZE - 1);
4418     }
4419
4420   if (opIsGptr (IC_RESULT (ic)) &&
4421       opIsGptr (IC_RIGHT (ic)) &&
4422       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4423     {
4424       aopPut (IC_RESULT (ic),
4425               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4426               GPTRSIZE - 1);
4427     }
4428
4429   if (opIsGptr (IC_RESULT (ic)) &&
4430       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4431       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4432       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4433       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4434     {
4435       char buffer[5];
4436       SNPRINTF (buffer, sizeof(buffer),
4437                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4438       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4439     }
4440 }
4441 #endif
4442
4443 /*-----------------------------------------------------------------*/
4444 /* genPlus - generates code for addition                           */
4445 /*-----------------------------------------------------------------*/
4446 static void
4447 genPlus (iCode * ic)
4448 {
4449   int size, offset = 0;
4450   int skip_bytes = 0;
4451   char *add = "add";
4452   bool swappedLR = FALSE;
4453   operand *leftOp, *rightOp;
4454   operand * op;
4455
4456   D (emitcode (";", "genPlus"));
4457
4458   /* special cases :- */
4459
4460   aopOp (IC_LEFT (ic), ic, FALSE);
4461   aopOp (IC_RIGHT (ic), ic, FALSE);
4462   aopOp (IC_RESULT (ic), ic, TRUE);
4463
4464   /* if literal, literal on the right or
4465      if left requires ACC or right is already
4466      in ACC */
4467   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4468       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4469       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4470     {
4471       operand *t = IC_RIGHT (ic);
4472       IC_RIGHT (ic) = IC_LEFT (ic);
4473       IC_LEFT (ic) = t;
4474       swappedLR = TRUE;
4475     }
4476
4477   /* if both left & right are in bit
4478      space */
4479   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4480       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4481     {
4482       genPlusBits (ic);
4483       goto release;
4484     }
4485
4486   /* if left in bit space & right literal */
4487   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4488       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4489     {
4490       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4491       /* if result in bit space */
4492       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4493         {
4494           if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4495             emitcode ("cpl", "c");
4496           outBitC (IC_RESULT (ic));
4497         }
4498       else
4499         {
4500           size = getDataSize (IC_RESULT (ic));
4501           while (size--)
4502             {
4503               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4504               emitcode ("addc", "a,%s", zero);
4505               aopPut (IC_RESULT (ic), "a", offset++);
4506             }
4507         }
4508       goto release;
4509     }
4510
4511   /* if I can do an increment instead
4512      of add then GOOD for ME */
4513   if (genPlusIncr (ic) == TRUE)
4514     goto release;
4515
4516   size = getDataSize (IC_RESULT (ic));
4517   leftOp = IC_LEFT(ic);
4518   rightOp = IC_RIGHT(ic);
4519   op = IC_LEFT(ic);
4520
4521   /* if this is an add for an array access
4522      at a 256 byte boundary */
4523   if ( 2 == size
4524        && AOP_TYPE (op) == AOP_IMMD
4525        && IS_SYMOP (op)
4526        && IS_SPEC (OP_SYM_ETYPE (op))
4527        && SPEC_ABSA (OP_SYM_ETYPE (op))
4528        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4529      )
4530     {
4531       D(emitcode (";", "genPlus aligned array"));
4532       aopPut (IC_RESULT (ic),
4533               aopGet (rightOp, 0, FALSE, FALSE),
4534               0);
4535
4536       if( 1 == getDataSize (IC_RIGHT (ic)) )
4537         {
4538           aopPut (IC_RESULT (ic),
4539                   aopGet (leftOp, 1, FALSE, FALSE),
4540                   1);
4541         }
4542       else
4543         {
4544           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4545           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4546           aopPut (IC_RESULT (ic), "a", 1);
4547         }
4548       goto release;
4549     }
4550
4551   /* if the lower bytes of a literal are zero skip the addition */
4552   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4553     {
4554        while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4555               (skip_bytes+1 < size))
4556          {
4557            skip_bytes++;
4558          }
4559        if (skip_bytes)
4560          D(emitcode (";", "genPlus shortcut"));
4561     }
4562
4563   while (size--)
4564     {
4565       if( offset >= skip_bytes )
4566         {
4567           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4568             {
4569               bool pushedB;
4570               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4571               pushedB = pushB ();
4572               emitcode("xch", "a,b");
4573               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4574               emitcode (add, "a,b");
4575               popB (pushedB);
4576             }
4577           else if (aopGetUsesAcc (leftOp, offset))
4578             {
4579               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4580               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4581             }
4582           else
4583             {
4584               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4585               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4586             }
4587           aopPut (IC_RESULT (ic), "a", offset);
4588           add = "addc";  /* further adds must propagate carry */
4589         }
4590       else
4591         {
4592           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4593               isOperandVolatile (IC_RESULT (ic), FALSE))
4594             {
4595               /* just move */
4596               aopPut (IC_RESULT (ic),
4597                       aopGet (leftOp, offset, FALSE, FALSE),
4598                       offset);
4599             }
4600         }
4601       offset++;
4602     }
4603
4604   adjustArithmeticResult (ic);
4605
4606 release:
4607   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4608   if (!swappedLR)
4609     {
4610       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4611       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4612     }
4613   else
4614     {
4615       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4616       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4617     }
4618 }
4619
4620 /*-----------------------------------------------------------------*/
4621 /* genMinusDec :- does subtraction with decrement if possible      */
4622 /*-----------------------------------------------------------------*/
4623 static bool
4624 genMinusDec (iCode * ic)
4625 {
4626   unsigned int icount;
4627   unsigned int size = getDataSize (IC_RESULT (ic));
4628
4629   /* will try to generate an increment */
4630   /* if the right side is not a literal
4631      we cannot */
4632   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4633     return FALSE;
4634
4635   /* if the literal value of the right hand side
4636      is greater than 4 then it is not worth it */
4637   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4638     return FALSE;
4639
4640   D (emitcode (";", "genMinusDec"));
4641
4642   /* if decrement >=16 bits in register or direct space */
4643   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4644         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4645         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4646       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4647       (size > 1) &&
4648       (icount == 1))
4649     {
4650       symbol *tlbl;
4651       int emitTlbl;
4652       int labelRange;
4653
4654       /* If the next instruction is a goto and the goto target
4655        * is <= 10 instructions previous to this, we can generate
4656        * jumps straight to that target.
4657        */
4658       if (ic->next && ic->next->op == GOTO
4659           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4660           && labelRange <= 10)
4661         {
4662           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4663           tlbl = IC_LABEL (ic->next);
4664           emitTlbl = 0;
4665         }
4666       else
4667         {
4668           tlbl = newiTempLabel (NULL);
4669           emitTlbl = 1;
4670         }
4671
4672       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4673       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4674           IS_AOP_PREG (IC_RESULT (ic)))
4675         emitcode ("cjne", "%s,#0xff,%05d$"
4676                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4677                   ,tlbl->key + 100);
4678       else
4679         {
4680           emitcode ("mov", "a,#0xff");
4681           emitcode ("cjne", "a,%s,%05d$"
4682                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4683                     ,tlbl->key + 100);
4684         }
4685       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4686       if (size > 2)
4687         {
4688           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4689               IS_AOP_PREG (IC_RESULT (ic)))
4690             emitcode ("cjne", "%s,#0xff,%05d$"
4691                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4692                       ,tlbl->key + 100);
4693           else
4694             {
4695               emitcode ("cjne", "a,%s,%05d$"
4696                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4697                         ,tlbl->key + 100);
4698             }
4699           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4700         }
4701       if (size > 3)
4702         {
4703           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4704               IS_AOP_PREG (IC_RESULT (ic)))
4705             emitcode ("cjne", "%s,#0xff,%05d$"
4706                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4707                       ,tlbl->key + 100);
4708           else
4709             {
4710               emitcode ("cjne", "a,%s,%05d$"
4711                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4712                         ,tlbl->key + 100);
4713             }
4714           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4715         }
4716       if (emitTlbl)
4717         {
4718           emitLabel (tlbl);
4719         }
4720       return TRUE;
4721     }
4722
4723   /* if the sizes are greater than 1 then we cannot */
4724   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4725       AOP_SIZE (IC_LEFT (ic)) > 1)
4726     return FALSE;
4727
4728   /* we can if the aops of the left & result match or
4729      if they are in registers and the registers are the
4730      same */
4731   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4732     {
4733       char *l;
4734
4735       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4736         {
4737           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4738           l = "a";
4739         }
4740       else
4741         {
4742           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4743         }
4744
4745       while (icount--)
4746         {
4747           emitcode ("dec", "%s", l);
4748         }
4749
4750       if (AOP_NEEDSACC (IC_RESULT (ic)))
4751         aopPut (IC_RESULT (ic), "a", 0);
4752
4753       return TRUE;
4754     }
4755
4756   if (icount == 1)
4757     {
4758       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4759       emitcode ("dec", "a");
4760       aopPut (IC_RESULT (ic), "a", 0);
4761       return TRUE;
4762     }
4763
4764   return FALSE;
4765 }
4766
4767 /*-----------------------------------------------------------------*/
4768 /* addSign - complete with sign                                    */
4769 /*-----------------------------------------------------------------*/
4770 static void
4771 addSign (operand * result, int offset, int sign)
4772 {
4773   int size = (getDataSize (result) - offset);
4774   if (size > 0)
4775     {
4776       if (sign)
4777         {
4778           emitcode ("rlc", "a");
4779           emitcode ("subb", "a,acc");
4780           while (size--)
4781             {
4782               aopPut (result, "a", offset++);
4783             }
4784         }
4785       else
4786         {
4787           while (size--)
4788             {
4789               aopPut (result, zero, offset++);
4790             }
4791         }
4792     }
4793 }
4794
4795 /*-----------------------------------------------------------------*/
4796 /* genMinusBits - generates code for subtraction  of two bits      */
4797 /*-----------------------------------------------------------------*/
4798 static void
4799 genMinusBits (iCode * ic)
4800 {
4801   symbol *lbl = newiTempLabel (NULL);
4802
4803   D (emitcode (";", "genMinusBits"));
4804
4805   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4806     {
4807       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4808       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4809       emitcode ("cpl", "c");
4810       emitLabel (lbl);
4811       outBitC (IC_RESULT (ic));
4812     }
4813   else
4814     {
4815       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4816       emitcode ("subb", "a,acc");
4817       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4818       emitcode ("inc", "a");
4819       emitLabel (lbl);
4820       aopPut (IC_RESULT (ic), "a", 0);
4821       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4822     }
4823 }
4824
4825 /*-----------------------------------------------------------------*/
4826 /* genMinus - generates code for subtraction                       */
4827 /*-----------------------------------------------------------------*/
4828 static void
4829 genMinus (iCode * ic)
4830 {
4831   int size, offset = 0;
4832
4833   D (emitcode (";", "genMinus"));
4834
4835   aopOp (IC_LEFT (ic), ic, FALSE);
4836   aopOp (IC_RIGHT (ic), ic, FALSE);
4837   aopOp (IC_RESULT (ic), ic, TRUE);
4838
4839   /* special cases :- */
4840   /* if both left & right are in bit space */
4841   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4842       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4843     {
4844       genMinusBits (ic);
4845       goto release;
4846     }
4847
4848   /* if I can do an decrement instead
4849      of subtract then GOOD for ME */
4850   if (genMinusDec (ic) == TRUE)
4851     goto release;
4852
4853   size = getDataSize (IC_RESULT (ic));
4854
4855   /* if literal, add a,#-lit, else normal subb */
4856   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4857     {
4858       unsigned long lit = 0L;
4859       bool useCarry = FALSE;
4860
4861       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4862       lit = -(long) lit;
4863
4864       while (size--)
4865         {
4866           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4867             {
4868               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4869               if (!offset && !size && lit== (unsigned long) -1)
4870                 {
4871                   emitcode ("dec", "a");
4872                 }
4873               else if (!useCarry)
4874                 {
4875                   /* first add without previous c */
4876                   emitcode ("add", "a,#0x%02x",
4877                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4878                   useCarry = TRUE;
4879                 }
4880               else
4881                 {
4882                   emitcode ("addc", "a,#0x%02x",
4883                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4884                 }
4885               aopPut (IC_RESULT (ic), "a", offset++);
4886             }
4887           else
4888             {
4889               /* no need to add zeroes */
4890               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4891                 {
4892                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4893                           offset);
4894                 }
4895               offset++;
4896             }
4897         }
4898     }
4899   else
4900     {
4901       operand *leftOp, *rightOp;
4902
4903       leftOp = IC_LEFT(ic);
4904       rightOp = IC_RIGHT(ic);
4905
4906       while (size--)
4907         {
4908           if (aopGetUsesAcc(rightOp, offset)) {
4909             if (aopGetUsesAcc(leftOp, offset)) {
4910               bool pushedB;
4911
4912               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4913               pushedB = pushB ();
4914               emitcode ("mov", "b,a");
4915               if (offset == 0)
4916                 CLRC;
4917               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4918               emitcode ("subb", "a,b");
4919               popB (pushedB);
4920             } else {
4921               /* reverse subtraction with 2's complement */
4922               if (offset == 0)
4923                 emitcode( "setb", "c");
4924               else
4925                 emitcode( "cpl", "c");
4926               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4927               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4928               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4929               emitcode("cpl", "a");
4930               if (size) /* skip if last byte */
4931                 emitcode( "cpl", "c");
4932             }
4933           } else {
4934             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4935             if (offset == 0)
4936               CLRC;
4937             emitcode ("subb", "a,%s",
4938                       aopGet(rightOp, offset, FALSE, TRUE));
4939           }
4940
4941           aopPut (IC_RESULT (ic), "a", offset++);
4942         }
4943     }
4944
4945   adjustArithmeticResult (ic);
4946
4947 release:
4948   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4949   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4950   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4951 }
4952
4953
4954 /*-----------------------------------------------------------------*/
4955 /* genMultbits :- multiplication of bits                           */
4956 /*-----------------------------------------------------------------*/
4957 static void
4958 genMultbits (operand * left,
4959              operand * right,
4960              operand * result)
4961 {
4962   D (emitcode (";", "genMultbits"));
4963
4964   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4965   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4966   outBitC (result);
4967 }
4968
4969 /*-----------------------------------------------------------------*/
4970 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4971 /*-----------------------------------------------------------------*/
4972 static void
4973 genMultOneByte (operand * left,
4974                 operand * right,
4975                 operand * result)
4976 {
4977   symbol *lbl;
4978   int size = AOP_SIZE (result);
4979   bool runtimeSign, compiletimeSign;
4980   bool lUnsigned, rUnsigned, pushedB;
4981
4982   D (emitcode (";", "genMultOneByte"));
4983
4984   if (size < 1 || size > 2)
4985     {
4986       /* this should never happen */
4987       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4988                AOP_SIZE(result), __FILE__, lineno);
4989       exit (1);
4990     }
4991
4992   /* (if two literals: the value is computed before) */
4993   /* if one literal, literal on the right */
4994   if (AOP_TYPE (left) == AOP_LIT)
4995     {
4996       operand *t = right;
4997       right = left;
4998       left = t;
4999       /* emitcode (";", "swapped left and right"); */
5000     }
5001   /* if no literal, unsigned on the right: shorter code */
5002   if (   AOP_TYPE (right) != AOP_LIT
5003       && SPEC_USIGN (getSpec (operandType (left))))
5004     {
5005       operand *t = right;
5006       right = left;
5007       left = t;
5008     }
5009
5010   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5011   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5012
5013   pushedB = pushB ();
5014
5015   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5016                    no need to take care about the signedness! */
5017       || (lUnsigned && rUnsigned))
5018     {
5019       /* just an unsigned 8 * 8 = 8 multiply
5020          or 8u * 8u = 16u */
5021       /* emitcode (";","unsigned"); */
5022       /* TODO: check for accumulator clash between left & right aops? */
5023
5024       if (AOP_TYPE (right) == AOP_LIT)
5025         {
5026           /* moving to accumulator first helps peepholes */
5027           MOVA (aopGet (left, 0, FALSE, FALSE));
5028           MOVB (aopGet (right, 0, FALSE, FALSE));
5029         }
5030       else
5031         {
5032           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5033           MOVA (aopGet (left, 0, FALSE, FALSE));
5034         }
5035
5036       emitcode ("mul", "ab");
5037       aopPut (result, "a", 0);
5038       if (size == 2)
5039         aopPut (result, "b", 1);
5040
5041       popB (pushedB);
5042       return;
5043     }
5044
5045   /* we have to do a signed multiply */
5046   /* emitcode (";", "signed"); */
5047
5048   /* now sign adjust for both left & right */
5049
5050   /* let's see what's needed: */
5051   /* apply negative sign during runtime */
5052   runtimeSign = FALSE;
5053   /* negative sign from literals */
5054   compiletimeSign = FALSE;
5055
5056   if (!lUnsigned)
5057     {
5058       if (AOP_TYPE(left) == AOP_LIT)
5059         {
5060           /* signed literal */
5061           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5062           if (val < 0)
5063             compiletimeSign = TRUE;
5064         }
5065       else
5066         /* signed but not literal */
5067         runtimeSign = TRUE;
5068     }
5069
5070   if (!rUnsigned)
5071     {
5072       if (AOP_TYPE(right) == AOP_LIT)
5073         {
5074           /* signed literal */
5075           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5076           if (val < 0)
5077             compiletimeSign ^= TRUE;
5078         }
5079       else
5080         /* signed but not literal */
5081         runtimeSign = TRUE;
5082     }
5083
5084   /* initialize F0, which stores the runtime sign */
5085   if (runtimeSign)
5086     {
5087       if (compiletimeSign)
5088         emitcode ("setb", "F0"); /* set sign flag */
5089       else
5090         emitcode ("clr", "F0"); /* reset sign flag */
5091     }
5092
5093   /* save the signs of the operands */
5094   if (AOP_TYPE(right) == AOP_LIT)
5095     {
5096       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5097
5098       if (!rUnsigned && val < 0)
5099         emitcode ("mov", "b,#0x%02x", -val);
5100       else
5101         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5102     }
5103   else /* ! literal */
5104     {
5105       if (rUnsigned)  /* emitcode (";", "signed"); */
5106         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5107       else
5108         {
5109           MOVA (aopGet (right, 0, FALSE, FALSE));
5110           lbl = newiTempLabel (NULL);
5111           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5112           emitcode ("cpl", "F0"); /* complement sign flag */
5113           emitcode ("cpl", "a");  /* 2's complement */
5114           emitcode ("inc", "a");
5115           emitLabel (lbl);
5116           emitcode ("mov", "b,a");
5117         }
5118     }
5119
5120   if (AOP_TYPE(left) == AOP_LIT)
5121     {
5122       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5123
5124       if (!lUnsigned && val < 0)
5125         emitcode ("mov", "a,#0x%02x", -val);
5126       else
5127         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5128     }
5129   else /* ! literal */
5130     {
5131       MOVA (aopGet (left, 0, FALSE, FALSE));
5132
5133       if (!lUnsigned)
5134         {
5135           lbl = newiTempLabel (NULL);
5136           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5137           emitcode ("cpl", "F0"); /* complement sign flag */
5138           emitcode ("cpl", "a"); /* 2's complement */
5139           emitcode ("inc", "a");
5140           emitLabel (lbl);
5141         }
5142     }
5143
5144   /* now the multiplication */
5145   emitcode ("mul", "ab");
5146   if (runtimeSign || compiletimeSign)
5147     {
5148       lbl = newiTempLabel (NULL);
5149       if (runtimeSign)
5150         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5151       emitcode ("cpl", "a"); /* lsb 2's complement */
5152       if (size != 2)
5153         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5154       else
5155         {
5156           emitcode ("add", "a,#1"); /* this sets carry flag */
5157           emitcode ("xch", "a,b");
5158           emitcode ("cpl", "a"); /* msb 2's complement */
5159           emitcode ("addc", "a,#0");
5160           emitcode ("xch", "a,b");
5161         }
5162       emitLabel (lbl);
5163     }
5164   aopPut (result, "a", 0);
5165   if (size == 2)
5166     aopPut (result, "b", 1);
5167
5168   popB (pushedB);
5169 }
5170
5171 /*-----------------------------------------------------------------*/
5172 /* genMult - generates code for multiplication                     */
5173 /*-----------------------------------------------------------------*/
5174 static void
5175 genMult (iCode * ic)
5176 {
5177   operand *left = IC_LEFT (ic);
5178   operand *right = IC_RIGHT (ic);
5179   operand *result = IC_RESULT (ic);
5180
5181   D (emitcode (";", "genMult"));
5182
5183   /* assign the asmops */
5184   aopOp (left, ic, FALSE);
5185   aopOp (right, ic, FALSE);
5186   aopOp (result, ic, TRUE);
5187
5188   /* special cases first */
5189   /* both are bits */
5190   if (AOP_TYPE (left) == AOP_CRY &&
5191       AOP_TYPE (right) == AOP_CRY)
5192     {
5193       genMultbits (left, right, result);
5194       goto release;
5195     }
5196
5197   /* if both are of size == 1 */
5198 #if 0 // one of them can be a sloc shared with the result
5199     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5200 #else
5201   if (getSize(operandType(left)) == 1 &&
5202       getSize(operandType(right)) == 1)
5203 #endif
5204     {
5205       genMultOneByte (left, right, result);
5206       goto release;
5207     }
5208
5209   /* should have been converted to function call */
5210     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5211              getSize(OP_SYMBOL(right)->type));
5212   assert (0);
5213
5214 release:
5215   freeAsmop (result, NULL, ic, TRUE);
5216   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5217   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5218 }
5219
5220 /*-----------------------------------------------------------------*/
5221 /* genDivbits :- division of bits                                  */
5222 /*-----------------------------------------------------------------*/
5223 static void
5224 genDivbits (operand * left,
5225             operand * right,
5226             operand * result)
5227 {
5228   char *l;
5229   bool pushedB;
5230
5231   D(emitcode (";", "genDivbits"));
5232
5233   pushedB = pushB ();
5234
5235   /* the result must be bit */
5236   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5237   l = aopGet (left, 0, FALSE, FALSE);
5238
5239   MOVA (l);
5240
5241   emitcode ("div", "ab");
5242   emitcode ("rrc", "a");
5243
5244   popB (pushedB);
5245
5246   aopPut (result, "c", 0);
5247 }
5248
5249 /*-----------------------------------------------------------------*/
5250 /* genDivOneByte : 8 bit division                                  */
5251 /*-----------------------------------------------------------------*/
5252 static void
5253 genDivOneByte (operand * left,
5254                operand * right,
5255                operand * result)
5256 {
5257   bool lUnsigned, rUnsigned, pushedB;
5258   bool runtimeSign, compiletimeSign;
5259   bool accuse = FALSE;
5260   bool pushedA = FALSE;
5261   symbol *lbl;
5262   int size, offset;
5263
5264   D(emitcode (";", "genDivOneByte"));
5265
5266   /* Why is it necessary that genDivOneByte() can return an int result?
5267      Have a look at:
5268
5269         volatile unsigned char uc;
5270         volatile signed char sc1, sc2;
5271         volatile int i;
5272
5273         uc  = 255;
5274         sc1 = -1;
5275         i = uc / sc1;
5276
5277      Or:
5278
5279         sc1 = -128;
5280         sc2 = -1;
5281         i = sc1 / sc2;
5282
5283      In all cases a one byte result would overflow, the following cast to int
5284      would return the wrong result.
5285
5286      Two possible solution:
5287         a) cast operands to int, if ((unsigned) / (signed)) or
5288            ((signed) / (signed))
5289         b) return an 16 bit signed int; this is what we're doing here!
5290   */
5291
5292   size = AOP_SIZE (result) - 1;
5293   offset = 1;
5294   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5295   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5296
5297   pushedB = pushB ();
5298
5299   /* signed or unsigned */
5300   if (lUnsigned && rUnsigned)
5301     {
5302       /* unsigned is easy */
5303       MOVB (aopGet (right, 0, FALSE, FALSE));
5304       MOVA (aopGet (left, 0, FALSE, FALSE));
5305       emitcode ("div", "ab");
5306       aopPut (result, "a", 0);
5307       while (size--)
5308         aopPut (result, zero, offset++);
5309
5310       popB (pushedB);
5311       return;
5312     }
5313
5314   /* signed is a little bit more difficult */
5315
5316   /* now sign adjust for both left & right */
5317
5318   /* let's see what's needed: */
5319   /* apply negative sign during runtime */
5320   runtimeSign = FALSE;
5321   /* negative sign from literals */
5322   compiletimeSign = FALSE;
5323
5324   if (!lUnsigned)
5325     {
5326       if (AOP_TYPE(left) == AOP_LIT)
5327         {
5328           /* signed literal */
5329           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5330           if (val < 0)
5331             compiletimeSign = TRUE;
5332         }
5333       else
5334         /* signed but not literal */
5335         runtimeSign = TRUE;
5336     }
5337
5338   if (!rUnsigned)
5339     {
5340       if (AOP_TYPE(right) == AOP_LIT)
5341         {
5342           /* signed literal */
5343           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5344           if (val < 0)
5345             compiletimeSign ^= TRUE;
5346         }
5347       else
5348         /* signed but not literal */
5349         runtimeSign = TRUE;
5350     }
5351
5352   /* initialize F0, which stores the runtime sign */
5353   if (runtimeSign)
5354     {
5355       if (compiletimeSign)
5356         emitcode ("setb", "F0"); /* set sign flag */
5357       else
5358         emitcode ("clr", "F0"); /* reset sign flag */
5359     }
5360
5361   /* save the signs of the operands */
5362   if (AOP_TYPE(right) == AOP_LIT)
5363     {
5364       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5365
5366       if (!rUnsigned && val < 0)
5367         emitcode ("mov", "b,#0x%02x", -val);
5368       else
5369         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5370     }
5371   else /* ! literal */
5372     {
5373       if (rUnsigned)
5374         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5375       else
5376         {
5377           MOVA (aopGet (right, 0, FALSE, FALSE));
5378           lbl = newiTempLabel (NULL);
5379           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5380           emitcode ("cpl", "F0"); /* complement sign flag */
5381           emitcode ("cpl", "a");  /* 2's complement */
5382           emitcode ("inc", "a");
5383           emitLabel (lbl);
5384           emitcode ("mov", "b,a");
5385         }
5386     }
5387
5388   if (AOP_TYPE(left) == AOP_LIT)
5389     {
5390       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5391
5392       if (!lUnsigned && val < 0)
5393         emitcode ("mov", "a,#0x%02x", -val);
5394       else
5395         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5396     }
5397   else /* ! literal */
5398     {
5399       MOVA (aopGet (left, 0, FALSE, FALSE));
5400
5401       if (!lUnsigned)
5402         {
5403           lbl = newiTempLabel (NULL);
5404           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5405           emitcode ("cpl", "F0"); /* complement sign flag */
5406           emitcode ("cpl", "a");  /* 2's complement */
5407           emitcode ("inc", "a");
5408           emitLabel (lbl);
5409         }
5410     }
5411
5412   /* now the division */
5413   emitcode ("div", "ab");
5414
5415   if (runtimeSign || compiletimeSign)
5416     {
5417       lbl = newiTempLabel (NULL);
5418       if (runtimeSign)
5419         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5420       emitcode ("cpl", "a"); /* lsb 2's complement */
5421       emitcode ("inc", "a");
5422       emitLabel (lbl);
5423
5424       accuse = aopPut (result, "a", 0);
5425       if (size > 0)
5426         {
5427           /* msb is 0x00 or 0xff depending on the sign */
5428           if (runtimeSign)
5429             {
5430               if (accuse)
5431                 {
5432                   emitcode ("push", "acc");
5433                   pushedA = TRUE;
5434                 }
5435               emitcode ("mov", "c,F0");
5436               emitcode ("subb", "a,acc");
5437               while (size--)
5438                 aopPut (result, "a", offset++);
5439             }
5440           else /* compiletimeSign */
5441             {
5442               if (aopPutUsesAcc (result, "#0xFF", offset))
5443                 {
5444                   emitcode ("push", "acc");
5445                   pushedA = TRUE;
5446                 }
5447               while (size--)
5448                 aopPut (result, "#0xff", offset++);
5449             }
5450         }
5451     }
5452   else
5453     {
5454       aopPut (result, "a", 0);
5455       while (size--)
5456         aopPut (result, zero, offset++);
5457     }
5458
5459   if (pushedA)
5460     emitcode ("pop", "acc");
5461   popB (pushedB);
5462 }
5463
5464 /*-----------------------------------------------------------------*/
5465 /* genDiv - generates code for division                            */
5466 /*-----------------------------------------------------------------*/
5467 static void
5468 genDiv (iCode * ic)
5469 {
5470   operand *left = IC_LEFT (ic);
5471   operand *right = IC_RIGHT (ic);
5472   operand *result = IC_RESULT (ic);
5473
5474   D (emitcode (";", "genDiv"));
5475
5476   /* assign the asmops */
5477   aopOp (left, ic, FALSE);
5478   aopOp (right, ic, FALSE);
5479   aopOp (result, ic, TRUE);
5480
5481   /* special cases first */
5482   /* both are bits */
5483   if (AOP_TYPE (left) == AOP_CRY &&
5484       AOP_TYPE (right) == AOP_CRY)
5485     {
5486       genDivbits (left, right, result);
5487       goto release;
5488     }
5489
5490   /* if both are of size == 1 */
5491   if (AOP_SIZE (left) == 1 &&
5492       AOP_SIZE (right) == 1)
5493     {
5494       genDivOneByte (left, right, result);
5495       goto release;
5496     }
5497
5498   /* should have been converted to function call */
5499   assert (0);
5500 release:
5501   freeAsmop (result, NULL, ic, TRUE);
5502   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5503   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5504 }
5505
5506 /*-----------------------------------------------------------------*/
5507 /* genModbits :- modulus of bits                                   */
5508 /*-----------------------------------------------------------------*/
5509 static void
5510 genModbits (operand * left,
5511             operand * right,
5512             operand * result)
5513 {
5514   char *l;
5515   bool pushedB;
5516
5517   D (emitcode (";", "genModbits"));
5518
5519   pushedB = pushB ();
5520
5521   /* the result must be bit */
5522   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5523   l = aopGet (left, 0, FALSE, FALSE);
5524
5525   MOVA (l);
5526
5527   emitcode ("div", "ab");
5528   emitcode ("mov", "a,b");
5529   emitcode ("rrc", "a");
5530
5531   popB (pushedB);
5532
5533   aopPut (result, "c", 0);
5534 }
5535
5536 /*-----------------------------------------------------------------*/
5537 /* genModOneByte : 8 bit modulus                                   */
5538 /*-----------------------------------------------------------------*/
5539 static void
5540 genModOneByte (operand * left,
5541                operand * right,
5542                operand * result)
5543 {
5544   bool lUnsigned, rUnsigned, pushedB;
5545   bool runtimeSign, compiletimeSign;
5546   symbol *lbl;
5547   int size, offset;
5548
5549   D (emitcode (";", "genModOneByte"));
5550
5551   size = AOP_SIZE (result) - 1;
5552   offset = 1;
5553   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5554   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5555
5556   /* if right is a literal, check it for 2^n */
5557   if (AOP_TYPE(right) == AOP_LIT)
5558     {
5559       unsigned char val = abs((int) operandLitValue(right));
5560       symbol *lbl2 = NULL;
5561
5562       switch (val)
5563         {
5564           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5565           case 2:
5566           case 4:
5567           case 8:
5568           case 16:
5569           case 32:
5570           case 64:
5571           case 128:
5572             if (lUnsigned)
5573               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5574                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5575               /* because iCode should have been changed to genAnd  */
5576               /* see file "SDCCopt.c", function "convertToFcall()" */
5577
5578             MOVA (aopGet (left, 0, FALSE, FALSE));
5579             emitcode ("mov", "c,acc.7");
5580             emitcode ("anl", "a,#0x%02x", val - 1);
5581             lbl = newiTempLabel (NULL);
5582             emitcode ("jz", "%05d$", (lbl->key + 100));
5583             emitcode ("jnc", "%05d$", (lbl->key + 100));
5584             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5585             if (size)
5586               {
5587                 int size2 = size;
5588                 int offs2 = offset;
5589
5590                 aopPut (result, "a", 0);
5591                 while (size2--)
5592                   aopPut (result, "#0xff", offs2++);
5593                 lbl2 = newiTempLabel (NULL);
5594                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5595               }
5596             emitLabel (lbl);
5597             aopPut (result, "a", 0);
5598             while (size--)
5599               aopPut (result, zero, offset++);
5600             if (lbl2)
5601               {
5602                 emitLabel (lbl2);
5603               }
5604             return;
5605
5606           default:
5607             break;
5608         }
5609     }
5610
5611   pushedB = pushB ();
5612
5613   /* signed or unsigned */
5614   if (lUnsigned && rUnsigned)
5615     {
5616       /* unsigned is easy */
5617       MOVB (aopGet (right, 0, FALSE, FALSE));
5618       MOVA (aopGet (left, 0, FALSE, FALSE));
5619       emitcode ("div", "ab");
5620       aopPut (result, "b", 0);
5621       while (size--)
5622         aopPut (result, zero, offset++);
5623
5624       popB (pushedB);
5625       return;
5626     }
5627
5628   /* signed is a little bit more difficult */
5629
5630   /* now sign adjust for both left & right */
5631
5632   /* modulus: sign of the right operand has no influence on the result! */
5633   if (AOP_TYPE(right) == AOP_LIT)
5634     {
5635       signed char val = (char) operandLitValue(right);
5636
5637       if (!rUnsigned && val < 0)
5638         emitcode ("mov", "b,#0x%02x", -val);
5639       else
5640         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5641     }
5642   else /* not literal */
5643     {
5644       if (rUnsigned)
5645         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5646       else
5647         {
5648           MOVA (aopGet (right, 0, FALSE, FALSE));
5649           lbl = newiTempLabel (NULL);
5650           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5651           emitcode ("cpl", "a"); /* 2's complement */
5652           emitcode ("inc", "a");
5653           emitLabel (lbl);
5654           emitcode ("mov", "b,a");
5655         }
5656     }
5657
5658   /* let's see what's needed: */
5659   /* apply negative sign during runtime */
5660   runtimeSign = FALSE;
5661   /* negative sign from literals */
5662   compiletimeSign = FALSE;
5663
5664   /* sign adjust left side */
5665   if (AOP_TYPE(left) == AOP_LIT)
5666     {
5667       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5668
5669       if (!lUnsigned && val < 0)
5670         {
5671           compiletimeSign = TRUE; /* set sign flag */
5672           emitcode ("mov", "a,#0x%02x", -val);
5673         }
5674       else
5675         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5676     }
5677   else /* ! literal */
5678     {
5679       MOVA (aopGet (left, 0, FALSE, FALSE));
5680
5681       if (!lUnsigned)
5682         {
5683           runtimeSign = TRUE;
5684           emitcode ("clr", "F0"); /* clear sign flag */
5685
5686           lbl = newiTempLabel (NULL);
5687           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5688           emitcode ("setb", "F0"); /* set sign flag */
5689           emitcode ("cpl", "a");   /* 2's complement */
5690           emitcode ("inc", "a");
5691           emitLabel (lbl);
5692         }
5693     }
5694
5695   /* now the modulus */
5696   emitcode ("div", "ab");
5697
5698   if (runtimeSign || compiletimeSign)
5699     {
5700       emitcode ("mov", "a,b");
5701       lbl = newiTempLabel (NULL);
5702       if (runtimeSign)
5703         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5704       emitcode ("cpl", "a"); /* 2's complement */
5705       emitcode ("inc", "a");
5706       emitLabel (lbl);
5707
5708       aopPut (result, "a", 0);
5709       if (size > 0)
5710         {
5711           /* msb is 0x00 or 0xff depending on the sign */
5712           if (runtimeSign)
5713             {
5714               emitcode ("mov", "c,F0");
5715               emitcode ("subb", "a,acc");
5716               while (size--)
5717                 aopPut (result, "a", offset++);
5718             }
5719           else /* compiletimeSign */
5720             while (size--)
5721               aopPut (result, "#0xff", offset++);
5722         }
5723     }
5724   else
5725     {
5726       aopPut (result, "b", 0);
5727       while (size--)
5728         aopPut (result, zero, offset++);
5729     }
5730
5731   popB (pushedB);
5732 }
5733
5734 /*-----------------------------------------------------------------*/
5735 /* genMod - generates code for division                            */
5736 /*-----------------------------------------------------------------*/
5737 static void
5738 genMod (iCode * ic)
5739 {
5740   operand *left = IC_LEFT (ic);
5741   operand *right = IC_RIGHT (ic);
5742   operand *result = IC_RESULT (ic);
5743
5744   D (emitcode (";", "genMod"));
5745
5746   /* assign the asmops */
5747   aopOp (left, ic, FALSE);
5748   aopOp (right, ic, FALSE);
5749   aopOp (result, ic, TRUE);
5750
5751   /* special cases first */
5752   /* both are bits */
5753   if (AOP_TYPE (left) == AOP_CRY &&
5754       AOP_TYPE (right) == AOP_CRY)
5755     {
5756       genModbits (left, right, result);
5757       goto release;
5758     }
5759
5760   /* if both are of size == 1 */
5761   if (AOP_SIZE (left) == 1 &&
5762       AOP_SIZE (right) == 1)
5763     {
5764       genModOneByte (left, right, result);
5765       goto release;
5766     }
5767
5768   /* should have been converted to function call */
5769   assert (0);
5770
5771 release:
5772   freeAsmop (result, NULL, ic, TRUE);
5773   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5774   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5775 }
5776
5777 /*-----------------------------------------------------------------*/
5778 /* genIfxJump :- will create a jump depending on the ifx           */
5779 /*-----------------------------------------------------------------*/
5780 static void
5781 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5782 {
5783   symbol *jlbl;
5784   symbol *tlbl = newiTempLabel (NULL);
5785   char *inst;
5786
5787   D (emitcode (";", "genIfxJump"));
5788
5789   /* if true label then we jump if condition
5790      supplied is true */
5791   if (IC_TRUE (ic))
5792     {
5793       jlbl = IC_TRUE (ic);
5794       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5795                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5796     }
5797   else
5798     {
5799       /* false label is present */
5800       jlbl = IC_FALSE (ic);
5801       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5802                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5803     }
5804   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5805     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5806   else
5807     emitcode (inst, "%05d$", tlbl->key + 100);
5808   freeForBranchAsmop (result);
5809   freeForBranchAsmop (right);
5810   freeForBranchAsmop (left);
5811   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5812   emitLabel (tlbl);
5813
5814   /* mark the icode as generated */
5815   ic->generated = 1;
5816 }
5817
5818 /*-----------------------------------------------------------------*/
5819 /* genCmp :- greater or less than comparison                       */
5820 /*-----------------------------------------------------------------*/
5821 static void
5822 genCmp (operand * left, operand * right,
5823         operand * result, iCode * ifx, int sign, iCode *ic)
5824 {
5825   int size, offset = 0;
5826   unsigned long lit = 0L;
5827   bool rightInB;
5828
5829   D (emitcode (";", "genCmp"));
5830
5831   /* if left & right are bit variables */
5832   if (AOP_TYPE (left) == AOP_CRY &&
5833       AOP_TYPE (right) == AOP_CRY)
5834     {
5835       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5836       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5837     }
5838   else
5839     {
5840       /* subtract right from left if at the
5841          end the carry flag is set then we know that
5842          left is greater than right */
5843       size = max (AOP_SIZE (left), AOP_SIZE (right));
5844
5845       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5846       if ((size == 1) && !sign &&
5847           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5848         {
5849           symbol *lbl = newiTempLabel (NULL);
5850           emitcode ("cjne", "%s,%s,%05d$",
5851                     aopGet (left, offset, FALSE, FALSE),
5852                     aopGet (right, offset, FALSE, FALSE),
5853                     lbl->key + 100);
5854           emitLabel (lbl);
5855         }
5856       else
5857         {
5858           if (AOP_TYPE (right) == AOP_LIT)
5859             {
5860               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5861               /* optimize if(x < 0) or if(x >= 0) */
5862               if (lit == 0L)
5863                 {
5864                   if (!sign)
5865                     {
5866                       CLRC;
5867                     }
5868                   else
5869                     {
5870                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5871                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5872                         {
5873                           genIfxJump (ifx, "acc.7", left, right, result);
5874                           freeAsmop (right, NULL, ic, TRUE);
5875                           freeAsmop (left, NULL, ic, TRUE);
5876
5877                           return;
5878                         }
5879                       else
5880                         {
5881                           emitcode ("rlc", "a");
5882                         }
5883                     }
5884                   goto release;
5885                 }
5886               else
5887                 {//nonzero literal
5888                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5889                   while (size && (bytelit == 0))
5890                     {
5891                       offset++;
5892                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5893                       size--;
5894                     }
5895                   CLRC;
5896                   while (size--)
5897                     {
5898                       MOVA (aopGet (left, offset, FALSE, FALSE));
5899                       if (sign && size == 0)
5900                         {
5901                           emitcode ("xrl", "a,#0x80");
5902                           emitcode ("subb", "a,#0x%02x",
5903                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5904                         }
5905                       else
5906                         {
5907                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5908                         }
5909                       offset++;
5910                     }
5911                   goto release;
5912                 }
5913             }
5914           CLRC;
5915           while (size--)
5916             {
5917               bool pushedB = FALSE;
5918               rightInB = aopGetUsesAcc(right, offset);
5919               if (rightInB)
5920                 {
5921                   pushedB = pushB ();
5922                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5923                 }
5924               MOVA (aopGet (left, offset, FALSE, FALSE));
5925               if (sign && size == 0)
5926                 {
5927                   emitcode ("xrl", "a,#0x80");
5928                   if (!rightInB)
5929                     {
5930                       pushedB = pushB ();
5931                       rightInB++;
5932                       MOVB (aopGet (right, offset, FALSE, FALSE));
5933                     }
5934                   emitcode ("xrl", "b,#0x80");
5935                   emitcode ("subb", "a,b");
5936                 }
5937               else
5938                 {
5939                   if (rightInB)
5940                     emitcode ("subb", "a,b");
5941                   else
5942                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5943                 }
5944               if (rightInB)
5945                 popB (pushedB);
5946               offset++;
5947             }
5948         }
5949     }
5950
5951 release:
5952   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5953   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5954   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5955     {
5956       outBitC (result);
5957     }
5958   else
5959     {
5960       /* if the result is used in the next
5961          ifx conditional branch then generate
5962          code a little differently */
5963       if (ifx)
5964         {
5965           genIfxJump (ifx, "c", NULL, NULL, result);
5966         }
5967       else
5968         {
5969           outBitC (result);
5970         }
5971       /* leave the result in acc */
5972     }
5973 }
5974
5975 /*-----------------------------------------------------------------*/
5976 /* genCmpGt :- greater than comparison                             */
5977 /*-----------------------------------------------------------------*/
5978 static void
5979 genCmpGt (iCode * ic, iCode * ifx)
5980 {
5981   operand *left, *right, *result;
5982   sym_link *letype, *retype;
5983   int sign;
5984
5985   D (emitcode (";", "genCmpGt"));
5986
5987   left = IC_LEFT (ic);
5988   right = IC_RIGHT (ic);
5989   result = IC_RESULT (ic);
5990
5991   letype = getSpec (operandType (left));
5992   retype = getSpec (operandType (right));
5993   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5994            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5995   /* assign the asmops */
5996   aopOp (result, ic, TRUE);
5997   aopOp (left, ic, FALSE);
5998   aopOp (right, ic, FALSE);
5999
6000   genCmp (right, left, result, ifx, sign, ic);
6001
6002   freeAsmop (result, NULL, ic, TRUE);
6003 }
6004
6005 /*-----------------------------------------------------------------*/
6006 /* genCmpLt - less than comparisons                                */
6007 /*-----------------------------------------------------------------*/
6008 static void
6009 genCmpLt (iCode * ic, iCode * ifx)
6010 {
6011   operand *left, *right, *result;
6012   sym_link *letype, *retype;
6013   int sign;
6014
6015   D (emitcode (";", "genCmpLt"));
6016
6017   left = IC_LEFT (ic);
6018   right = IC_RIGHT (ic);
6019   result = IC_RESULT (ic);
6020
6021   letype = getSpec (operandType (left));
6022   retype = getSpec (operandType (right));
6023   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6024            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6025   /* assign the asmops */
6026   aopOp (result, ic, TRUE);
6027   aopOp (left, ic, FALSE);
6028   aopOp (right, ic, FALSE);
6029
6030   genCmp (left, right, result, ifx, sign, ic);
6031
6032   freeAsmop (result, NULL, ic, TRUE);
6033 }
6034
6035 /*-----------------------------------------------------------------*/
6036 /* gencjneshort - compare and jump if not equal                    */
6037 /*-----------------------------------------------------------------*/
6038 static void
6039 gencjneshort (operand * left, operand * right, symbol * lbl)
6040 {
6041   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6042   int offset = 0;
6043   unsigned long lit = 0L;
6044
6045   D (emitcode (";", "gencjneshort"));
6046
6047   /* if the left side is a literal or
6048      if the right is in a pointer register and left
6049      is not */
6050   if ((AOP_TYPE (left) == AOP_LIT)  ||
6051       (AOP_TYPE (left) == AOP_IMMD) ||
6052       (AOP_TYPE (left) == AOP_DIR)  ||
6053       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6054     {
6055       operand *t = right;
6056       right = left;
6057       left = t;
6058     }
6059
6060   if (AOP_TYPE (right) == AOP_LIT)
6061     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6062
6063   /* if the right side is a literal then anything goes */
6064   if (AOP_TYPE (right) == AOP_LIT &&
6065       AOP_TYPE (left) != AOP_DIR  &&
6066       AOP_TYPE (left) != AOP_IMMD)
6067     {
6068       while (size--)
6069         {
6070           emitcode ("cjne", "%s,%s,%05d$",
6071                     aopGet (left, offset, FALSE, FALSE),
6072                     aopGet (right, offset, FALSE, FALSE),
6073                     lbl->key + 100);
6074           offset++;
6075         }
6076     }
6077
6078   /* if the right side is in a register or in direct space or
6079      if the left is a pointer register & right is not */
6080   else if (AOP_TYPE (right) == AOP_REG ||
6081            AOP_TYPE (right) == AOP_DIR ||
6082            AOP_TYPE (right) == AOP_LIT ||
6083            AOP_TYPE (right) == AOP_IMMD ||
6084            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6085            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6086     {
6087       while (size--)
6088         {
6089           MOVA (aopGet (left, offset, FALSE, FALSE));
6090           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6091               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6092             emitcode ("jnz", "%05d$", lbl->key + 100);
6093           else
6094             emitcode ("cjne", "a,%s,%05d$",
6095                       aopGet (right, offset, FALSE, TRUE),
6096                       lbl->key + 100);
6097           offset++;
6098         }
6099     }
6100   else
6101     {
6102       /* right is a pointer reg need both a & b */
6103       while (size--)
6104         {
6105           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6106           wassertl(!BINUSE, "B was in use");
6107           MOVB (aopGet (left, offset, FALSE, FALSE));
6108           MOVA (aopGet (right, offset, FALSE, FALSE));
6109           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6110           offset++;
6111         }
6112     }
6113 }
6114
6115 /*-----------------------------------------------------------------*/
6116 /* gencjne - compare and jump if not equal                         */
6117 /*-----------------------------------------------------------------*/
6118 static void
6119 gencjne (operand * left, operand * right, symbol * lbl)
6120 {
6121   symbol *tlbl = newiTempLabel (NULL);
6122
6123   D (emitcode (";", "gencjne"));
6124
6125   gencjneshort (left, right, lbl);
6126
6127   emitcode ("mov", "a,%s", one);
6128   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6129   emitLabel (lbl);
6130   emitcode ("clr", "a");
6131   emitLabel (tlbl);
6132 }
6133
6134 /*-----------------------------------------------------------------*/
6135 /* genCmpEq - generates code for equal to                          */
6136 /*-----------------------------------------------------------------*/
6137 static void
6138 genCmpEq (iCode * ic, iCode * ifx)
6139 {
6140   bool swappedLR = FALSE;
6141   operand *left, *right, *result;
6142
6143   D (emitcode (";", "genCmpEq"));
6144
6145   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6146   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6147   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6148
6149   /* if literal, literal on the right or
6150      if the right is in a pointer register and left
6151      is not */
6152   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6153       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6154     {
6155       operand *t = IC_RIGHT (ic);
6156       IC_RIGHT (ic) = IC_LEFT (ic);
6157       IC_LEFT (ic) = t;
6158       swappedLR = TRUE;
6159     }
6160
6161   if (ifx && !AOP_SIZE (result))
6162     {
6163       symbol *tlbl;
6164       /* if they are both bit variables */
6165       if (AOP_TYPE (left) == AOP_CRY &&
6166           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6167         {
6168           if (AOP_TYPE (right) == AOP_LIT)
6169             {
6170               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6171               if (lit == 0L)
6172                 {
6173                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6174                   emitcode ("cpl", "c");
6175                 }
6176               else if (lit == 1L)
6177                 {
6178                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6179                 }
6180               else
6181                 {
6182                   emitcode ("clr", "c");
6183                 }
6184               /* AOP_TYPE(right) == AOP_CRY */
6185             }
6186           else
6187             {
6188               symbol *lbl = newiTempLabel (NULL);
6189               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6190               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6191               emitcode ("cpl", "c");
6192               emitLabel (lbl);
6193             }
6194           /* if true label then we jump if condition
6195              supplied is true */
6196           tlbl = newiTempLabel (NULL);
6197           if (IC_TRUE (ifx))
6198             {
6199               emitcode ("jnc", "%05d$", tlbl->key + 100);
6200               freeForBranchAsmop (result);
6201               freeForBranchAsmop (right);
6202               freeForBranchAsmop (left);
6203               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6204             }
6205           else
6206             {
6207               emitcode ("jc", "%05d$", tlbl->key + 100);
6208               freeForBranchAsmop (result);
6209               freeForBranchAsmop (right);
6210               freeForBranchAsmop (left);
6211               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6212             }
6213           emitLabel (tlbl);
6214         }
6215       else
6216         {
6217           tlbl = newiTempLabel (NULL);
6218           gencjneshort (left, right, tlbl);
6219           if (IC_TRUE (ifx))
6220             {
6221               freeForBranchAsmop (result);
6222               freeForBranchAsmop (right);
6223               freeForBranchAsmop (left);
6224               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6225               emitLabel (tlbl);
6226             }
6227           else
6228             {
6229               symbol *lbl = newiTempLabel (NULL);
6230               emitcode ("sjmp", "%05d$", lbl->key + 100);
6231               emitLabel (tlbl);
6232               freeForBranchAsmop (result);
6233               freeForBranchAsmop (right);
6234               freeForBranchAsmop (left);
6235               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6236               emitLabel (lbl);
6237             }
6238         }
6239       /* mark the icode as generated */
6240       ifx->generated = 1;
6241       goto release;
6242     }
6243
6244   /* if they are both bit variables */
6245   if (AOP_TYPE (left) == AOP_CRY &&
6246       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6247     {
6248       if (AOP_TYPE (right) == AOP_LIT)
6249         {
6250           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6251           if (lit == 0L)
6252             {
6253               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6254               emitcode ("cpl", "c");
6255             }
6256           else if (lit == 1L)
6257             {
6258               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6259             }
6260           else
6261             {
6262               emitcode ("clr", "c");
6263             }
6264           /* AOP_TYPE(right) == AOP_CRY */
6265         }
6266       else
6267         {
6268           symbol *lbl = newiTempLabel (NULL);
6269           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6270           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6271           emitcode ("cpl", "c");
6272           emitLabel (lbl);
6273         }
6274       /* c = 1 if egal */
6275       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6276         {
6277           outBitC (result);
6278           goto release;
6279         }
6280       if (ifx)
6281         {
6282           genIfxJump (ifx, "c", left, right, result);
6283           goto release;
6284         }
6285       /* if the result is used in an arithmetic operation
6286          then put the result in place */
6287       outBitC (result);
6288     }
6289   else
6290     {
6291       gencjne (left, right, newiTempLabel (NULL));
6292       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6293         {
6294           aopPut (result, "a", 0);
6295           goto release;
6296         }
6297       if (ifx)
6298         {
6299           genIfxJump (ifx, "a", left, right, result);
6300           goto release;
6301         }
6302       /* if the result is used in an arithmetic operation
6303          then put the result in place */
6304       if (AOP_TYPE (result) != AOP_CRY)
6305         outAcc (result);
6306       /* leave the result in acc */
6307     }
6308
6309 release:
6310   freeAsmop (result, NULL, ic, TRUE);
6311   if (!swappedLR)
6312     {
6313       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6314       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6315     }
6316   else
6317     {
6318       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6319       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6320     }
6321 }
6322
6323 /*-----------------------------------------------------------------*/
6324 /* ifxForOp - returns the icode containing the ifx for operand     */
6325 /*-----------------------------------------------------------------*/
6326 static iCode *
6327 ifxForOp (operand * op, iCode * ic)
6328 {
6329   /* if true symbol then needs to be assigned */
6330   if (IS_TRUE_SYMOP (op))
6331     return NULL;
6332
6333   /* if this has register type condition and
6334      the next instruction is ifx with the same operand
6335      and live to of the operand is upto the ifx only then */
6336   if (ic->next &&
6337       ic->next->op == IFX &&
6338       IC_COND (ic->next)->key == op->key &&
6339       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6340     return ic->next;
6341
6342   return NULL;
6343 }
6344
6345 /*-----------------------------------------------------------------*/
6346 /* hasInc - operand is incremented before any other use            */
6347 /*-----------------------------------------------------------------*/
6348 static iCode *
6349 hasInc (operand *op, iCode *ic, int osize)
6350 {
6351   sym_link *type = operandType(op);
6352   sym_link *retype = getSpec (type);
6353   iCode *lic = ic->next;
6354   int isize ;
6355
6356   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6357   if (!IS_SYMOP(op)) return NULL;
6358
6359   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6360   if (IS_AGGREGATE(type->next)) return NULL;
6361   if (osize != (isize = getSize(type->next))) return NULL;
6362
6363   while (lic) {
6364     /* if operand of the form op = op + <sizeof *op> */
6365     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6366         isOperandEqual(IC_RESULT(lic),op) &&
6367         isOperandLiteral(IC_RIGHT(lic)) &&
6368         operandLitValue(IC_RIGHT(lic)) == isize) {
6369       return lic;
6370     }
6371     /* if the operand used or deffed */
6372     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6373       return NULL;
6374     }
6375     /* if GOTO or IFX */
6376     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6377     lic = lic->next;
6378   }
6379   return NULL;
6380 }
6381
6382 /*-----------------------------------------------------------------*/
6383 /* genAndOp - for && operation                                     */
6384 /*-----------------------------------------------------------------*/
6385 static void
6386 genAndOp (iCode * ic)
6387 {
6388   operand *left, *right, *result;
6389   symbol *tlbl;
6390
6391   D (emitcode (";", "genAndOp"));
6392
6393   /* note here that && operations that are in an
6394      if statement are taken away by backPatchLabels
6395      only those used in arthmetic operations remain */
6396   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6397   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6398   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6399
6400   /* if both are bit variables */
6401   if (AOP_TYPE (left) == AOP_CRY &&
6402       AOP_TYPE (right) == AOP_CRY)
6403     {
6404       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6405       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6406       outBitC (result);
6407     }
6408   else
6409     {
6410       tlbl = newiTempLabel (NULL);
6411       toBoolean (left);
6412       emitcode ("jz", "%05d$", tlbl->key + 100);
6413       toBoolean (right);
6414       emitLabel (tlbl);
6415       outBitAcc (result);
6416     }
6417
6418   freeAsmop (result, NULL, ic, TRUE);
6419   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6420   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6421 }
6422
6423
6424 /*-----------------------------------------------------------------*/
6425 /* genOrOp - for || operation                                      */
6426 /*-----------------------------------------------------------------*/
6427 static void
6428 genOrOp (iCode * ic)
6429 {
6430   operand *left, *right, *result;
6431   symbol *tlbl;
6432
6433   D (emitcode (";", "genOrOp"));
6434
6435   /* note here that || operations that are in an
6436      if statement are taken away by backPatchLabels
6437      only those used in arthmetic operations remain */
6438   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6439   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6440   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6441
6442   /* if both are bit variables */
6443   if (AOP_TYPE (left) == AOP_CRY &&
6444       AOP_TYPE (right) == AOP_CRY)
6445     {
6446       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6447       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6448       outBitC (result);
6449     }
6450   else
6451     {
6452       tlbl = newiTempLabel (NULL);
6453       toBoolean (left);
6454       emitcode ("jnz", "%05d$", tlbl->key + 100);
6455       toBoolean (right);
6456       emitLabel (tlbl);
6457       outBitAcc (result);
6458     }
6459
6460   freeAsmop (result, NULL, ic, TRUE);
6461   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6462   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6463 }
6464
6465 /*-----------------------------------------------------------------*/
6466 /* isLiteralBit - test if lit == 2^n                               */
6467 /*-----------------------------------------------------------------*/
6468 static int
6469 isLiteralBit (unsigned long lit)
6470 {
6471   unsigned long pw[32] =
6472   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6473    0x100L, 0x200L, 0x400L, 0x800L,
6474    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6475    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6476    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6477    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6478    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6479   int idx;
6480
6481   for (idx = 0; idx < 32; idx++)
6482     if (lit == pw[idx])
6483       return idx + 1;
6484   return 0;
6485 }
6486
6487 /*-----------------------------------------------------------------*/
6488 /* continueIfTrue -                                                */
6489 /*-----------------------------------------------------------------*/
6490 static void
6491 continueIfTrue (iCode * ic)
6492 {
6493   if (IC_TRUE (ic))
6494     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6495   ic->generated = 1;
6496 }
6497
6498 /*-----------------------------------------------------------------*/
6499 /* jmpIfTrue -                                                     */
6500 /*-----------------------------------------------------------------*/
6501 static void
6502 jumpIfTrue (iCode * ic)
6503 {
6504   if (!IC_TRUE (ic))
6505     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6506   ic->generated = 1;
6507 }
6508
6509 /*-----------------------------------------------------------------*/
6510 /* jmpTrueOrFalse -                                                */
6511 /*-----------------------------------------------------------------*/
6512 static void
6513 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6514 {
6515   // ugly but optimized by peephole
6516   if (IC_TRUE (ic))
6517     {
6518       symbol *nlbl = newiTempLabel (NULL);
6519       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6520       emitLabel (tlbl);
6521       freeForBranchAsmop (result);
6522       freeForBranchAsmop (right);
6523       freeForBranchAsmop (left);
6524       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6525       emitLabel (nlbl);
6526     }
6527   else
6528     {
6529       freeForBranchAsmop (result);
6530       freeForBranchAsmop (right);
6531       freeForBranchAsmop (left);
6532       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6533       emitLabel (tlbl);
6534     }
6535   ic->generated = 1;
6536 }
6537
6538 /*-----------------------------------------------------------------*/
6539 /* genAnd  - code for and                                          */
6540 /*-----------------------------------------------------------------*/
6541 static void
6542 genAnd (iCode * ic, iCode * ifx)
6543 {
6544   operand *left, *right, *result;
6545   int size, offset = 0;
6546   unsigned long lit = 0L;
6547   int bytelit = 0;
6548   char buffer[10];
6549
6550   D (emitcode (";", "genAnd"));
6551
6552   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6553   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6554   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6555
6556 #ifdef DEBUG_TYPE
6557   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6558             AOP_TYPE (result),
6559             AOP_TYPE (left), AOP_TYPE (right));
6560   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6561             AOP_SIZE (result),
6562             AOP_SIZE (left), AOP_SIZE (right));
6563 #endif
6564
6565   /* if left is a literal & right is not then exchange them */
6566   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6567       AOP_NEEDSACC (left))
6568     {
6569       operand *tmp = right;
6570       right = left;
6571       left = tmp;
6572     }
6573
6574   /* if result = right then exchange left and right */
6575   if (sameRegs (AOP (result), AOP (right)))
6576     {
6577       operand *tmp = right;
6578       right = left;
6579       left = tmp;
6580     }
6581
6582   /* if right is bit then exchange them */
6583   if (AOP_TYPE (right) == AOP_CRY &&
6584       AOP_TYPE (left) != AOP_CRY)
6585     {
6586       operand *tmp = right;
6587       right = left;
6588       left = tmp;
6589     }
6590   if (AOP_TYPE (right) == AOP_LIT)
6591     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6592
6593   size = AOP_SIZE (result);
6594
6595   // if(bit & yy)
6596   // result = bit & yy;
6597   if (AOP_TYPE (left) == AOP_CRY)
6598     {
6599       // c = bit & literal;
6600       if (AOP_TYPE (right) == AOP_LIT)
6601         {
6602           if (lit & 1)
6603             {
6604               if (size && sameRegs (AOP (result), AOP (left)))
6605                 // no change
6606                 goto release;
6607               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6608             }
6609           else
6610             {
6611               // bit(result) = 0;
6612               if (size && (AOP_TYPE (result) == AOP_CRY))
6613                 {
6614                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6615                   goto release;
6616                 }
6617               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6618                 {
6619                   jumpIfTrue (ifx);
6620                   goto release;
6621                 }
6622               emitcode ("clr", "c");
6623             }
6624         }
6625       else
6626         {
6627           if (AOP_TYPE (right) == AOP_CRY)
6628             {
6629               // c = bit & bit;
6630               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6631               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6632             }
6633           else
6634             {
6635               // c = bit & val;
6636               MOVA (aopGet (right, 0, FALSE, FALSE));
6637               // c = lsb
6638               emitcode ("rrc", "a");
6639               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6640             }
6641         }
6642       // bit = c
6643       // val = c
6644       if (size)
6645         outBitC (result);
6646       // if(bit & ...)
6647       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6648         genIfxJump (ifx, "c", left, right, result);
6649       goto release;
6650     }
6651
6652   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6653   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6654   if ((AOP_TYPE (right) == AOP_LIT) &&
6655       (AOP_TYPE (result) == AOP_CRY) &&
6656       (AOP_TYPE (left) != AOP_CRY))
6657     {
6658       int posbit = isLiteralBit (lit);
6659       /* left &  2^n */
6660       if (posbit)
6661         {
6662           posbit--;
6663           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6664           // bit = left & 2^n
6665           if (size)
6666             {
6667               switch (posbit & 0x07)
6668                 {
6669                   case 0: emitcode ("rrc", "a");
6670                           break;
6671                   case 7: emitcode ("rlc", "a");
6672                           break;
6673                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6674                           break;
6675                 }
6676             }
6677           // if(left &  2^n)
6678           else
6679             {
6680               if (ifx)
6681                 {
6682                   SNPRINTF (buffer, sizeof(buffer),
6683                             "acc.%d", posbit & 0x07);
6684                   genIfxJump (ifx, buffer, left, right, result);
6685                 }
6686               else
6687                 {// what is this case? just found it in ds390/gen.c
6688                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6689                 }
6690               goto release;
6691             }
6692         }
6693       else
6694         {
6695           symbol *tlbl = newiTempLabel (NULL);
6696           int sizel = AOP_SIZE (left);
6697           if (size)
6698             emitcode ("setb", "c");
6699           while (sizel--)
6700             {
6701               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6702                 {
6703                   MOVA (aopGet (left, offset, FALSE, FALSE));
6704                   // byte ==  2^n ?
6705                   if ((posbit = isLiteralBit (bytelit)) != 0)
6706                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6707                   else
6708                     {
6709                       if (bytelit != 0x0FFL)
6710                         emitcode ("anl", "a,%s",
6711                                   aopGet (right, offset, FALSE, TRUE));
6712                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6713                     }
6714                 }
6715               offset++;
6716             }
6717           // bit = left & literal
6718           if (size)
6719             {
6720               emitcode ("clr", "c");
6721               emitLabel (tlbl);
6722             }
6723           // if(left & literal)
6724           else
6725             {
6726               if (ifx)
6727                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6728               else
6729                 emitLabel (tlbl);
6730               goto release;
6731             }
6732         }
6733       outBitC (result);
6734       goto release;
6735     }
6736
6737   /* if left is same as result */
6738   if (sameRegs (AOP (result), AOP (left)))
6739     {
6740       for (; size--; offset++)
6741         {
6742           if (AOP_TYPE (right) == AOP_LIT)
6743             {
6744               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6745               if (bytelit == 0x0FF)
6746                 {
6747                   /* dummy read of volatile operand */
6748                   if (isOperandVolatile (left, FALSE))
6749                     MOVA (aopGet (left, offset, FALSE, FALSE));
6750                   else
6751                     continue;
6752                 }
6753               else if (bytelit == 0)
6754                 {
6755                   aopPut (result, zero, offset);
6756                 }
6757               else if (IS_AOP_PREG (result))
6758                 {
6759                   MOVA (aopGet (left, offset, FALSE, TRUE));
6760                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6761                   aopPut (result, "a", offset);
6762                 }
6763               else
6764                 emitcode ("anl", "%s,%s",
6765                           aopGet (left, offset, FALSE, TRUE),
6766                           aopGet (right, offset, FALSE, FALSE));
6767             }
6768           else
6769             {
6770               if (AOP_TYPE (left) == AOP_ACC)
6771                 {
6772                   if (offset)
6773                     emitcode("mov", "a,b");
6774                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6775                 }
6776               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6777                 {
6778                   MOVB (aopGet (left, offset, FALSE, FALSE));
6779                   MOVA (aopGet (right, offset, FALSE, FALSE));
6780                   emitcode ("anl", "a,b");
6781                   aopPut (result, "a", offset);
6782                 }
6783               else if (aopGetUsesAcc (left, offset))
6784                 {
6785                   MOVA (aopGet (left, offset, FALSE, FALSE));
6786                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6787                   aopPut (result, "a", offset);
6788                 }
6789               else
6790                 {
6791                   MOVA (aopGet (right, offset, FALSE, FALSE));
6792                   if (IS_AOP_PREG (result))
6793                     {
6794                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6795                       aopPut (result, "a", offset);
6796                     }
6797                   else
6798                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6799                 }
6800             }
6801         }
6802     }
6803   else
6804     {
6805       // left & result in different registers
6806       if (AOP_TYPE (result) == AOP_CRY)
6807         {
6808           // result = bit
6809           // if(size), result in bit
6810           // if(!size && ifx), conditional oper: if(left & right)
6811           symbol *tlbl = newiTempLabel (NULL);
6812           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6813           if (size)
6814             emitcode ("setb", "c");
6815           while (sizer--)
6816             {
6817               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6818                   && AOP_TYPE(left)==AOP_ACC)
6819                 {
6820                   if (offset)
6821                     emitcode("mov", "a,b");
6822                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6823                 }
6824               else if (AOP_TYPE(left)==AOP_ACC)
6825                 {
6826                   if (!offset)
6827                     {
6828                       bool pushedB = pushB ();
6829                       emitcode("mov", "b,a");
6830                       MOVA (aopGet (right, offset, FALSE, FALSE));
6831                       emitcode("anl", "a,b");
6832                       popB (pushedB);
6833                     }
6834                   else
6835                     {
6836                       MOVA (aopGet (right, offset, FALSE, FALSE));
6837                       emitcode("anl", "a,b");
6838                     }
6839                 }
6840               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6841                 {
6842                   MOVB (aopGet (left, offset, FALSE, FALSE));
6843                   MOVA (aopGet (right, offset, FALSE, FALSE));
6844                   emitcode ("anl", "a,b");
6845                 }
6846               else if (aopGetUsesAcc (left, offset))
6847                 {
6848                   MOVA (aopGet (left, offset, FALSE, FALSE));
6849                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6850                     }
6851               else
6852                 {
6853                   MOVA (aopGet (right, offset, FALSE, FALSE));
6854                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6855                 }
6856
6857               emitcode ("jnz", "%05d$", tlbl->key + 100);
6858               offset++;
6859             }
6860           if (size)
6861             {
6862               CLRC;
6863               emitLabel (tlbl);
6864               outBitC (result);
6865             }
6866           else if (ifx)
6867             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6868           else
6869             emitLabel (tlbl);
6870         }
6871       else
6872         {
6873           for (; (size--); offset++)
6874             {
6875               // normal case
6876               // result = left & right
6877               if (AOP_TYPE (right) == AOP_LIT)
6878                 {
6879                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6880                   if (bytelit == 0x0FF)
6881                     {
6882                       aopPut (result,
6883                               aopGet (left, offset, FALSE, FALSE),
6884                               offset);
6885                       continue;
6886                     }
6887                   else if (bytelit == 0)
6888                     {
6889                       /* dummy read of volatile operand */
6890                       if (isOperandVolatile (left, FALSE))
6891                         MOVA (aopGet (left, offset, FALSE, FALSE));
6892                       aopPut (result, zero, offset);
6893                       continue;
6894                     }
6895                   else if (AOP_TYPE (left) == AOP_ACC)
6896                     {
6897                       if (!offset)
6898                         {
6899                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6900                           aopPut (result, "a", offset);
6901                           continue;
6902                         }
6903                       else
6904                         {
6905                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6906                           aopPut (result, "b", offset);
6907                           continue;
6908                         }
6909                     }
6910                 }
6911               // faster than result <- left, anl result,right
6912               // and better if result is SFR
6913               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6914                   && AOP_TYPE(left)==AOP_ACC)
6915                 {
6916                   if (offset)
6917                     emitcode("mov", "a,b");
6918                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6919                 }
6920               else if (AOP_TYPE(left)==AOP_ACC)
6921                 {
6922                   if (!offset)
6923                     {
6924                       bool pushedB = pushB ();
6925                       emitcode("mov", "b,a");
6926                       MOVA (aopGet (right, offset, FALSE, FALSE));
6927                       emitcode("anl", "a,b");
6928                       popB (pushedB);
6929                     }
6930                   else
6931                     {
6932                       MOVA (aopGet (right, offset, FALSE, FALSE));
6933                       emitcode("anl", "a,b");
6934                     }
6935                 }
6936               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6937                 {
6938                   MOVB (aopGet (left, offset, FALSE, FALSE));
6939                   MOVA (aopGet (right, offset, FALSE, FALSE));
6940                   emitcode ("anl", "a,b");
6941                 }
6942               else if (aopGetUsesAcc (left, offset))
6943                 {
6944                   MOVA (aopGet (left, offset, FALSE, FALSE));
6945                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6946                 }
6947               else
6948                 {
6949                   MOVA (aopGet (right, offset, FALSE, FALSE));
6950                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6951                 }
6952               aopPut (result, "a", offset);
6953             }
6954         }
6955     }
6956
6957 release:
6958   freeAsmop (result, NULL, ic, TRUE);
6959   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6960   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6961 }
6962
6963 /*-----------------------------------------------------------------*/
6964 /* genOr  - code for or                                            */
6965 /*-----------------------------------------------------------------*/
6966 static void
6967 genOr (iCode * ic, iCode * ifx)
6968 {
6969   operand *left, *right, *result;
6970   int size, offset = 0;
6971   unsigned long lit = 0L;
6972   int bytelit = 0;
6973
6974   D (emitcode (";", "genOr"));
6975
6976   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6977   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6978   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6979
6980 #ifdef DEBUG_TYPE
6981   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6982             AOP_TYPE (result),
6983             AOP_TYPE (left), AOP_TYPE (right));
6984   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6985             AOP_SIZE (result),
6986             AOP_SIZE (left), AOP_SIZE (right));
6987 #endif
6988
6989   /* if left is a literal & right is not then exchange them */
6990   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6991       AOP_NEEDSACC (left))
6992     {
6993       operand *tmp = right;
6994       right = left;
6995       left = tmp;
6996     }
6997
6998   /* if result = right then exchange them */
6999   if (sameRegs (AOP (result), AOP (right)))
7000     {
7001       operand *tmp = right;
7002       right = left;
7003       left = tmp;
7004     }
7005
7006   /* if right is bit then exchange them */
7007   if (AOP_TYPE (right) == AOP_CRY &&
7008       AOP_TYPE (left) != AOP_CRY)
7009     {
7010       operand *tmp = right;
7011       right = left;
7012       left = tmp;
7013     }
7014   if (AOP_TYPE (right) == AOP_LIT)
7015     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7016
7017   size = AOP_SIZE (result);
7018
7019   // if(bit | yy)
7020   // xx = bit | yy;
7021   if (AOP_TYPE (left) == AOP_CRY)
7022     {
7023       if (AOP_TYPE (right) == AOP_LIT)
7024         {
7025           // c = bit | literal;
7026           if (lit)
7027             {
7028               // lit != 0 => result = 1
7029               if (AOP_TYPE (result) == AOP_CRY)
7030                 {
7031                   if (size)
7032                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7033                   else if (ifx)
7034                     continueIfTrue (ifx);
7035                   goto release;
7036                 }
7037               emitcode ("setb", "c");
7038             }
7039           else
7040             {
7041               // lit == 0 => result = left
7042               if (size && sameRegs (AOP (result), AOP (left)))
7043                 goto release;
7044               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7045             }
7046         }
7047       else
7048         {
7049           if (AOP_TYPE (right) == AOP_CRY)
7050             {
7051               // c = bit | bit;
7052               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7053               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7054             }
7055           else
7056             {
7057               // c = bit | val;
7058               symbol *tlbl = newiTempLabel (NULL);
7059               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7060                 emitcode ("setb", "c");
7061               emitcode ("jb", "%s,%05d$",
7062                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7063               toBoolean (right);
7064               emitcode ("jnz", "%05d$", tlbl->key + 100);
7065               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7066                 {
7067                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7068                   goto release;
7069                 }
7070               else
7071                 {
7072                   CLRC;
7073                   emitLabel (tlbl);
7074                 }
7075             }
7076         }
7077       // bit = c
7078       // val = c
7079       if (size)
7080         outBitC (result);
7081       // if(bit | ...)
7082       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7083         genIfxJump (ifx, "c", left, right, result);
7084       goto release;
7085     }
7086
7087   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7088   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7089   if ((AOP_TYPE (right) == AOP_LIT) &&
7090       (AOP_TYPE (result) == AOP_CRY) &&
7091       (AOP_TYPE (left) != AOP_CRY))
7092     {
7093       if (lit)
7094         {
7095           // result = 1
7096           if (size)
7097             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7098           else
7099             continueIfTrue (ifx);
7100           goto release;
7101         }
7102       else
7103         {
7104           // lit = 0, result = boolean(left)
7105           if (size)
7106             emitcode ("setb", "c");
7107           toBoolean (right);
7108           if (size)
7109             {
7110               symbol *tlbl = newiTempLabel (NULL);
7111               emitcode ("jnz", "%05d$", tlbl->key + 100);
7112               CLRC;
7113               emitLabel (tlbl);
7114             }
7115           else
7116             {
7117               genIfxJump (ifx, "a", left, right, result);
7118               goto release;
7119             }
7120         }
7121       outBitC (result);
7122       goto release;
7123     }
7124
7125   /* if left is same as result */
7126   if (sameRegs (AOP (result), AOP (left)))
7127     {
7128       for (; size--; offset++)
7129         {
7130           if (AOP_TYPE (right) == AOP_LIT)
7131             {
7132               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7133               if (bytelit == 0)
7134                 {
7135                   /* dummy read of volatile operand */
7136                   if (isOperandVolatile (left, FALSE))
7137                     MOVA (aopGet (left, offset, FALSE, FALSE));
7138                   else
7139                     continue;
7140                 }
7141               else if (bytelit == 0x0FF)
7142                 {
7143                   aopPut (result, "#0xFF", offset);
7144                 }
7145               else if (IS_AOP_PREG (left))
7146                 {
7147                   MOVA (aopGet (left, offset, FALSE, TRUE));
7148                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7149                   aopPut (result, "a", offset);
7150                 }
7151               else
7152                 {
7153                   emitcode ("orl", "%s,%s",
7154                             aopGet (left, offset, FALSE, TRUE),
7155                             aopGet (right, offset, FALSE, FALSE));
7156                 }
7157             }
7158           else
7159             {
7160               if (AOP_TYPE (left) == AOP_ACC)
7161                 {
7162                   if (offset)
7163                     emitcode("mov", "a,b");
7164                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7165                 }
7166               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7167                 {
7168                   MOVB (aopGet (left, offset, FALSE, FALSE));
7169                   MOVA (aopGet (right, offset, FALSE, FALSE));
7170                   emitcode ("orl", "a,b");
7171                   aopPut (result, "a", offset);
7172                 }
7173               else if (aopGetUsesAcc (left, offset))
7174                 {
7175                   MOVA (aopGet (left, offset, FALSE, FALSE));
7176                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7177                   aopPut (result, "a", offset);
7178                 }
7179               else
7180                 {
7181                   MOVA (aopGet (right, offset, FALSE, FALSE));
7182                   if (IS_AOP_PREG (left))
7183                     {
7184                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7185                       aopPut (result, "a", offset);
7186                     }
7187                   else
7188                     {
7189                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7190                     }
7191                 }
7192             }
7193         }
7194     }
7195   else
7196     {
7197       // left & result in different registers
7198       if (AOP_TYPE (result) == AOP_CRY)
7199         {
7200           // result = bit
7201           // if(size), result in bit
7202           // if(!size && ifx), conditional oper: if(left | right)
7203           symbol *tlbl = newiTempLabel (NULL);
7204           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7205           if (size)
7206             emitcode ("setb", "c");
7207           while (sizer--)
7208             {
7209               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7210                   && AOP_TYPE(left)==AOP_ACC)
7211                 {
7212                   if (offset)
7213                     emitcode("mov", "a,b");
7214                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7215                 }
7216               else if (AOP_TYPE(left)==AOP_ACC)
7217                 {
7218                   if (!offset)
7219                     {
7220                       bool pushedB = pushB ();
7221                       emitcode("mov", "b,a");
7222                       MOVA (aopGet (right, offset, FALSE, FALSE));
7223                       emitcode("orl", "a,b");
7224                       popB (pushedB);
7225                     }
7226                   else
7227                     {
7228                       MOVA (aopGet (right, offset, FALSE, FALSE));
7229                       emitcode("orl", "a,b");
7230                     }
7231                 }
7232               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7233                 {
7234                   MOVB (aopGet (left, offset, FALSE, FALSE));
7235                   MOVA (aopGet (right, offset, FALSE, FALSE));
7236                   emitcode ("orl", "a,b");
7237                 }
7238               else if (aopGetUsesAcc (left, offset))
7239                 {
7240                   MOVA (aopGet (left, offset, FALSE, FALSE));
7241                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7242                 }
7243               else
7244                 {
7245                   MOVA (aopGet (right, offset, FALSE, FALSE));
7246                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7247               }
7248
7249               emitcode ("jnz", "%05d$", tlbl->key + 100);
7250               offset++;
7251             }
7252           if (size)
7253             {
7254               CLRC;
7255               emitLabel (tlbl);
7256               outBitC (result);
7257             }
7258           else if (ifx)
7259             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7260           else
7261             emitLabel (tlbl);
7262         }
7263       else
7264         {
7265           for (; (size--); offset++)
7266             {
7267               // normal case
7268               // result = left | right
7269               if (AOP_TYPE (right) == AOP_LIT)
7270                 {
7271                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7272                   if (bytelit == 0)
7273                     {
7274                       aopPut (result,
7275                               aopGet (left, offset, FALSE, FALSE),
7276                               offset);
7277                       continue;
7278                     }
7279                   else if (bytelit == 0x0FF)
7280                     {
7281                       /* dummy read of volatile operand */
7282                       if (isOperandVolatile (left, FALSE))
7283                         MOVA (aopGet (left, offset, FALSE, FALSE));
7284                       aopPut (result, "#0xFF", offset);
7285                       continue;
7286                     }
7287                 }
7288               // faster than result <- left, orl result,right
7289               // and better if result is SFR
7290               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7291                   && AOP_TYPE(left)==AOP_ACC)
7292                 {
7293                   if (offset)
7294                     emitcode("mov", "a,b");
7295                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7296                 }
7297               else if (AOP_TYPE(left)==AOP_ACC)
7298                 {
7299                   if (!offset)
7300                     {
7301                       bool pushedB = pushB ();
7302                       emitcode("mov", "b,a");
7303                       MOVA (aopGet (right, offset, FALSE, FALSE));
7304                       emitcode("orl", "a,b");
7305                       popB (pushedB);
7306                     }
7307                   else
7308                     {
7309                       MOVA (aopGet (right, offset, FALSE, FALSE));
7310                       emitcode("orl", "a,b");
7311                     }
7312                 }
7313               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7314                 {
7315                   MOVB (aopGet (left, offset, FALSE, FALSE));
7316                   MOVA (aopGet (right, offset, FALSE, FALSE));
7317                   emitcode ("orl", "a,b");
7318                 }
7319               else if (aopGetUsesAcc (left, offset))
7320                 {
7321                   MOVA (aopGet (left, offset, FALSE, FALSE));
7322                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7323                 }
7324               else
7325                 {
7326                   MOVA (aopGet (right, offset, FALSE, FALSE));
7327                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7328                 }
7329               aopPut (result, "a", offset);
7330             }
7331         }
7332     }
7333
7334 release:
7335   freeAsmop (result, NULL, ic, TRUE);
7336   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7337   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7338 }
7339
7340 /*-----------------------------------------------------------------*/
7341 /* genXor - code for xclusive or                                   */
7342 /*-----------------------------------------------------------------*/
7343 static void
7344 genXor (iCode * ic, iCode * ifx)
7345 {
7346   operand *left, *right, *result;
7347   int size, offset = 0;
7348   unsigned long lit = 0L;
7349   int bytelit = 0;
7350
7351   D (emitcode (";", "genXor"));
7352
7353   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7354   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7355   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7356
7357 #ifdef DEBUG_TYPE
7358   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7359             AOP_TYPE (result),
7360             AOP_TYPE (left), AOP_TYPE (right));
7361   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7362             AOP_SIZE (result),
7363             AOP_SIZE (left), AOP_SIZE (right));
7364 #endif
7365
7366   /* if left is a literal & right is not ||
7367      if left needs acc & right does not */
7368   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7369       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7370     {
7371       operand *tmp = right;
7372       right = left;
7373       left = tmp;
7374     }
7375
7376   /* if result = right then exchange them */
7377   if (sameRegs (AOP (result), AOP (right)))
7378     {
7379       operand *tmp = right;
7380       right = left;
7381       left = tmp;
7382     }
7383
7384   /* if right is bit then exchange them */
7385   if (AOP_TYPE (right) == AOP_CRY &&
7386       AOP_TYPE (left) != AOP_CRY)
7387     {
7388       operand *tmp = right;
7389       right = left;
7390       left = tmp;
7391     }
7392
7393   if (AOP_TYPE (right) == AOP_LIT)
7394     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7395
7396   size = AOP_SIZE (result);
7397
7398   // if(bit ^ yy)
7399   // xx = bit ^ yy;
7400   if (AOP_TYPE (left) == AOP_CRY)
7401     {
7402       if (AOP_TYPE (right) == AOP_LIT)
7403         {
7404           // c = bit & literal;
7405           if (lit >> 1)
7406             {
7407               // lit>>1  != 0 => result = 1
7408               if (AOP_TYPE (result) == AOP_CRY)
7409                 {
7410                   if (size)
7411                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7412                   else if (ifx)
7413                     continueIfTrue (ifx);
7414                   goto release;
7415                 }
7416               emitcode ("setb", "c");
7417             }
7418           else
7419             {
7420               // lit == (0 or 1)
7421               if (lit == 0)
7422                 {
7423                   // lit == 0, result = left
7424                   if (size && sameRegs (AOP (result), AOP (left)))
7425                     goto release;
7426                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7427                 }
7428               else
7429                 {
7430                   // lit == 1, result = not(left)
7431                   if (size && sameRegs (AOP (result), AOP (left)))
7432                     {
7433                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7434                       goto release;
7435                     }
7436                   else
7437                     {
7438                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7439                       emitcode ("cpl", "c");
7440                     }
7441                 }
7442             }
7443         }
7444       else
7445         {
7446           // right != literal
7447           symbol *tlbl = newiTempLabel (NULL);
7448           if (AOP_TYPE (right) == AOP_CRY)
7449             {
7450               // c = bit ^ bit;
7451               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7452             }
7453           else
7454             {
7455               // c = bit ^ val
7456               toCarry (right);
7457             }
7458           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7459           emitcode ("cpl", "c");
7460           emitLabel (tlbl);
7461         }
7462       // bit = c
7463       // val = c
7464       if (size)
7465         outBitC (result);
7466       // if(bit ^ ...)
7467       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7468         genIfxJump (ifx, "c", left, right, result);
7469       goto release;
7470     }
7471
7472   /* if left is same as result */
7473   if (sameRegs (AOP (result), AOP (left)))
7474     {
7475       for (; size--; offset++)
7476         {
7477           if (AOP_TYPE (right) == AOP_LIT)
7478             {
7479               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7480               if (bytelit == 0)
7481                 {
7482                   /* dummy read of volatile operand */
7483                   if (isOperandVolatile (left, FALSE))
7484                     MOVA (aopGet (left, offset, FALSE, FALSE));
7485                   else
7486                     continue;
7487                 }
7488               else if (IS_AOP_PREG (left))
7489                 {
7490                   MOVA (aopGet (left, offset, FALSE, TRUE));
7491                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7492                   aopPut (result, "a", offset);
7493                 }
7494               else
7495                 {
7496                   emitcode ("xrl", "%s,%s",
7497                             aopGet (left, offset, FALSE, TRUE),
7498                             aopGet (right, offset, FALSE, FALSE));
7499                 }
7500             }
7501           else
7502             {
7503               if (AOP_TYPE (left) == AOP_ACC)
7504                 {
7505                   if (offset)
7506                     emitcode("mov", "a,b");
7507                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7508                 }
7509               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7510                 {
7511                   MOVB (aopGet (left, offset, FALSE, FALSE));
7512                   MOVA (aopGet (right, offset, FALSE, FALSE));
7513                   emitcode ("xrl", "a,b");
7514                   aopPut (result, "a", offset);
7515                 }
7516               else if (aopGetUsesAcc (left, offset))
7517                 {
7518                   MOVA (aopGet (left, offset, FALSE, FALSE));
7519                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7520                   aopPut (result, "a", offset);
7521                 }
7522               else
7523                 {
7524                   MOVA (aopGet (right, offset, FALSE, FALSE));
7525                   if (IS_AOP_PREG (left))
7526                     {
7527                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7528                       aopPut (result, "a", offset);
7529                     }
7530                   else
7531                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7532                 }
7533             }
7534         }
7535     }
7536   else
7537     {
7538       // left & result in different registers
7539       if (AOP_TYPE (result) == AOP_CRY)
7540         {
7541           // result = bit
7542           // if(size), result in bit
7543           // if(!size && ifx), conditional oper: if(left ^ right)
7544           symbol *tlbl = newiTempLabel (NULL);
7545           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7546
7547           if (size)
7548             emitcode ("setb", "c");
7549           while (sizer--)
7550             {
7551               if ((AOP_TYPE (right) == AOP_LIT) &&
7552                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7553                 {
7554                   MOVA (aopGet (left, offset, FALSE, FALSE));
7555                 }
7556               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7557                   && AOP_TYPE(left)==AOP_ACC)
7558                 {
7559                   if (offset)
7560                     emitcode("mov", "a,b");
7561                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7562                 }
7563               else if (AOP_TYPE(left)==AOP_ACC)
7564                 {
7565                   if (!offset)
7566                     {
7567                       bool pushedB = pushB ();
7568                       emitcode("mov", "b,a");
7569                       MOVA (aopGet (right, offset, FALSE, FALSE));
7570                       emitcode("xrl", "a,b");
7571                       popB (pushedB);
7572                     }
7573                   else
7574                     {
7575                       MOVA (aopGet (right, offset, FALSE, FALSE));
7576                       emitcode("xrl", "a,b");
7577                     }
7578                 }
7579               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7580                 {
7581                   MOVB (aopGet (left, offset, FALSE, FALSE));
7582                   MOVA (aopGet (right, offset, FALSE, FALSE));
7583                   emitcode ("xrl", "a,b");
7584                 }
7585               else if (aopGetUsesAcc (left, offset))
7586                 {
7587                   MOVA (aopGet (left, offset, FALSE, FALSE));
7588                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7589                 }
7590               else
7591                 {
7592                   MOVA (aopGet (right, offset, FALSE, FALSE));
7593                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7594                 }
7595
7596               emitcode ("jnz", "%05d$", tlbl->key + 100);
7597               offset++;
7598             }
7599           if (size)
7600             {
7601               CLRC;
7602               emitLabel (tlbl);
7603               outBitC (result);
7604             }
7605           else if (ifx)
7606             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7607         }
7608       else
7609         {
7610           for (; (size--); offset++)
7611             {
7612               // normal case
7613               // result = left ^ right
7614               if (AOP_TYPE (right) == AOP_LIT)
7615                 {
7616                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7617                   if (bytelit == 0)
7618                     {
7619                       aopPut (result,
7620                               aopGet (left, offset, FALSE, FALSE),
7621                               offset);
7622                       continue;
7623                     }
7624                 }
7625               // faster than result <- left, xrl result,right
7626               // and better if result is SFR
7627               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7628                   && AOP_TYPE(left)==AOP_ACC)
7629                 {
7630                   if (offset)
7631                     emitcode("mov", "a,b");
7632                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7633                 }
7634               else if (AOP_TYPE(left)==AOP_ACC)
7635                 {
7636                   if (!offset)
7637                     {
7638                       bool pushedB = pushB ();
7639                       emitcode("mov", "b,a");
7640                       MOVA (aopGet (right, offset, FALSE, FALSE));
7641                       emitcode("xrl", "a,b");
7642                       popB (pushedB);
7643                     }
7644                   else
7645                     {
7646                       MOVA (aopGet (right, offset, FALSE, FALSE));
7647                       emitcode("xrl", "a,b");
7648                     }
7649                 }
7650               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7651                 {
7652                   MOVB (aopGet (left, offset, FALSE, FALSE));
7653                   MOVA (aopGet (right, offset, FALSE, FALSE));
7654                   emitcode ("xrl", "a,b");
7655                 }
7656               else if (aopGetUsesAcc (left, offset))
7657                 {
7658                   MOVA (aopGet (left, offset, FALSE, FALSE));
7659                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7660                 }
7661               else
7662                 {
7663                   MOVA (aopGet (right, offset, FALSE, FALSE));
7664                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7665                 }
7666               aopPut (result, "a", offset);
7667             }
7668         }
7669     }
7670
7671 release:
7672   freeAsmop (result, NULL, ic, TRUE);
7673   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7674   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7675 }
7676
7677 /*-----------------------------------------------------------------*/
7678 /* genInline - write the inline code out                           */
7679 /*-----------------------------------------------------------------*/
7680 static void
7681 genInline (iCode * ic)
7682 {
7683   char *buffer, *bp, *bp1;
7684
7685   D (emitcode (";", "genInline"));
7686
7687   _G.inLine += (!options.asmpeep);
7688
7689   buffer = bp = bp1 = Safe_strdup(IC_INLINE(ic));
7690
7691   /* emit each line as a code */
7692   while (*bp)
7693     {
7694       if (*bp == '\n')
7695         {
7696           *bp++ = '\0';
7697           emitcode (bp1, "");
7698           bp1 = bp;
7699         }
7700       else
7701         {
7702           /* Add \n for labels, not dirs such as c:\mydir */
7703           if ( (*bp == ':') && (isspace((unsigned char)bp[1])) )
7704             {
7705               bp++;
7706               *bp = '\0';
7707               bp++;
7708               emitcode (bp1, "");
7709               bp1 = bp;
7710             }
7711           else
7712             bp++;
7713         }
7714     }
7715   if (bp1 != bp)
7716     emitcode (bp1, "");
7717   /*     emitcode("",buffer); */
7718   _G.inLine -= (!options.asmpeep);
7719 }
7720
7721 /*-----------------------------------------------------------------*/
7722 /* genRRC - rotate right with carry                                */
7723 /*-----------------------------------------------------------------*/
7724 static void
7725 genRRC (iCode * ic)
7726 {
7727   operand *left, *result;
7728   int size, offset;
7729   char *l;
7730
7731   D (emitcode (";", "genRRC"));
7732
7733   /* rotate right with carry */
7734   left = IC_LEFT (ic);
7735   result = IC_RESULT (ic);
7736   aopOp (left, ic, FALSE);
7737   aopOp (result, ic, FALSE);
7738
7739   /* move it to the result */
7740   size = AOP_SIZE (result);
7741   offset = size - 1;
7742   if (size == 1) { /* special case for 1 byte */
7743       l = aopGet (left, offset, FALSE, FALSE);
7744       MOVA (l);
7745       emitcode ("rr", "a");
7746       goto release;
7747   }
7748   /* no need to clear carry, bit7 will be written later */
7749   while (size--)
7750     {
7751       l = aopGet (left, offset, FALSE, FALSE);
7752       MOVA (l);
7753       emitcode ("rrc", "a");
7754       if (AOP_SIZE (result) > 1)
7755         aopPut (result, "a", offset--);
7756     }
7757   /* now we need to put the carry into the
7758      highest order byte of the result */
7759   if (AOP_SIZE (result) > 1)
7760     {
7761       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7762       MOVA (l);
7763     }
7764   emitcode ("mov", "acc.7,c");
7765  release:
7766   aopPut (result, "a", AOP_SIZE (result) - 1);
7767   freeAsmop (result, NULL, ic, TRUE);
7768   freeAsmop (left, NULL, ic, TRUE);
7769 }
7770
7771 /*-----------------------------------------------------------------*/
7772 /* genRLC - generate code for rotate left with carry               */
7773 /*-----------------------------------------------------------------*/
7774 static void
7775 genRLC (iCode * ic)
7776 {
7777   operand *left, *result;
7778   int size, offset;
7779   char *l;
7780
7781   D (emitcode (";", "genRLC"));
7782
7783   /* rotate right with carry */
7784   left = IC_LEFT (ic);
7785   result = IC_RESULT (ic);
7786   aopOp (left, ic, FALSE);
7787   aopOp (result, ic, FALSE);
7788
7789   /* move it to the result */
7790   size = AOP_SIZE (result);
7791   offset = 0;
7792   if (size--)
7793     {
7794       l = aopGet (left, offset, FALSE, FALSE);
7795       MOVA (l);
7796       if (size == 0) { /* special case for 1 byte */
7797               emitcode("rl","a");
7798               goto release;
7799       }
7800       emitcode("rlc","a"); /* bit0 will be written later */
7801       if (AOP_SIZE (result) > 1)
7802         {
7803           aopPut (result, "a", offset++);
7804         }
7805
7806       while (size--)
7807         {
7808           l = aopGet (left, offset, FALSE, FALSE);
7809           MOVA (l);
7810           emitcode ("rlc", "a");
7811           if (AOP_SIZE (result) > 1)
7812             aopPut (result, "a", offset++);
7813         }
7814     }
7815   /* now we need to put the carry into the
7816      highest order byte of the result */
7817   if (AOP_SIZE (result) > 1)
7818     {
7819       l = aopGet (result, 0, FALSE, FALSE);
7820       MOVA (l);
7821     }
7822   emitcode ("mov", "acc.0,c");
7823  release:
7824   aopPut (result, "a", 0);
7825   freeAsmop (result, NULL, ic, TRUE);
7826   freeAsmop (left, NULL, ic, TRUE);
7827 }
7828
7829 /*-----------------------------------------------------------------*/
7830 /* genGetHbit - generates code get highest order bit               */
7831 /*-----------------------------------------------------------------*/
7832 static void
7833 genGetHbit (iCode * ic)
7834 {
7835   operand *left, *result;
7836
7837   D (emitcode (";", "genGetHbit"));
7838
7839   left = IC_LEFT (ic);
7840   result = IC_RESULT (ic);
7841   aopOp (left, ic, FALSE);
7842   aopOp (result, ic, FALSE);
7843
7844   /* get the highest order byte into a */
7845   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7846   if (AOP_TYPE (result) == AOP_CRY)
7847     {
7848       emitcode ("rlc", "a");
7849       outBitC (result);
7850     }
7851   else
7852     {
7853       emitcode ("rl", "a");
7854       emitcode ("anl", "a,#0x01");
7855       outAcc (result);
7856     }
7857
7858   freeAsmop (result, NULL, ic, TRUE);
7859   freeAsmop (left, NULL, ic, TRUE);
7860 }
7861
7862 /*-----------------------------------------------------------------*/
7863 /* genGetAbit - generates code get a single bit                    */
7864 /*-----------------------------------------------------------------*/
7865 static void
7866 genGetAbit (iCode * ic)
7867 {
7868   operand *left, *right, *result;
7869   int shCount;
7870
7871   D (emitcode (";", "genGetAbit"));
7872
7873   left = IC_LEFT (ic);
7874   right = IC_RIGHT (ic);
7875   result = IC_RESULT (ic);
7876   aopOp (left, ic, FALSE);
7877   aopOp (right, ic, FALSE);
7878   aopOp (result, ic, FALSE);
7879
7880   shCount = (int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7881
7882   /* get the needed byte into a */
7883   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7884   shCount %= 8;
7885   if (AOP_TYPE (result) == AOP_CRY)
7886     {
7887       if ((shCount) == 7)
7888           emitcode ("rlc", "a");
7889       else if ((shCount) == 0)
7890           emitcode ("rrc", "a");
7891       else
7892           emitcode ("mov", "c,acc[%d]", shCount);
7893       outBitC (result);
7894     }
7895   else
7896     {
7897       switch (shCount)
7898         {
7899         case 2:
7900           emitcode ("rr", "a");
7901           //fallthrough
7902         case 1:
7903           emitcode ("rr", "a");
7904           //fallthrough
7905         case 0:
7906           emitcode ("anl", "a,#0x01");
7907           break;
7908         case 3:
7909         case 5:
7910           emitcode ("mov", "c,acc[%d]", shCount);
7911           emitcode ("clr", "a");
7912           emitcode ("rlc", "a");
7913           break;
7914         case 4:
7915           emitcode ("swap", "a");
7916           emitcode ("anl", "a,#0x01");
7917           break;
7918         case 6:
7919           emitcode ("rl", "a");
7920           //fallthrough
7921         case 7:
7922           emitcode ("rl", "a");
7923           emitcode ("anl", "a,#0x01");
7924           break;
7925         }
7926       outAcc (result);
7927     }
7928
7929   freeAsmop (result, NULL, ic, TRUE);
7930   freeAsmop (right, NULL, ic, TRUE);
7931   freeAsmop (left, NULL, ic, TRUE);
7932 }
7933
7934 /*-----------------------------------------------------------------*/
7935 /* genGetByte - generates code get a single byte                   */
7936 /*-----------------------------------------------------------------*/
7937 static void
7938 genGetByte (iCode * ic)
7939 {
7940   operand *left, *right, *result;
7941   int offset;
7942
7943   D (emitcode (";", "genGetByte"));
7944
7945   left = IC_LEFT (ic);
7946   right = IC_RIGHT (ic);
7947   result = IC_RESULT (ic);
7948   aopOp (left, ic, FALSE);
7949   aopOp (right, ic, FALSE);
7950   aopOp (result, ic, FALSE);
7951
7952   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7953   aopPut (result,
7954           aopGet (left, offset, FALSE, FALSE),
7955           0);
7956
7957   freeAsmop (result, NULL, ic, TRUE);
7958   freeAsmop (right, NULL, ic, TRUE);
7959   freeAsmop (left, NULL, ic, TRUE);
7960 }
7961
7962 /*-----------------------------------------------------------------*/
7963 /* genGetWord - generates code get two bytes                       */
7964 /*-----------------------------------------------------------------*/
7965 static void
7966 genGetWord (iCode * ic)
7967 {
7968   operand *left, *right, *result;
7969   int offset;
7970
7971   D (emitcode (";", "genGetWord"));
7972
7973   left = IC_LEFT (ic);
7974   right = IC_RIGHT (ic);
7975   result = IC_RESULT (ic);
7976   aopOp (left, ic, FALSE);
7977   aopOp (right, ic, FALSE);
7978   aopOp (result, ic, FALSE);
7979
7980   offset = (int)floatFromVal (AOP (right)->aopu.aop_lit) / 8;
7981   aopPut (result,
7982           aopGet (left, offset, FALSE, FALSE),
7983           0);
7984   aopPut (result,
7985           aopGet (left, offset+1, FALSE, FALSE),
7986           1);
7987
7988   freeAsmop (result, NULL, ic, TRUE);
7989   freeAsmop (right, NULL, ic, TRUE);
7990   freeAsmop (left, NULL, ic, TRUE);
7991 }
7992
7993 /*-----------------------------------------------------------------*/
7994 /* genSwap - generates code to swap nibbles or bytes               */
7995 /*-----------------------------------------------------------------*/
7996 static void
7997 genSwap (iCode * ic)
7998 {
7999   operand *left, *result;
8000
8001   D(emitcode (";", "genSwap"));
8002
8003   left = IC_LEFT (ic);
8004   result = IC_RESULT (ic);
8005   aopOp (left, ic, FALSE);
8006   aopOp (result, ic, FALSE);
8007
8008   switch (AOP_SIZE (left))
8009     {
8010     case 1: /* swap nibbles in byte */
8011       MOVA (aopGet (left, 0, FALSE, FALSE));
8012       emitcode ("swap", "a");
8013       aopPut (result, "a", 0);
8014       break;
8015     case 2: /* swap bytes in word */
8016       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8017         {
8018           MOVA (aopGet (left, 0, FALSE, FALSE));
8019           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8020           aopPut (result, "a", 1);
8021         }
8022       else if (operandsEqu (left, result))
8023         {
8024           char * reg = "a";
8025           bool pushedB = FALSE, leftInB = FALSE;
8026
8027           MOVA (aopGet (left, 0, FALSE, FALSE));
8028           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8029             {
8030               pushedB = pushB ();
8031               emitcode ("mov", "b,a");
8032               reg = "b";
8033               leftInB = TRUE;
8034             }
8035           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8036           aopPut (result, reg, 1);
8037
8038           if (leftInB)
8039             popB (pushedB);
8040         }
8041       else
8042         {
8043           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8044           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8045         }
8046       break;
8047     default:
8048       wassertl(FALSE, "unsupported SWAP operand size");
8049     }
8050
8051   freeAsmop (result, NULL, ic, TRUE);
8052   freeAsmop (left, NULL, ic, TRUE);
8053 }
8054
8055 /*-----------------------------------------------------------------*/
8056 /* AccRol - rotate left accumulator by known count                 */
8057 /*-----------------------------------------------------------------*/
8058 static void
8059 AccRol (int shCount)
8060 {
8061   shCount &= 0x0007;            // shCount : 0..7
8062
8063   switch (shCount)
8064     {
8065     case 0:
8066       break;
8067     case 1:
8068       emitcode ("rl", "a");
8069       break;
8070     case 2:
8071       emitcode ("rl", "a");
8072       emitcode ("rl", "a");
8073       break;
8074     case 3:
8075       emitcode ("swap", "a");
8076       emitcode ("rr", "a");
8077       break;
8078     case 4:
8079       emitcode ("swap", "a");
8080       break;
8081     case 5:
8082       emitcode ("swap", "a");
8083       emitcode ("rl", "a");
8084       break;
8085     case 6:
8086       emitcode ("rr", "a");
8087       emitcode ("rr", "a");
8088       break;
8089     case 7:
8090       emitcode ("rr", "a");
8091       break;
8092     }
8093 }
8094
8095 /*-----------------------------------------------------------------*/
8096 /* AccLsh - left shift accumulator by known count                  */
8097 /*-----------------------------------------------------------------*/
8098 static void
8099 AccLsh (int shCount)
8100 {
8101   if (shCount != 0)
8102     {
8103       if (shCount == 1)
8104         emitcode ("add", "a,acc");
8105       else if (shCount == 2)
8106         {
8107           emitcode ("add", "a,acc");
8108           emitcode ("add", "a,acc");
8109         }
8110       else
8111         {
8112           /* rotate left accumulator */
8113           AccRol (shCount);
8114           /* and kill the lower order bits */
8115           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8116         }
8117     }
8118 }
8119
8120 /*-----------------------------------------------------------------*/
8121 /* AccRsh - right shift accumulator by known count                 */
8122 /*-----------------------------------------------------------------*/
8123 static void
8124 AccRsh (int shCount)
8125 {
8126   if (shCount != 0)
8127     {
8128       if (shCount == 1)
8129         {
8130           CLRC;
8131           emitcode ("rrc", "a");
8132         }
8133       else
8134         {
8135           /* rotate right accumulator */
8136           AccRol (8 - shCount);
8137           /* and kill the higher order bits */
8138           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8139         }
8140     }
8141 }
8142
8143 /*-----------------------------------------------------------------*/
8144 /* AccSRsh - signed right shift accumulator by known count                 */
8145 /*-----------------------------------------------------------------*/
8146 static void
8147 AccSRsh (int shCount)
8148 {
8149   symbol *tlbl;
8150   if (shCount != 0)
8151     {
8152       if (shCount == 1)
8153         {
8154           emitcode ("mov", "c,acc.7");
8155           emitcode ("rrc", "a");
8156         }
8157       else if (shCount == 2)
8158         {
8159           emitcode ("mov", "c,acc.7");
8160           emitcode ("rrc", "a");
8161           emitcode ("mov", "c,acc.7");
8162           emitcode ("rrc", "a");
8163         }
8164       else
8165         {
8166           tlbl = newiTempLabel (NULL);
8167           /* rotate right accumulator */
8168           AccRol (8 - shCount);
8169           /* and kill the higher order bits */
8170           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8171           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8172           emitcode ("orl", "a,#0x%02x",
8173                     (unsigned char) ~SRMask[shCount]);
8174           emitLabel (tlbl);
8175         }
8176     }
8177 }
8178
8179 /*-----------------------------------------------------------------*/
8180 /* shiftR1Left2Result - shift right one byte from left to result   */
8181 /*-----------------------------------------------------------------*/
8182 static void
8183 shiftR1Left2Result (operand * left, int offl,
8184                     operand * result, int offr,
8185                     int shCount, int sign)
8186 {
8187   MOVA (aopGet (left, offl, FALSE, FALSE));
8188   /* shift right accumulator */
8189   if (sign)
8190     AccSRsh (shCount);
8191   else
8192     AccRsh (shCount);
8193   aopPut (result, "a", offr);
8194 }
8195
8196 /*-----------------------------------------------------------------*/
8197 /* shiftL1Left2Result - shift left one byte from left to result    */
8198 /*-----------------------------------------------------------------*/
8199 static void
8200 shiftL1Left2Result (operand * left, int offl,
8201                     operand * result, int offr, int shCount)
8202 {
8203   char *l;
8204   l = aopGet (left, offl, FALSE, FALSE);
8205   MOVA (l);
8206   /* shift left accumulator */
8207   AccLsh (shCount);
8208   aopPut (result, "a", offr);
8209 }
8210
8211 /*-----------------------------------------------------------------*/
8212 /* movLeft2Result - move byte from left to result                  */
8213 /*-----------------------------------------------------------------*/
8214 static void
8215 movLeft2Result (operand * left, int offl,
8216                 operand * result, int offr, int sign)
8217 {
8218   char *l;
8219   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8220     {
8221       l = aopGet (left, offl, FALSE, FALSE);
8222
8223       if (*l == '@' && (IS_AOP_PREG (result)))
8224         {
8225           emitcode ("mov", "a,%s", l);
8226           aopPut (result, "a", offr);
8227         }
8228       else
8229         {
8230           if (!sign)
8231             {
8232               aopPut (result, l, offr);
8233             }
8234           else
8235             {
8236               /* MSB sign in acc.7 ! */
8237               if (getDataSize (left) == offl + 1)
8238                 {
8239                   MOVA (l);
8240                   aopPut (result, "a", offr);
8241                 }
8242             }
8243         }
8244     }
8245 }
8246
8247 /*-----------------------------------------------------------------*/
8248 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8249 /*-----------------------------------------------------------------*/
8250 static void
8251 AccAXRrl1 (char *x)
8252 {
8253   emitcode ("rrc", "a");
8254   emitcode ("xch", "a,%s", x);
8255   emitcode ("rrc", "a");
8256   emitcode ("xch", "a,%s", x);
8257 }
8258
8259 /*-----------------------------------------------------------------*/
8260 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8261 /*-----------------------------------------------------------------*/
8262 static void
8263 AccAXLrl1 (char *x)
8264 {
8265   emitcode ("xch", "a,%s", x);
8266   emitcode ("rlc", "a");
8267   emitcode ("xch", "a,%s", x);
8268   emitcode ("rlc", "a");
8269 }
8270
8271 /*-----------------------------------------------------------------*/
8272 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8273 /*-----------------------------------------------------------------*/
8274 static void
8275 AccAXLsh1 (char *x)
8276 {
8277   emitcode ("xch", "a,%s", x);
8278   emitcode ("add", "a,acc");
8279   emitcode ("xch", "a,%s", x);
8280   emitcode ("rlc", "a");
8281 }
8282
8283 /*-----------------------------------------------------------------*/
8284 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8285 /*-----------------------------------------------------------------*/
8286 static void
8287 AccAXLsh (char *x, int shCount)
8288 {
8289   switch (shCount)
8290     {
8291     case 0:
8292       break;
8293     case 1:
8294       AccAXLsh1 (x);
8295       break;
8296     case 2:
8297       AccAXLsh1 (x);
8298       AccAXLsh1 (x);
8299       break;
8300     case 3:
8301     case 4:
8302     case 5:                     // AAAAABBB:CCCCCDDD
8303
8304       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8305
8306       emitcode ("anl", "a,#0x%02x",
8307                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8308
8309       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8310
8311       AccRol (shCount);         // DDDCCCCC:BBB00000
8312
8313       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8314
8315       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8316
8317       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8318
8319       emitcode ("anl", "a,#0x%02x",
8320                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8321
8322       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8323
8324       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8325
8326       break;
8327     case 6:                     // AAAAAABB:CCCCCCDD
8328       emitcode ("anl", "a,#0x%02x",
8329                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8330       emitcode ("mov", "c,acc.0");      // c = B
8331       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8332 #if 0 // REMOVE ME
8333       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8334       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8335 #else
8336       emitcode("rrc","a");
8337       emitcode("xch","a,%s", x);
8338       emitcode("rrc","a");
8339       emitcode("mov","c,acc.0"); //<< get correct bit
8340       emitcode("xch","a,%s", x);
8341
8342       emitcode("rrc","a");
8343       emitcode("xch","a,%s", x);
8344       emitcode("rrc","a");
8345       emitcode("xch","a,%s", x);
8346 #endif
8347       break;
8348     case 7:                     // a:x <<= 7
8349
8350       emitcode ("anl", "a,#0x%02x",
8351                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8352
8353       emitcode ("mov", "c,acc.0");      // c = B
8354
8355       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8356
8357       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8358
8359       break;
8360     default:
8361       break;
8362     }
8363 }
8364
8365 /*-----------------------------------------------------------------*/
8366 /* AccAXRsh - right shift a:x known count (0..7)                   */
8367 /*-----------------------------------------------------------------*/
8368 static void
8369 AccAXRsh (char *x, int shCount)
8370 {
8371   switch (shCount)
8372     {
8373     case 0:
8374       break;
8375     case 1:
8376       CLRC;
8377       AccAXRrl1 (x);            // 0->a:x
8378
8379       break;
8380     case 2:
8381       CLRC;
8382       AccAXRrl1 (x);            // 0->a:x
8383
8384       CLRC;
8385       AccAXRrl1 (x);            // 0->a:x
8386
8387       break;
8388     case 3:
8389     case 4:
8390     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8391
8392       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8393
8394       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8395
8396       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8397
8398       emitcode ("anl", "a,#0x%02x",
8399                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8400
8401       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8402
8403       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8404
8405       emitcode ("anl", "a,#0x%02x",
8406                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8407
8408       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8409
8410       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8411
8412       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8413
8414       break;
8415     case 6:                     // AABBBBBB:CCDDDDDD
8416
8417       emitcode ("mov", "c,acc.7");
8418       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8419
8420       emitcode ("mov", "c,acc.7");
8421       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8422
8423       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8424
8425       emitcode ("anl", "a,#0x%02x",
8426                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8427
8428       break;
8429     case 7:                     // ABBBBBBB:CDDDDDDD
8430
8431       emitcode ("mov", "c,acc.7");      // c = A
8432
8433       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8434
8435       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8436
8437       emitcode ("anl", "a,#0x%02x",
8438                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8439
8440       break;
8441     default:
8442       break;
8443     }
8444 }
8445
8446 /*-----------------------------------------------------------------*/
8447 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8448 /*-----------------------------------------------------------------*/
8449 static void
8450 AccAXRshS (char *x, int shCount)
8451 {
8452   symbol *tlbl;
8453   switch (shCount)
8454     {
8455     case 0:
8456       break;
8457     case 1:
8458       emitcode ("mov", "c,acc.7");
8459       AccAXRrl1 (x);            // s->a:x
8460
8461       break;
8462     case 2:
8463       emitcode ("mov", "c,acc.7");
8464       AccAXRrl1 (x);            // s->a:x
8465
8466       emitcode ("mov", "c,acc.7");
8467       AccAXRrl1 (x);            // s->a:x
8468
8469       break;
8470     case 3:
8471     case 4:
8472     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8473
8474       tlbl = newiTempLabel (NULL);
8475       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8476
8477       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8478
8479       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8480
8481       emitcode ("anl", "a,#0x%02x",
8482                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8483
8484       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8485
8486       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8487
8488       emitcode ("anl", "a,#0x%02x",
8489                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8490
8491       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8492
8493       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8494
8495       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8496
8497       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8498       emitcode ("orl", "a,#0x%02x",
8499                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8500
8501       emitLabel (tlbl);
8502       break;                    // SSSSAAAA:BBBCCCCC
8503
8504     case 6:                     // AABBBBBB:CCDDDDDD
8505
8506       tlbl = newiTempLabel (NULL);
8507       emitcode ("mov", "c,acc.7");
8508       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8509
8510       emitcode ("mov", "c,acc.7");
8511       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8512
8513       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8514
8515       emitcode ("anl", "a,#0x%02x",
8516                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8517
8518       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8519       emitcode ("orl", "a,#0x%02x",
8520                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8521
8522       emitLabel (tlbl);
8523       break;
8524     case 7:                     // ABBBBBBB:CDDDDDDD
8525
8526       tlbl = newiTempLabel (NULL);
8527       emitcode ("mov", "c,acc.7");      // c = A
8528
8529       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8530
8531       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8532
8533       emitcode ("anl", "a,#0x%02x",
8534                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8535
8536       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8537       emitcode ("orl", "a,#0x%02x",
8538                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8539
8540       emitLabel (tlbl);
8541       break;
8542     default:
8543       break;
8544     }
8545 }
8546
8547 /*-----------------------------------------------------------------*/
8548 /* shiftL2Left2Result - shift left two bytes from left to result   */
8549 /*-----------------------------------------------------------------*/
8550 static void
8551 shiftL2Left2Result (operand * left, int offl,
8552                     operand * result, int offr, int shCount)
8553 {
8554   char * x;
8555   bool pushedB = FALSE;
8556   bool usedB = FALSE;
8557
8558   if (sameRegs (AOP (result), AOP (left)) &&
8559       ((offl + MSB16) == offr))
8560     {
8561       /* don't crash result[offr] */
8562       MOVA (aopGet (left, offl, FALSE, FALSE));
8563       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8564       usedB = !strncmp(x, "b", 1);
8565     }
8566   else if (aopGetUsesAcc (result, offr))
8567     {
8568       movLeft2Result (left, offl, result, offr, 0);
8569       pushedB = pushB ();
8570       usedB = TRUE;
8571       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8572       MOVA (aopGet (result, offr, FALSE, FALSE));
8573       emitcode ("xch", "a,b");
8574       x = "b";
8575     }
8576   else
8577     {
8578       movLeft2Result (left, offl, result, offr, 0);
8579       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8580       x = aopGet (result, offr, FALSE, FALSE);
8581     }
8582   /* ax << shCount (x = lsb(result)) */
8583   AccAXLsh (x, shCount);
8584   if (usedB)
8585     {
8586       emitcode ("xch", "a,b");
8587       aopPut (result, "a", offr);
8588       aopPut (result, "b", offr + MSB16);
8589       popB (pushedB);
8590     }
8591   else
8592     {
8593       aopPut (result, "a", offr + MSB16);
8594     }
8595 }
8596
8597
8598 /*-----------------------------------------------------------------*/
8599 /* shiftR2Left2Result - shift right two bytes from left to result  */
8600 /*-----------------------------------------------------------------*/
8601 static void
8602 shiftR2Left2Result (operand * left, int offl,
8603                     operand * result, int offr,
8604                     int shCount, int sign)
8605 {
8606   char * x;
8607   bool pushedB = FALSE;
8608   bool usedB = FALSE;
8609
8610   if (sameRegs (AOP (result), AOP (left)) &&
8611       ((offl + MSB16) == offr))
8612     {
8613       /* don't crash result[offr] */
8614       MOVA (aopGet (left, offl, FALSE, FALSE));
8615       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8616       usedB = !strncmp(x, "b", 1);
8617     }
8618   else if (aopGetUsesAcc (result, offr))
8619     {
8620       movLeft2Result (left, offl, result, offr, 0);
8621       pushedB = pushB ();
8622       usedB = TRUE;
8623       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8624       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8625       x = "b";
8626     }
8627   else
8628     {
8629       movLeft2Result (left, offl, result, offr, 0);
8630       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8631       x = aopGet (result, offr, FALSE, FALSE);
8632     }
8633   /* a:x >> shCount (x = lsb(result)) */
8634   if (sign)
8635     AccAXRshS (x, shCount);
8636   else
8637     AccAXRsh (x, shCount);
8638   if (usedB)
8639     {
8640       emitcode ("xch", "a,b");
8641       aopPut (result, "a", offr);
8642       emitcode ("xch", "a,b");
8643       popB (pushedB);
8644     }
8645   if (getDataSize (result) > 1)
8646     aopPut (result, "a", offr + MSB16);
8647 }
8648
8649 /*-----------------------------------------------------------------*/
8650 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8651 /*-----------------------------------------------------------------*/
8652 static void
8653 shiftLLeftOrResult (operand * left, int offl,
8654                     operand * result, int offr, int shCount)
8655 {
8656   MOVA (aopGet (left, offl, FALSE, FALSE));
8657   /* shift left accumulator */
8658   AccLsh (shCount);
8659   /* or with result */
8660   if (aopGetUsesAcc (result, offr))
8661     {
8662       emitcode ("xch", "a,b");
8663       MOVA (aopGet (result, offr, FALSE, FALSE));
8664       emitcode ("orl", "a,b");
8665     }
8666   else
8667     {
8668       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8669     }
8670   /* back to result */
8671   aopPut (result, "a", offr);
8672 }
8673
8674 /*-----------------------------------------------------------------*/
8675 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8676 /*-----------------------------------------------------------------*/
8677 static void
8678 shiftRLeftOrResult (operand * left, int offl,
8679                     operand * result, int offr, int shCount)
8680 {
8681   MOVA (aopGet (left, offl, FALSE, FALSE));
8682   /* shift right accumulator */
8683   AccRsh (shCount);
8684   /* or with result */
8685   if (aopGetUsesAcc(result, offr))
8686     {
8687       emitcode ("xch", "a,b");
8688       MOVA (aopGet (result, offr, FALSE, FALSE));
8689       emitcode ("orl", "a,b");
8690     }
8691   else
8692     {
8693       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8694     }
8695   /* back to result */
8696   aopPut (result, "a", offr);
8697 }
8698
8699 /*-----------------------------------------------------------------*/
8700 /* genlshOne - left shift a one byte quantity by known count       */
8701 /*-----------------------------------------------------------------*/
8702 static void
8703 genlshOne (operand * result, operand * left, int shCount)
8704 {
8705   D (emitcode (";", "genlshOne"));
8706
8707   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8708 }
8709
8710 /*-----------------------------------------------------------------*/
8711 /* genlshTwo - left shift two bytes by known amount != 0           */
8712 /*-----------------------------------------------------------------*/
8713 static void
8714 genlshTwo (operand * result, operand * left, int shCount)
8715 {
8716   int size;
8717
8718   D (emitcode (";", "genlshTwo"));
8719
8720   size = getDataSize (result);
8721
8722   /* if shCount >= 8 */
8723   if (shCount >= 8)
8724     {
8725       shCount -= 8;
8726
8727       if (size > 1)
8728         {
8729           if (shCount)
8730             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8731           else
8732             movLeft2Result (left, LSB, result, MSB16, 0);
8733         }
8734       aopPut (result, zero, LSB);
8735     }
8736
8737   /*  1 <= shCount <= 7 */
8738   else
8739     {
8740       if (size == 1)
8741         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8742       else
8743         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8744     }
8745 }
8746
8747 /*-----------------------------------------------------------------*/
8748 /* shiftLLong - shift left one long from left to result            */
8749 /* offl = LSB or MSB16                                             */
8750 /*-----------------------------------------------------------------*/
8751 static void
8752 shiftLLong (operand * left, operand * result, int offr)
8753 {
8754   char *l;
8755   int size = AOP_SIZE (result);
8756
8757   if (size >= LSB + offr)
8758     {
8759       l = aopGet (left, LSB, FALSE, FALSE);
8760       MOVA (l);
8761       emitcode ("add", "a,acc");
8762       if (sameRegs (AOP (left), AOP (result)) &&
8763           size >= MSB16 + offr && offr != LSB)
8764         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8765       else
8766         aopPut (result, "a", LSB + offr);
8767     }
8768
8769   if (size >= MSB16 + offr)
8770     {
8771       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8772         {
8773           l = aopGet (left, MSB16, FALSE, FALSE);
8774           MOVA (l);
8775         }
8776       emitcode ("rlc", "a");
8777       if (sameRegs (AOP (left), AOP (result)) &&
8778           size >= MSB24 + offr && offr != LSB)
8779         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8780       else
8781         aopPut (result, "a", MSB16 + offr);
8782     }
8783
8784   if (size >= MSB24 + offr)
8785     {
8786       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8787         {
8788           l = aopGet (left, MSB24, FALSE, FALSE);
8789           MOVA (l);
8790         }
8791       emitcode ("rlc", "a");
8792       if (sameRegs (AOP (left), AOP (result)) &&
8793           size >= MSB32 + offr && offr != LSB)
8794         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8795       else
8796         aopPut (result, "a", MSB24 + offr);
8797     }
8798
8799   if (size > MSB32 + offr)
8800     {
8801       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8802         {
8803           l = aopGet (left, MSB32, FALSE, FALSE);
8804           MOVA (l);
8805         }
8806       emitcode ("rlc", "a");
8807       aopPut (result, "a", MSB32 + offr);
8808     }
8809   if (offr != LSB)
8810     aopPut (result, zero, LSB);
8811 }
8812
8813 /*-----------------------------------------------------------------*/
8814 /* genlshFour - shift four byte by a known amount != 0             */
8815 /*-----------------------------------------------------------------*/
8816 static void
8817 genlshFour (operand * result, operand * left, int shCount)
8818 {
8819   int size;
8820
8821   D (emitcode (";", "genlshFour"));
8822
8823   size = AOP_SIZE (result);
8824
8825   /* if shifting more that 3 bytes */
8826   if (shCount >= 24)
8827     {
8828       shCount -= 24;
8829       if (shCount)
8830         /* lowest order of left goes to the highest
8831            order of the destination */
8832         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8833       else
8834         movLeft2Result (left, LSB, result, MSB32, 0);
8835       aopPut (result, zero, LSB);
8836       aopPut (result, zero, MSB16);
8837       aopPut (result, zero, MSB24);
8838       return;
8839     }
8840
8841   /* more than two bytes */
8842   else if (shCount >= 16)
8843     {
8844       /* lower order two bytes goes to higher order two bytes */
8845       shCount -= 16;
8846       /* if some more remaining */
8847       if (shCount)
8848         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8849       else
8850         {
8851           movLeft2Result (left, MSB16, result, MSB32, 0);
8852           movLeft2Result (left, LSB, result, MSB24, 0);
8853         }
8854       aopPut (result, zero, MSB16);
8855       aopPut (result, zero, LSB);
8856       return;
8857     }
8858
8859   /* if more than 1 byte */
8860   else if (shCount >= 8)
8861     {
8862       /* lower order three bytes goes to higher order  three bytes */
8863       shCount -= 8;
8864       if (size == 2)
8865         {
8866           if (shCount)
8867             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8868           else
8869             movLeft2Result (left, LSB, result, MSB16, 0);
8870         }
8871       else
8872         {                       /* size = 4 */
8873           if (shCount == 0)
8874             {
8875               movLeft2Result (left, MSB24, result, MSB32, 0);
8876               movLeft2Result (left, MSB16, result, MSB24, 0);
8877               movLeft2Result (left, LSB, result, MSB16, 0);
8878               aopPut (result, zero, LSB);
8879             }
8880           else if (shCount == 1)
8881             shiftLLong (left, result, MSB16);
8882           else
8883             {
8884               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8885               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8886               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8887               aopPut (result, zero, LSB);
8888             }
8889         }
8890     }
8891
8892   /* 1 <= shCount <= 7 */
8893   else if (shCount <= 2)
8894     {
8895       shiftLLong (left, result, LSB);
8896       if (shCount == 2)
8897         shiftLLong (result, result, LSB);
8898     }
8899   /* 3 <= shCount <= 7, optimize */
8900   else
8901     {
8902       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8903       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8904       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8905     }
8906 }
8907
8908 /*-----------------------------------------------------------------*/
8909 /* genLeftShiftLiteral - left shifting by known count              */
8910 /*-----------------------------------------------------------------*/
8911 static void
8912 genLeftShiftLiteral (operand * left,
8913                      operand * right,
8914                      operand * result,
8915                      iCode * ic)
8916 {
8917   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8918   int size;
8919
8920   D (emitcode (";", "genLeftShiftLiteral"));
8921
8922   freeAsmop (right, NULL, ic, TRUE);
8923
8924   aopOp (left, ic, FALSE);
8925   aopOp (result, ic, FALSE);
8926
8927   size = getSize (operandType (result));
8928
8929 #if VIEW_SIZE
8930   emitcode ("; shift left ", "result %d, left %d", size,
8931             AOP_SIZE (left));
8932 #endif
8933
8934   /* I suppose that the left size >= result size */
8935   if (shCount == 0)
8936     {
8937       while (size--)
8938         {
8939           movLeft2Result (left, size, result, size, 0);
8940         }
8941     }
8942   else if (shCount >= (size * 8))
8943     {
8944       while (size--)
8945         {
8946           aopPut (result, zero, size);
8947         }
8948     }
8949   else
8950     {
8951       switch (size)
8952         {
8953         case 1:
8954           genlshOne (result, left, shCount);
8955           break;
8956
8957         case 2:
8958           genlshTwo (result, left, shCount);
8959           break;
8960
8961         case 4:
8962           genlshFour (result, left, shCount);
8963           break;
8964         default:
8965           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
8966                   "*** ack! mystery literal shift!\n");
8967           break;
8968         }
8969     }
8970   freeAsmop (result, NULL, ic, TRUE);
8971   freeAsmop (left, NULL, ic, TRUE);
8972 }
8973
8974 /*-----------------------------------------------------------------*/
8975 /* genLeftShift - generates code for left shifting                 */
8976 /*-----------------------------------------------------------------*/
8977 static void
8978 genLeftShift (iCode * ic)
8979 {
8980   operand *left, *right, *result;
8981   int size, offset;
8982   char *l;
8983   symbol *tlbl, *tlbl1;
8984   bool pushedB;
8985
8986   D (emitcode (";", "genLeftShift"));
8987
8988   right = IC_RIGHT (ic);
8989   left = IC_LEFT (ic);
8990   result = IC_RESULT (ic);
8991
8992   aopOp (right, ic, FALSE);
8993
8994   /* if the shift count is known then do it
8995      as efficiently as possible */
8996   if (AOP_TYPE (right) == AOP_LIT)
8997     {
8998       genLeftShiftLiteral (left, right, result, ic);
8999       return;
9000     }
9001
9002   /* shift count is unknown then we have to form
9003      a loop get the loop count in B : Note: we take
9004      only the lower order byte since shifting
9005      more that 32 bits make no sense anyway, ( the
9006      largest size of an object can be only 32 bits ) */
9007
9008   pushedB = pushB ();
9009   MOVB (aopGet (right, 0, FALSE, FALSE));
9010   emitcode ("inc", "b");
9011   freeAsmop (right, NULL, ic, TRUE);
9012   aopOp (left, ic, FALSE);
9013   aopOp (result, ic, FALSE);
9014
9015   /* now move the left to the result if they are not the same */
9016   if (!sameRegs (AOP (left), AOP (result)) &&
9017       AOP_SIZE (result) > 1)
9018     {
9019
9020       size = AOP_SIZE (result);
9021       offset = 0;
9022       while (size--)
9023         {
9024           l = aopGet (left, offset, FALSE, TRUE);
9025           if (*l == '@' && (IS_AOP_PREG (result)))
9026             {
9027
9028               emitcode ("mov", "a,%s", l);
9029               aopPut (result, "a", offset);
9030             }
9031           else
9032             aopPut (result, l, offset);
9033           offset++;
9034         }
9035     }
9036
9037   tlbl = newiTempLabel (NULL);
9038   size = AOP_SIZE (result);
9039   offset = 0;
9040   tlbl1 = newiTempLabel (NULL);
9041
9042   /* if it is only one byte then */
9043   if (size == 1)
9044     {
9045       symbol *tlbl1 = newiTempLabel (NULL);
9046
9047       l = aopGet (left, 0, FALSE, FALSE);
9048       MOVA (l);
9049       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9050       emitLabel (tlbl);
9051       emitcode ("add", "a,acc");
9052       emitLabel (tlbl1);
9053       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9054       popB (pushedB);
9055       aopPut (result, "a", 0);
9056       goto release;
9057     }
9058
9059   reAdjustPreg (AOP (result));
9060
9061   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9062   emitLabel (tlbl);
9063   l = aopGet (result, offset, FALSE, FALSE);
9064   MOVA (l);
9065   emitcode ("add", "a,acc");
9066   aopPut (result, "a", offset++);
9067   while (--size)
9068     {
9069       l = aopGet (result, offset, FALSE, FALSE);
9070       MOVA (l);
9071       emitcode ("rlc", "a");
9072       aopPut (result, "a", offset++);
9073     }
9074   reAdjustPreg (AOP (result));
9075
9076   emitLabel (tlbl1);
9077   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9078   popB (pushedB);
9079 release:
9080   freeAsmop (result, NULL, ic, TRUE);
9081   freeAsmop (left, NULL, ic, TRUE);
9082 }
9083
9084 /*-----------------------------------------------------------------*/
9085 /* genrshOne - right shift a one byte quantity by known count      */
9086 /*-----------------------------------------------------------------*/
9087 static void
9088 genrshOne (operand * result, operand * left,
9089            int shCount, int sign)
9090 {
9091   D (emitcode (";", "genrshOne"));
9092
9093   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9094 }
9095
9096 /*-----------------------------------------------------------------*/
9097 /* genrshTwo - right shift two bytes by known amount != 0          */
9098 /*-----------------------------------------------------------------*/
9099 static void
9100 genrshTwo (operand * result, operand * left,
9101            int shCount, int sign)
9102 {
9103   D (emitcode (";", "genrshTwo"));
9104
9105   /* if shCount >= 8 */
9106   if (shCount >= 8)
9107     {
9108       shCount -= 8;
9109       if (shCount)
9110         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9111       else
9112         movLeft2Result (left, MSB16, result, LSB, sign);
9113       addSign (result, MSB16, sign);
9114     }
9115
9116   /*  1 <= shCount <= 7 */
9117   else
9118     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9119 }
9120
9121 /*-----------------------------------------------------------------*/
9122 /* shiftRLong - shift right one long from left to result           */
9123 /* offl = LSB or MSB16                                             */
9124 /*-----------------------------------------------------------------*/
9125 static void
9126 shiftRLong (operand * left, int offl,
9127             operand * result, int sign)
9128 {
9129   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9130
9131   if (overlapping && offl>1)
9132     {
9133       // we are in big trouble, but this shouldn't happen
9134       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9135     }
9136
9137   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9138
9139   if (offl==MSB16)
9140     {
9141       // shift is > 8
9142       if (sign)
9143         {
9144           emitcode ("rlc", "a");
9145           emitcode ("subb", "a,acc");
9146           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9147             {
9148               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9149             }
9150           else
9151             {
9152               aopPut (result, "a", MSB32);
9153               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9154             }
9155         }
9156       else
9157         {
9158           if (aopPutUsesAcc (result, zero, MSB32))
9159             {
9160               emitcode("xch", "a,b");
9161               aopPut (result, zero, MSB32);
9162               emitcode("xch", "a,b");
9163             }
9164           else
9165             {
9166               aopPut (result, zero, MSB32);
9167             }
9168         }
9169     }
9170
9171   if (!sign)
9172     {
9173       emitcode ("clr", "c");
9174     }
9175   else
9176     {
9177       emitcode ("mov", "c,acc.7");
9178     }
9179
9180   emitcode ("rrc", "a");
9181
9182   if (overlapping && offl==MSB16 &&
9183       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9184     {
9185       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9186     }
9187   else
9188     {
9189       aopPut (result, "a", MSB32 - offl);
9190       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9191     }
9192
9193   emitcode ("rrc", "a");
9194   if (overlapping && offl==MSB16 &&
9195       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9196     {
9197       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9198     }
9199   else
9200     {
9201       aopPut (result, "a", MSB24 - offl);
9202       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9203     }
9204
9205   emitcode ("rrc", "a");
9206   if (offl != LSB)
9207     {
9208       aopPut (result, "a", MSB16 - offl);
9209     }
9210   else
9211     {
9212       if (overlapping &&
9213           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9214         {
9215           xch_a_aopGet (left, LSB, FALSE, FALSE);
9216         }
9217       else
9218         {
9219           aopPut (result, "a", MSB16 - offl);
9220           MOVA (aopGet (left, LSB, FALSE, FALSE));
9221         }
9222       emitcode ("rrc", "a");
9223       aopPut (result, "a", LSB);
9224     }
9225 }
9226
9227 /*-----------------------------------------------------------------*/
9228 /* genrshFour - shift four byte by a known amount != 0             */
9229 /*-----------------------------------------------------------------*/
9230 static void
9231 genrshFour (operand * result, operand * left,
9232             int shCount, int sign)
9233 {
9234   D (emitcode (";", "genrshFour"));
9235
9236   /* if shifting more that 3 bytes */
9237   if (shCount >= 24)
9238     {
9239       shCount -= 24;
9240       if (shCount)
9241         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9242       else
9243         movLeft2Result (left, MSB32, result, LSB, sign);
9244       addSign (result, MSB16, sign);
9245     }
9246   else if (shCount >= 16)
9247     {
9248       shCount -= 16;
9249       if (shCount)
9250         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9251       else
9252         {
9253           movLeft2Result (left, MSB24, result, LSB, 0);
9254           movLeft2Result (left, MSB32, result, MSB16, sign);
9255         }
9256       addSign (result, MSB24, sign);
9257     }
9258   else if (shCount >= 8)
9259     {
9260       shCount -= 8;
9261       if (shCount == 1)
9262         {
9263           shiftRLong (left, MSB16, result, sign);
9264         }
9265       else if (shCount == 0)
9266         {
9267           movLeft2Result (left, MSB16, result, LSB, 0);
9268           movLeft2Result (left, MSB24, result, MSB16, 0);
9269           movLeft2Result (left, MSB32, result, MSB24, sign);
9270           addSign (result, MSB32, sign);
9271         }
9272       else
9273         {
9274           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9275           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9276           /* the last shift is signed */
9277           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9278           addSign (result, MSB32, sign);
9279         }
9280     }
9281   else
9282     {
9283       /* 1 <= shCount <= 7 */
9284       if (shCount <= 2)
9285         {
9286           shiftRLong (left, LSB, result, sign);
9287           if (shCount == 2)
9288             shiftRLong (result, LSB, result, sign);
9289         }
9290       else
9291         {
9292           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9293           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9294           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9295         }
9296     }
9297 }
9298
9299 /*-----------------------------------------------------------------*/
9300 /* genRightShiftLiteral - right shifting by known count            */
9301 /*-----------------------------------------------------------------*/
9302 static void
9303 genRightShiftLiteral (operand * left,
9304                       operand * right,
9305                       operand * result,
9306                       iCode * ic,
9307                       int sign)
9308 {
9309   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9310   int size;
9311
9312   D (emitcode (";", "genRightShiftLiteral"));
9313
9314   freeAsmop (right, NULL, ic, TRUE);
9315
9316   aopOp (left, ic, FALSE);
9317   aopOp (result, ic, FALSE);
9318
9319 #if VIEW_SIZE
9320   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9321             AOP_SIZE (left));
9322 #endif
9323
9324   size = getDataSize (left);
9325   /* test the LEFT size !!! */
9326
9327   /* I suppose that the left size >= result size */
9328   if (shCount == 0)
9329     {
9330       size = getDataSize (result);
9331       while (size--)
9332         movLeft2Result (left, size, result, size, 0);
9333     }
9334
9335   else if (shCount >= (size * 8))
9336     {
9337       if (sign)
9338         {
9339           /* get sign in acc.7 */
9340           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9341         }
9342       addSign (result, LSB, sign);
9343     }
9344   else
9345     {
9346       switch (size)
9347         {
9348         case 1:
9349           genrshOne (result, left, shCount, sign);
9350           break;
9351
9352         case 2:
9353           genrshTwo (result, left, shCount, sign);
9354           break;
9355
9356         case 4:
9357           genrshFour (result, left, shCount, sign);
9358           break;
9359         default:
9360           break;
9361         }
9362     }
9363   freeAsmop (result, NULL, ic, TRUE);
9364   freeAsmop (left, NULL, ic, TRUE);
9365 }
9366
9367 /*-----------------------------------------------------------------*/
9368 /* genSignedRightShift - right shift of signed number              */
9369 /*-----------------------------------------------------------------*/
9370 static void
9371 genSignedRightShift (iCode * ic)
9372 {
9373   operand *right, *left, *result;
9374   int size, offset;
9375   char *l;
9376   symbol *tlbl, *tlbl1;
9377   bool pushedB;
9378
9379   D (emitcode (";", "genSignedRightShift"));
9380
9381   /* we do it the hard way put the shift count in b
9382      and loop thru preserving the sign */
9383
9384   right = IC_RIGHT (ic);
9385   left = IC_LEFT (ic);
9386   result = IC_RESULT (ic);
9387
9388   aopOp (right, ic, FALSE);
9389
9390
9391   if (AOP_TYPE (right) == AOP_LIT)
9392     {
9393       genRightShiftLiteral (left, right, result, ic, 1);
9394       return;
9395     }
9396   /* shift count is unknown then we have to form
9397      a loop get the loop count in B : Note: we take
9398      only the lower order byte since shifting
9399      more that 32 bits make no sense anyway, ( the
9400      largest size of an object can be only 32 bits ) */
9401
9402   pushedB = pushB ();
9403   MOVB (aopGet (right, 0, FALSE, FALSE));
9404   emitcode ("inc", "b");
9405   freeAsmop (right, NULL, ic, TRUE);
9406   aopOp (left, ic, FALSE);
9407   aopOp (result, ic, FALSE);
9408
9409   /* now move the left to the result if they are not the
9410      same */
9411   if (!sameRegs (AOP (left), AOP (result)) &&
9412       AOP_SIZE (result) > 1)
9413     {
9414
9415       size = AOP_SIZE (result);
9416       offset = 0;
9417       while (size--)
9418         {
9419           l = aopGet (left, offset, FALSE, TRUE);
9420           if (*l == '@' && IS_AOP_PREG (result))
9421             {
9422
9423               emitcode ("mov", "a,%s", l);
9424               aopPut (result, "a", offset);
9425             }
9426           else
9427             aopPut (result, l, offset);
9428           offset++;
9429         }
9430     }
9431
9432   /* mov the highest order bit to OVR */
9433   tlbl = newiTempLabel (NULL);
9434   tlbl1 = newiTempLabel (NULL);
9435
9436   size = AOP_SIZE (result);
9437   offset = size - 1;
9438   MOVA (aopGet (left, offset, FALSE, FALSE));
9439   emitcode ("rlc", "a");
9440   emitcode ("mov", "ov,c");
9441   /* if it is only one byte then */
9442   if (size == 1)
9443     {
9444       l = aopGet (left, 0, FALSE, FALSE);
9445       MOVA (l);
9446       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9447       emitLabel (tlbl);
9448       emitcode ("mov", "c,ov");
9449       emitcode ("rrc", "a");
9450       emitLabel (tlbl1);
9451       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9452       popB (pushedB);
9453       aopPut (result, "a", 0);
9454       goto release;
9455     }
9456
9457   reAdjustPreg (AOP (result));
9458   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9459   emitLabel (tlbl);
9460   emitcode ("mov", "c,ov");
9461   while (size--)
9462     {
9463       l = aopGet (result, offset, FALSE, FALSE);
9464       MOVA (l);
9465       emitcode ("rrc", "a");
9466       aopPut (result, "a", offset--);
9467     }
9468   reAdjustPreg (AOP (result));
9469   emitLabel (tlbl1);
9470   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9471   popB (pushedB);
9472
9473 release:
9474   freeAsmop (result, NULL, ic, TRUE);
9475   freeAsmop (left, NULL, ic, TRUE);
9476 }
9477
9478 /*-----------------------------------------------------------------*/
9479 /* genRightShift - generate code for right shifting                */
9480 /*-----------------------------------------------------------------*/
9481 static void
9482 genRightShift (iCode * ic)
9483 {
9484   operand *right, *left, *result;
9485   sym_link *letype;
9486   int size, offset;
9487   char *l;
9488   symbol *tlbl, *tlbl1;
9489   bool pushedB;
9490
9491   D (emitcode (";", "genRightShift"));
9492
9493   /* if signed then we do it the hard way preserve the
9494      sign bit moving it inwards */
9495   letype = getSpec (operandType (IC_LEFT (ic)));
9496
9497   if (!SPEC_USIGN (letype))
9498     {
9499       genSignedRightShift (ic);
9500       return;
9501     }
9502
9503   /* signed & unsigned types are treated the same : i.e. the
9504      signed is NOT propagated inwards : quoting from the
9505      ANSI - standard : "for E1 >> E2, is equivalent to division
9506      by 2**E2 if unsigned or if it has a non-negative value,
9507      otherwise the result is implementation defined ", MY definition
9508      is that the sign does not get propagated */
9509
9510   right = IC_RIGHT (ic);
9511   left = IC_LEFT (ic);
9512   result = IC_RESULT (ic);
9513
9514   aopOp (right, ic, FALSE);
9515
9516   /* if the shift count is known then do it
9517      as efficiently as possible */
9518   if (AOP_TYPE (right) == AOP_LIT)
9519     {
9520       genRightShiftLiteral (left, right, result, ic, 0);
9521       return;
9522     }
9523
9524   /* shift count is unknown then we have to form
9525      a loop get the loop count in B : Note: we take
9526      only the lower order byte since shifting
9527      more that 32 bits make no sense anyway, ( the
9528      largest size of an object can be only 32 bits ) */
9529
9530   pushedB = pushB ();
9531   MOVB (aopGet (right, 0, FALSE, FALSE));
9532   emitcode ("inc", "b");
9533   freeAsmop (right, NULL, ic, TRUE);
9534   aopOp (left, ic, FALSE);
9535   aopOp (result, ic, FALSE);
9536
9537   /* now move the left to the result if they are not the
9538      same */
9539   if (!sameRegs (AOP (left), AOP (result)) &&
9540       AOP_SIZE (result) > 1)
9541     {
9542       size = AOP_SIZE (result);
9543       offset = 0;
9544       while (size--)
9545         {
9546           l = aopGet (left, offset, FALSE, TRUE);
9547           if (*l == '@' && IS_AOP_PREG (result))
9548             {
9549
9550               emitcode ("mov", "a,%s", l);
9551               aopPut (result, "a", offset);
9552             }
9553           else
9554             aopPut (result, l, offset);
9555           offset++;
9556         }
9557     }
9558
9559   tlbl = newiTempLabel (NULL);
9560   tlbl1 = newiTempLabel (NULL);
9561   size = AOP_SIZE (result);
9562   offset = size - 1;
9563
9564   /* if it is only one byte then */
9565   if (size == 1)
9566     {
9567       l = aopGet (left, 0, FALSE, FALSE);
9568       MOVA (l);
9569       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9570       emitLabel (tlbl);
9571       CLRC;
9572       emitcode ("rrc", "a");
9573       emitLabel (tlbl1);
9574       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9575       popB (pushedB);
9576       aopPut (result, "a", 0);
9577       goto release;
9578     }
9579
9580   reAdjustPreg (AOP (result));
9581   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9582   emitLabel (tlbl);
9583   CLRC;
9584   while (size--)
9585     {
9586       l = aopGet (result, offset, FALSE, FALSE);
9587       MOVA (l);
9588       emitcode ("rrc", "a");
9589       aopPut (result, "a", offset--);
9590     }
9591   reAdjustPreg (AOP (result));
9592
9593   emitLabel (tlbl1);
9594   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9595   popB (pushedB);
9596
9597 release:
9598   freeAsmop (result, NULL, ic, TRUE);
9599   freeAsmop (left, NULL, ic, TRUE);
9600 }
9601
9602 /*-----------------------------------------------------------------*/
9603 /* emitPtrByteGet - emits code to get a byte into A through a      */
9604 /*                  pointer register (R0, R1, or DPTR). The        */
9605 /*                  original value of A can be preserved in B.     */
9606 /*-----------------------------------------------------------------*/
9607 static void
9608 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9609 {
9610   switch (p_type)
9611     {
9612     case IPOINTER:
9613     case POINTER:
9614       if (preserveAinB)
9615         emitcode ("mov", "b,a");
9616       emitcode ("mov", "a,@%s", rname);
9617       break;
9618
9619     case PPOINTER:
9620       if (preserveAinB)
9621         emitcode ("mov", "b,a");
9622       emitcode ("movx", "a,@%s", rname);
9623       break;
9624
9625     case FPOINTER:
9626       if (preserveAinB)
9627         emitcode ("mov", "b,a");
9628       emitcode ("movx", "a,@dptr");
9629       break;
9630
9631     case CPOINTER:
9632       if (preserveAinB)
9633         emitcode ("mov", "b,a");
9634       emitcode ("clr", "a");
9635       emitcode ("movc", "a,@a+dptr");
9636       break;
9637
9638     case GPOINTER:
9639       if (preserveAinB)
9640         {
9641           emitcode ("push", "b");
9642           emitcode ("push", "acc");
9643         }
9644       emitcode ("lcall", "__gptrget");
9645       if (preserveAinB)
9646         emitcode ("pop", "b");
9647       break;
9648     }
9649 }
9650
9651 /*-----------------------------------------------------------------*/
9652 /* emitPtrByteSet - emits code to set a byte from src through a    */
9653 /*                  pointer register (R0, R1, or DPTR).            */
9654 /*-----------------------------------------------------------------*/
9655 static void
9656 emitPtrByteSet (char *rname, int p_type, char *src)
9657 {
9658   switch (p_type)
9659     {
9660     case IPOINTER:
9661     case POINTER:
9662       if (*src=='@')
9663         {
9664           MOVA (src);
9665           emitcode ("mov", "@%s,a", rname);
9666         }
9667       else
9668         emitcode ("mov", "@%s,%s", rname, src);
9669       break;
9670
9671     case PPOINTER:
9672       MOVA (src);
9673       emitcode ("movx", "@%s,a", rname);
9674       break;
9675
9676     case FPOINTER:
9677       MOVA (src);
9678       emitcode ("movx", "@dptr,a");
9679       break;
9680
9681     case GPOINTER:
9682       MOVA (src);
9683       emitcode ("lcall", "__gptrput");
9684       break;
9685     }
9686 }
9687
9688 /*-----------------------------------------------------------------*/
9689 /* genUnpackBits - generates code for unpacking bits               */
9690 /*-----------------------------------------------------------------*/
9691 static void
9692 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9693 {
9694   int offset = 0;       /* result byte offset */
9695   int rsize;            /* result size */
9696   int rlen = 0;         /* remaining bitfield length */
9697   sym_link *etype;      /* bitfield type information */
9698   int blen;             /* bitfield length */
9699   int bstr;             /* bitfield starting bit within byte */
9700   char buffer[10];
9701
9702   D(emitcode (";", "genUnpackBits"));
9703
9704   etype = getSpec (operandType (result));
9705   rsize = getSize (operandType (result));
9706   blen = SPEC_BLEN (etype);
9707   bstr = SPEC_BSTR (etype);
9708
9709   if (ifx && blen <= 8)
9710     {
9711       emitPtrByteGet (rname, ptype, FALSE);
9712       if (blen == 1)
9713         {
9714           SNPRINTF (buffer, sizeof(buffer),
9715                     "acc.%d", bstr);
9716           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9717         }
9718       else
9719         {
9720           if (blen < 8)
9721             emitcode ("anl", "a,#0x%02x",
9722                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9723           genIfxJump (ifx, "a", NULL, NULL, NULL);
9724         }
9725       return;
9726     }
9727   wassert (!ifx);
9728
9729   /* If the bitfield length is less than a byte */
9730   if (blen < 8)
9731     {
9732       emitPtrByteGet (rname, ptype, FALSE);
9733       AccRol (8 - bstr);
9734       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9735       if (!SPEC_USIGN (etype))
9736         {
9737           /* signed bitfield */
9738           symbol *tlbl = newiTempLabel (NULL);
9739
9740           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9741           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9742           emitLabel (tlbl);
9743         }
9744       aopPut (result, "a", offset++);
9745       goto finish;
9746     }
9747
9748   /* Bit field did not fit in a byte. Copy all
9749      but the partial byte at the end.  */
9750   for (rlen=blen;rlen>=8;rlen-=8)
9751     {
9752       emitPtrByteGet (rname, ptype, FALSE);
9753       aopPut (result, "a", offset++);
9754       if (rlen>8)
9755         emitcode ("inc", "%s", rname);
9756     }
9757
9758   /* Handle the partial byte at the end */
9759   if (rlen)
9760     {
9761       emitPtrByteGet (rname, ptype, FALSE);
9762       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9763       if (!SPEC_USIGN (etype))
9764         {
9765           /* signed bitfield */
9766           symbol *tlbl = newiTempLabel (NULL);
9767
9768           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9769           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9770           emitLabel (tlbl);
9771         }
9772       aopPut (result, "a", offset++);
9773     }
9774
9775 finish:
9776   if (offset < rsize)
9777     {
9778       char *source;
9779
9780       if (SPEC_USIGN (etype))
9781         source = zero;
9782       else
9783         {
9784           /* signed bitfield: sign extension with 0x00 or 0xff */
9785           emitcode ("rlc", "a");
9786           emitcode ("subb", "a,acc");
9787
9788           source = "a";
9789         }
9790       rsize -= offset;
9791       while (rsize--)
9792         aopPut (result, source, offset++);
9793     }
9794 }
9795
9796
9797 /*-----------------------------------------------------------------*/
9798 /* genDataPointerGet - generates code when ptr offset is known     */
9799 /*-----------------------------------------------------------------*/
9800 static void
9801 genDataPointerGet (operand * left,
9802                    operand * result,
9803                    iCode * ic)
9804 {
9805   char *l;
9806   char buffer[256];
9807   int size, offset = 0;
9808
9809   D (emitcode (";", "genDataPointerGet"));
9810
9811   aopOp (result, ic, TRUE);
9812
9813   /* get the string representation of the name */
9814   l = aopGet (left, 0, FALSE, TRUE);
9815   l++; // remove #
9816   size = AOP_SIZE (result);
9817   while (size--)
9818     {
9819       if (offset)
9820         {
9821           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9822         }
9823       else
9824         {
9825           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9826         }
9827       aopPut (result, buffer, offset++);
9828     }
9829
9830   freeAsmop (result, NULL, ic, TRUE);
9831   freeAsmop (left, NULL, ic, TRUE);
9832 }
9833
9834 /*-----------------------------------------------------------------*/
9835 /* genNearPointerGet - emitcode for near pointer fetch             */
9836 /*-----------------------------------------------------------------*/
9837 static void
9838 genNearPointerGet (operand * left,
9839                    operand * result,
9840                    iCode * ic,
9841                    iCode * pi,
9842                    iCode * ifx)
9843 {
9844   asmop *aop = NULL;
9845   regs *preg = NULL;
9846   char *rname;
9847   sym_link *rtype, *retype;
9848   sym_link *ltype = operandType (left);
9849   char buffer[80];
9850
9851   D (emitcode (";", "genNearPointerGet"));
9852
9853   rtype = operandType (result);
9854   retype = getSpec (rtype);
9855
9856   aopOp (left, ic, FALSE);
9857
9858   /* if left is rematerialisable and
9859      result is not bitfield variable type and
9860      the left is pointer to data space i.e
9861      lower 128 bytes of space */
9862   if (AOP_TYPE (left) == AOP_IMMD &&
9863       !IS_BITFIELD (retype) &&
9864       DCL_TYPE (ltype) == POINTER)
9865     {
9866       genDataPointerGet (left, result, ic);
9867       return;
9868     }
9869
9870  /* if the value is already in a pointer register
9871      then don't need anything more */
9872   if (!AOP_INPREG (AOP (left)))
9873     {
9874       if (IS_AOP_PREG (left))
9875         {
9876           // Aha, it is a pointer, just in disguise.
9877           rname = aopGet (left, 0, FALSE, FALSE);
9878           if (*rname != '@')
9879             {
9880               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9881                       __FILE__, __LINE__);
9882             }
9883           else
9884             {
9885               // Expected case.
9886               emitcode ("mov", "a%s,%s", rname + 1, rname);
9887               rname++;  // skip the '@'.
9888             }
9889         }
9890       else
9891         {
9892           /* otherwise get a free pointer register */
9893           aop = newAsmop (0);
9894           preg = getFreePtr (ic, &aop, FALSE);
9895           emitcode ("mov", "%s,%s",
9896                     preg->name,
9897                     aopGet (left, 0, FALSE, TRUE));
9898           rname = preg->name;
9899         }
9900     }
9901   else
9902     rname = aopGet (left, 0, FALSE, FALSE);
9903
9904   //aopOp (result, ic, FALSE);
9905   aopOp (result, ic, result?TRUE:FALSE);
9906
9907   /* if bitfield then unpack the bits */
9908   if (IS_BITFIELD (retype))
9909     genUnpackBits (result, rname, POINTER, ifx);
9910   else
9911     {
9912       /* we have can just get the values */
9913       int size = AOP_SIZE (result);
9914       int offset = 0;
9915
9916       while (size--)
9917         {
9918           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9919             {
9920
9921               emitcode ("mov", "a,@%s", rname);
9922               if (!ifx)
9923                 aopPut (result, "a", offset);
9924             }
9925           else
9926             {
9927               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9928               aopPut (result, buffer, offset);
9929             }
9930           offset++;
9931           if (size || pi)
9932             emitcode ("inc", "%s", rname);
9933         }
9934     }
9935
9936   /* now some housekeeping stuff */
9937   if (aop)       /* we had to allocate for this iCode */
9938     {
9939       if (pi) { /* post increment present */
9940         aopPut (left, rname, 0);
9941       }
9942       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9943     }
9944   else
9945     {
9946       /* we did not allocate which means left
9947          already in a pointer register, then
9948          if size > 0 && this could be used again
9949          we have to point it back to where it
9950          belongs */
9951       if ((AOP_SIZE (result) > 1 &&
9952            !OP_SYMBOL (left)->remat &&
9953            (OP_SYMBOL (left)->liveTo > ic->seq ||
9954             ic->depth)) &&
9955           !pi)
9956         {
9957           int size = AOP_SIZE (result) - 1;
9958           while (size--)
9959             emitcode ("dec", "%s", rname);
9960         }
9961     }
9962
9963   if (ifx && !ifx->generated)
9964     {
9965       genIfxJump (ifx, "a", left, NULL, result);
9966     }
9967
9968   /* done */
9969   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9970   freeAsmop (left, NULL, ic, TRUE);
9971   if (pi) pi->generated = 1;
9972 }
9973
9974 /*-----------------------------------------------------------------*/
9975 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9976 /*-----------------------------------------------------------------*/
9977 static void
9978 genPagedPointerGet (operand * left,
9979                     operand * result,
9980                     iCode * ic,
9981                     iCode *pi,
9982                     iCode *ifx)
9983 {
9984   asmop *aop = NULL;
9985   regs *preg = NULL;
9986   char *rname;
9987   sym_link *rtype, *retype;
9988
9989   D (emitcode (";", "genPagedPointerGet"));
9990
9991   rtype = operandType (result);
9992   retype = getSpec (rtype);
9993
9994   aopOp (left, ic, FALSE);
9995
9996   /* if the value is already in a pointer register
9997      then don't need anything more */
9998   if (!AOP_INPREG (AOP (left)))
9999     {
10000       /* otherwise get a free pointer register */
10001       aop = newAsmop (0);
10002       preg = getFreePtr (ic, &aop, FALSE);
10003       emitcode ("mov", "%s,%s",
10004                 preg->name,
10005                 aopGet (left, 0, FALSE, TRUE));
10006       rname = preg->name;
10007     }
10008   else
10009     rname = aopGet (left, 0, FALSE, FALSE);
10010
10011   aopOp (result, ic, FALSE);
10012
10013   /* if bitfield then unpack the bits */
10014   if (IS_BITFIELD (retype))
10015     genUnpackBits (result, rname, PPOINTER, ifx);
10016   else
10017     {
10018       /* we have can just get the values */
10019       int size = AOP_SIZE (result);
10020       int offset = 0;
10021
10022       while (size--)
10023         {
10024
10025           emitcode ("movx", "a,@%s", rname);
10026           if (!ifx)
10027             aopPut (result, "a", offset);
10028
10029           offset++;
10030
10031           if (size || pi)
10032             emitcode ("inc", "%s", rname);
10033         }
10034     }
10035
10036   /* now some housekeeping stuff */
10037   if (aop) /* we had to allocate for this iCode */
10038     {
10039       if (pi)
10040         aopPut (left, rname, 0);
10041       freeAsmop (NULL, aop, ic, TRUE);
10042     }
10043   else
10044     {
10045       /* we did not allocate which means left
10046          already in a pointer register, then
10047          if size > 0 && this could be used again
10048          we have to point it back to where it
10049          belongs */
10050       if ((AOP_SIZE (result) > 1 &&
10051            !OP_SYMBOL (left)->remat &&
10052            (OP_SYMBOL (left)->liveTo > ic->seq ||
10053             ic->depth)) &&
10054           !pi)
10055         {
10056           int size = AOP_SIZE (result) - 1;
10057           while (size--)
10058             emitcode ("dec", "%s", rname);
10059         }
10060     }
10061
10062   if (ifx && !ifx->generated)
10063     {
10064       genIfxJump (ifx, "a", left, NULL, result);
10065     }
10066
10067   /* done */
10068   freeAsmop (result, NULL, ic, TRUE);
10069   freeAsmop (left, NULL, ic, TRUE);
10070   if (pi) pi->generated = 1;
10071 }
10072
10073 /*--------------------------------------------------------------------*/
10074 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10075 /*--------------------------------------------------------------------*/
10076 static void
10077 loadDptrFromOperand (operand *op, bool loadBToo)
10078 {
10079   if (AOP_TYPE (op) != AOP_STR)
10080     {
10081       /* if this is rematerializable */
10082       if (AOP_TYPE (op) == AOP_IMMD)
10083         {
10084           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10085           if (loadBToo)
10086             {
10087               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10088                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10089               else
10090                 {
10091                   wassertl(FALSE, "need pointerCode");
10092                   emitcode (";", "mov b,???");
10093                   /* genPointerGet and genPointerSet originally did different
10094                   ** things for this case. Both seem wrong.
10095                   ** from genPointerGet:
10096                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10097                   ** from genPointerSet:
10098                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10099                   */
10100                 }
10101             }
10102         }
10103       else if (AOP_TYPE (op) == AOP_DPTR)
10104         {
10105           if (loadBToo)
10106             {
10107               MOVA (aopGet (op, 0, FALSE, FALSE));
10108               emitcode ("push", "acc");
10109               MOVA (aopGet (op, 1, FALSE, FALSE));
10110               emitcode ("push", "acc");
10111               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10112               emitcode ("pop", "dph");
10113               emitcode ("pop", "dpl");
10114             }
10115           else
10116             {
10117               MOVA (aopGet (op, 0, FALSE, FALSE));
10118               emitcode ("push", "acc");
10119               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10120               emitcode ("pop", "dpl");
10121             }
10122         }
10123       else
10124         {                       /* we need to get it byte by byte */
10125           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10126           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10127           if (loadBToo)
10128             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10129         }
10130     }
10131 }
10132
10133 /*-----------------------------------------------------------------*/
10134 /* genFarPointerGet - get value from far space                     */
10135 /*-----------------------------------------------------------------*/
10136 static void
10137 genFarPointerGet (operand * left,
10138                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10139 {
10140   int size, offset;
10141   sym_link *retype = getSpec (operandType (result));
10142
10143   D (emitcode (";", "genFarPointerGet"));
10144
10145   aopOp (left, ic, FALSE);
10146   loadDptrFromOperand (left, FALSE);
10147
10148   /* so dptr now contains the address */
10149   aopOp (result, ic, FALSE);
10150
10151   /* if bit then unpack */
10152   if (IS_BITFIELD (retype))
10153     genUnpackBits (result, "dptr", FPOINTER, ifx);
10154   else
10155     {
10156       size = AOP_SIZE (result);
10157       offset = 0;
10158
10159       while (size--)
10160         {
10161           emitcode ("movx", "a,@dptr");
10162           if (!ifx)
10163             aopPut (result, "a", offset++);
10164           if (size || pi)
10165             emitcode ("inc", "dptr");
10166         }
10167     }
10168
10169   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10170     {
10171       aopPut (left, "dpl", 0);
10172       aopPut (left, "dph", 1);
10173       pi->generated = 1;
10174     }
10175
10176   if (ifx && !ifx->generated)
10177     {
10178       genIfxJump (ifx, "a", left, NULL, result);
10179     }
10180
10181   freeAsmop (result, NULL, ic, TRUE);
10182   freeAsmop (left, NULL, ic, TRUE);
10183 }
10184
10185 /*-----------------------------------------------------------------*/
10186 /* genCodePointerGet - get value from code space                   */
10187 /*-----------------------------------------------------------------*/
10188 static void
10189 genCodePointerGet (operand * left,
10190                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10191 {
10192   int size, offset;
10193   sym_link *retype = getSpec (operandType (result));
10194
10195   D (emitcode (";", "genCodePointerGet"));
10196
10197   aopOp (left, ic, FALSE);
10198   loadDptrFromOperand (left, FALSE);
10199
10200   /* so dptr now contains the address */
10201   aopOp (result, ic, FALSE);
10202
10203   /* if bit then unpack */
10204   if (IS_BITFIELD (retype))
10205     genUnpackBits (result, "dptr", CPOINTER, ifx);
10206   else
10207     {
10208       size = AOP_SIZE (result);
10209       offset = 0;
10210
10211       while (size--)
10212         {
10213           emitcode ("clr", "a");
10214           emitcode ("movc", "a,@a+dptr");
10215           if (!ifx)
10216             aopPut (result, "a", offset++);
10217           if (size || pi)
10218             emitcode ("inc", "dptr");
10219         }
10220     }
10221
10222   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10223     {
10224       aopPut (left, "dpl", 0);
10225       aopPut (left, "dph", 1);
10226       pi->generated = 1;
10227     }
10228
10229   if (ifx && !ifx->generated)
10230     {
10231       genIfxJump (ifx, "a", left, NULL, result);
10232     }
10233
10234   freeAsmop (result, NULL, ic, TRUE);
10235   freeAsmop (left, NULL, ic, TRUE);
10236 }
10237
10238 /*-----------------------------------------------------------------*/
10239 /* genGenPointerGet - get value from generic pointer space         */
10240 /*-----------------------------------------------------------------*/
10241 static void
10242 genGenPointerGet (operand * left,
10243                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10244 {
10245   int size, offset;
10246   sym_link *retype = getSpec (operandType (result));
10247
10248   D (emitcode (";", "genGenPointerGet"));
10249
10250   aopOp (left, ic, FALSE);
10251   loadDptrFromOperand (left, TRUE);
10252
10253   /* so dptr now contains the address */
10254   aopOp (result, ic, FALSE);
10255
10256   /* if bit then unpack */
10257   if (IS_BITFIELD (retype))
10258     {
10259       genUnpackBits (result, "dptr", GPOINTER, ifx);
10260     }
10261   else
10262     {
10263       size = AOP_SIZE (result);
10264       offset = 0;
10265
10266       while (size--)
10267         {
10268           emitcode ("lcall", "__gptrget");
10269           if (!ifx)
10270             aopPut (result, "a", offset++);
10271           if (size || pi)
10272             emitcode ("inc", "dptr");
10273         }
10274     }
10275
10276   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10277     {
10278       aopPut (left, "dpl", 0);
10279       aopPut (left, "dph", 1);
10280       pi->generated = 1;
10281     }
10282
10283   if (ifx && !ifx->generated)
10284     {
10285       genIfxJump (ifx, "a", left, NULL, result);
10286     }
10287
10288   freeAsmop (result, NULL, ic, TRUE);
10289   freeAsmop (left, NULL, ic, TRUE);
10290 }
10291
10292 /*-----------------------------------------------------------------*/
10293 /* genPointerGet - generate code for pointer get                   */
10294 /*-----------------------------------------------------------------*/
10295 static void
10296 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10297 {
10298   operand *left, *result;
10299   sym_link *type, *etype;
10300   int p_type;
10301
10302   D (emitcode (";", "genPointerGet"));
10303
10304   left = IC_LEFT (ic);
10305   result = IC_RESULT (ic);
10306
10307   if (getSize (operandType (result))>1)
10308     ifx = NULL;
10309
10310   /* depending on the type of pointer we need to
10311      move it to the correct pointer register */
10312   type = operandType (left);
10313   etype = getSpec (type);
10314   /* if left is of type of pointer then it is simple */
10315   if (IS_PTR (type) && !IS_FUNC (type->next))
10316     p_type = DCL_TYPE (type);
10317   else
10318     {
10319       /* we have to go by the storage class */
10320       p_type = PTR_TYPE (SPEC_OCLS (etype));
10321     }
10322
10323   /* special case when cast remat */
10324   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10325       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10326     {
10327       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10328       type = operandType (left);
10329       p_type = DCL_TYPE (type);
10330     }
10331   /* now that we have the pointer type we assign
10332      the pointer values */
10333   switch (p_type)
10334     {
10335
10336     case POINTER:
10337     case IPOINTER:
10338       genNearPointerGet (left, result, ic, pi, ifx);
10339       break;
10340
10341     case PPOINTER:
10342       genPagedPointerGet (left, result, ic, pi, ifx);
10343       break;
10344
10345     case FPOINTER:
10346       genFarPointerGet (left, result, ic, pi, ifx);
10347       break;
10348
10349     case CPOINTER:
10350       genCodePointerGet (left, result, ic, pi, ifx);
10351       break;
10352
10353     case GPOINTER:
10354       genGenPointerGet (left, result, ic, pi, ifx);
10355       break;
10356     }
10357 }
10358
10359
10360 /*-----------------------------------------------------------------*/
10361 /* genPackBits - generates code for packed bit storage             */
10362 /*-----------------------------------------------------------------*/
10363 static void
10364 genPackBits (sym_link * etype,
10365              operand * right,
10366              char *rname, int p_type)
10367 {
10368   int offset = 0;       /* source byte offset */
10369   int rlen = 0;         /* remaining bitfield length */
10370   int blen;             /* bitfield length */
10371   int bstr;             /* bitfield starting bit within byte */
10372   int litval;           /* source literal value (if AOP_LIT) */
10373   unsigned char mask;   /* bitmask within current byte */
10374
10375   D(emitcode (";", "genPackBits"));
10376
10377   blen = SPEC_BLEN (etype);
10378   bstr = SPEC_BSTR (etype);
10379
10380   /* If the bitfield length is less than a byte */
10381   if (blen < 8)
10382     {
10383       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10384               (unsigned char) (0xFF >> (8 - bstr)));
10385
10386       if (AOP_TYPE (right) == AOP_LIT)
10387         {
10388           /* Case with a bitfield length <8 and literal source
10389           */
10390           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10391           litval <<= bstr;
10392           litval &= (~mask) & 0xff;
10393           emitPtrByteGet (rname, p_type, FALSE);
10394           if ((mask|litval)!=0xff)
10395             emitcode ("anl","a,#0x%02x", mask);
10396           if (litval)
10397             emitcode ("orl","a,#0x%02x", litval);
10398         }
10399       else
10400         {
10401           if ((blen==1) && (p_type!=GPOINTER))
10402             {
10403               /* Case with a bitfield length == 1 and no generic pointer
10404               */
10405               if (AOP_TYPE (right) == AOP_CRY)
10406                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10407               else
10408                 {
10409                   MOVA (aopGet (right, 0, FALSE, FALSE));
10410                   emitcode ("rrc","a");
10411                 }
10412               emitPtrByteGet (rname, p_type, FALSE);
10413               emitcode ("mov","acc.%d,c",bstr);
10414             }
10415           else
10416             {
10417               bool pushedB;
10418               /* Case with a bitfield length < 8 and arbitrary source
10419               */
10420               MOVA (aopGet (right, 0, FALSE, FALSE));
10421               /* shift and mask source value */
10422               AccLsh (bstr);
10423               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10424
10425               pushedB = pushB ();
10426               /* transfer A to B and get next byte */
10427               emitPtrByteGet (rname, p_type, TRUE);
10428
10429               emitcode ("anl", "a,#0x%02x", mask);
10430               emitcode ("orl", "a,b");
10431               if (p_type == GPOINTER)
10432                 emitcode ("pop", "b");
10433
10434               popB (pushedB);
10435            }
10436         }
10437
10438       emitPtrByteSet (rname, p_type, "a");
10439       return;
10440     }
10441
10442   /* Bit length is greater than 7 bits. In this case, copy  */
10443   /* all except the partial byte at the end                 */
10444   for (rlen=blen;rlen>=8;rlen-=8)
10445     {
10446       emitPtrByteSet (rname, p_type,
10447                       aopGet (right, offset++, FALSE, TRUE) );
10448       if (rlen>8)
10449         emitcode ("inc", "%s", rname);
10450     }
10451
10452   /* If there was a partial byte at the end */
10453   if (rlen)
10454     {
10455       mask = (((unsigned char) -1 << rlen) & 0xff);
10456
10457       if (AOP_TYPE (right) == AOP_LIT)
10458         {
10459           /* Case with partial byte and literal source
10460           */
10461           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10462           litval >>= (blen-rlen);
10463           litval &= (~mask) & 0xff;
10464           emitPtrByteGet (rname, p_type, FALSE);
10465           if ((mask|litval)!=0xff)
10466             emitcode ("anl","a,#0x%02x", mask);
10467           if (litval)
10468             emitcode ("orl","a,#0x%02x", litval);
10469         }
10470       else
10471         {
10472           bool pushedB;
10473           /* Case with partial byte and arbitrary source
10474           */
10475           MOVA (aopGet (right, offset++, FALSE, FALSE));
10476           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10477
10478           pushedB = pushB ();
10479           /* transfer A to B and get next byte */
10480           emitPtrByteGet (rname, p_type, TRUE);
10481
10482           emitcode ("anl", "a,#0x%02x", mask);
10483           emitcode ("orl", "a,b");
10484           if (p_type == GPOINTER)
10485             emitcode ("pop", "b");
10486
10487           popB (pushedB);
10488         }
10489       emitPtrByteSet (rname, p_type, "a");
10490     }
10491 }
10492
10493
10494 /*-----------------------------------------------------------------*/
10495 /* genDataPointerSet - remat pointer to data space                 */
10496 /*-----------------------------------------------------------------*/
10497 static void
10498 genDataPointerSet (operand * right,
10499                    operand * result,
10500                    iCode * ic)
10501 {
10502   int size, offset = 0;
10503   char *l, buffer[256];
10504
10505   D (emitcode (";", "genDataPointerSet"));
10506
10507   aopOp (right, ic, FALSE);
10508
10509   l = aopGet (result, 0, FALSE, TRUE);
10510   l++; //remove #
10511   size = AOP_SIZE (right);
10512   while (size--)
10513     {
10514       if (offset)
10515         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10516       else
10517         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10518       emitcode ("mov", "%s,%s", buffer,
10519                 aopGet (right, offset++, FALSE, FALSE));
10520     }
10521
10522   freeAsmop (result, NULL, ic, TRUE);
10523   freeAsmop (right, NULL, ic, TRUE);
10524 }
10525
10526 /*-----------------------------------------------------------------*/
10527 /* genNearPointerSet - emitcode for near pointer put                */
10528 /*-----------------------------------------------------------------*/
10529 static void
10530 genNearPointerSet (operand * right,
10531                    operand * result,
10532                    iCode * ic,
10533                    iCode * pi)
10534 {
10535   asmop *aop = NULL;
10536   regs *preg = NULL;
10537   char *rname, *l;
10538   sym_link *retype, *letype;
10539   sym_link *ptype = operandType (result);
10540
10541   D (emitcode (";", "genNearPointerSet"));
10542
10543   retype = getSpec (operandType (right));
10544   letype = getSpec (ptype);
10545
10546   aopOp (result, ic, FALSE);
10547
10548   /* if the result is rematerializable &
10549      in data space & not a bit variable */
10550   if (AOP_TYPE (result) == AOP_IMMD &&
10551       DCL_TYPE (ptype) == POINTER &&
10552       !IS_BITVAR (retype) &&
10553       !IS_BITVAR (letype))
10554     {
10555       genDataPointerSet (right, result, ic);
10556       return;
10557     }
10558
10559   /* if the value is already in a pointer register
10560      then don't need anything more */
10561   if (!AOP_INPREG (AOP (result)))
10562     {
10563         if (
10564             //AOP_TYPE (result) == AOP_STK
10565             IS_AOP_PREG(result)
10566             )
10567         {
10568             // Aha, it is a pointer, just in disguise.
10569             rname = aopGet (result, 0, FALSE, FALSE);
10570             if (*rname != '@')
10571             {
10572                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10573                         __FILE__, __LINE__);
10574             }
10575             else
10576             {
10577                 // Expected case.
10578                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10579                 rname++;  // skip the '@'.
10580             }
10581         }
10582         else
10583         {
10584             /* otherwise get a free pointer register */
10585             aop = newAsmop (0);
10586             preg = getFreePtr (ic, &aop, FALSE);
10587             emitcode ("mov", "%s,%s",
10588                       preg->name,
10589                       aopGet (result, 0, FALSE, TRUE));
10590             rname = preg->name;
10591         }
10592     }
10593     else
10594     {
10595         rname = aopGet (result, 0, FALSE, FALSE);
10596     }
10597
10598   aopOp (right, ic, FALSE);
10599
10600   /* if bitfield then unpack the bits */
10601   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10602     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10603   else
10604     {
10605       /* we can just get the values */
10606       int size = AOP_SIZE (right);
10607       int offset = 0;
10608
10609       while (size--)
10610         {
10611           l = aopGet (right, offset, FALSE, TRUE);
10612           if ((*l == '@') || (strcmp (l, "acc") == 0))
10613             {
10614               MOVA (l);
10615               emitcode ("mov", "@%s,a", rname);
10616             }
10617           else
10618             emitcode ("mov", "@%s,%s", rname, l);
10619           if (size || pi)
10620             emitcode ("inc", "%s", rname);
10621           offset++;
10622         }
10623     }
10624
10625   /* now some housekeeping stuff */
10626   if (aop) /* we had to allocate for this iCode */
10627     {
10628       if (pi)
10629         aopPut (result, rname, 0);
10630       freeAsmop (NULL, aop, ic, TRUE);
10631     }
10632   else
10633     {
10634       /* we did not allocate which means left
10635          already in a pointer register, then
10636          if size > 0 && this could be used again
10637          we have to point it back to where it
10638          belongs */
10639       if ((AOP_SIZE (right) > 1 &&
10640            !OP_SYMBOL (result)->remat &&
10641            (OP_SYMBOL (result)->liveTo > ic->seq ||
10642             ic->depth)) &&
10643           !pi)
10644         {
10645           int size = AOP_SIZE (right) - 1;
10646           while (size--)
10647             emitcode ("dec", "%s", rname);
10648         }
10649     }
10650
10651   /* done */
10652   if (pi) pi->generated = 1;
10653   freeAsmop (result, NULL, ic, TRUE);
10654   freeAsmop (right, NULL, ic, TRUE);
10655 }
10656
10657 /*-----------------------------------------------------------------*/
10658 /* genPagedPointerSet - emitcode for Paged pointer put             */
10659 /*-----------------------------------------------------------------*/
10660 static void
10661 genPagedPointerSet (operand * right,
10662                     operand * result,
10663                     iCode * ic,
10664                     iCode * pi)
10665 {
10666   asmop *aop = NULL;
10667   regs *preg = NULL;
10668   char *rname, *l;
10669   sym_link *retype, *letype;
10670
10671   D (emitcode (";", "genPagedPointerSet"));
10672
10673   retype = getSpec (operandType (right));
10674   letype = getSpec (operandType (result));
10675
10676   aopOp (result, ic, FALSE);
10677
10678   /* if the value is already in a pointer register
10679      then don't need anything more */
10680   if (!AOP_INPREG (AOP (result)))
10681     {
10682       /* otherwise get a free pointer register */
10683       aop = newAsmop (0);
10684       preg = getFreePtr (ic, &aop, FALSE);
10685       emitcode ("mov", "%s,%s",
10686                 preg->name,
10687                 aopGet (result, 0, FALSE, TRUE));
10688       rname = preg->name;
10689     }
10690   else
10691     rname = aopGet (result, 0, FALSE, FALSE);
10692
10693   aopOp (right, ic, FALSE);
10694
10695   /* if bitfield then unpack the bits */
10696   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10697     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10698   else
10699     {
10700       /* we have can just get the values */
10701       int size = AOP_SIZE (right);
10702       int offset = 0;
10703
10704       while (size--)
10705         {
10706           l = aopGet (right, offset, FALSE, TRUE);
10707           MOVA (l);
10708           emitcode ("movx", "@%s,a", rname);
10709
10710           if (size || pi)
10711             emitcode ("inc", "%s", rname);
10712
10713           offset++;
10714         }
10715     }
10716
10717   /* now some housekeeping stuff */
10718   if (aop) /* we had to allocate for this iCode */
10719     {
10720       if (pi)
10721         aopPut (result, rname, 0);
10722       freeAsmop (NULL, aop, ic, TRUE);
10723     }
10724   else
10725     {
10726       /* we did not allocate which means left
10727          already in a pointer register, then
10728          if size > 0 && this could be used again
10729          we have to point it back to where it
10730          belongs */
10731       if (AOP_SIZE (right) > 1 &&
10732           !OP_SYMBOL (result)->remat &&
10733           (OP_SYMBOL (result)->liveTo > ic->seq ||
10734            ic->depth))
10735         {
10736           int size = AOP_SIZE (right) - 1;
10737           while (size--)
10738             emitcode ("dec", "%s", rname);
10739         }
10740     }
10741
10742   /* done */
10743   if (pi) pi->generated = 1;
10744   freeAsmop (result, NULL, ic, TRUE);
10745   freeAsmop (right, NULL, ic, TRUE);
10746 }
10747
10748 /*-----------------------------------------------------------------*/
10749 /* genFarPointerSet - set value from far space                     */
10750 /*-----------------------------------------------------------------*/
10751 static void
10752 genFarPointerSet (operand * right,
10753                   operand * result, iCode * ic, iCode * pi)
10754 {
10755   int size, offset;
10756   sym_link *retype = getSpec (operandType (right));
10757   sym_link *letype = getSpec (operandType (result));
10758
10759   D(emitcode (";", "genFarPointerSet"));
10760
10761   aopOp (result, ic, FALSE);
10762   loadDptrFromOperand (result, FALSE);
10763
10764   /* so dptr now contains the address */
10765   aopOp (right, ic, FALSE);
10766
10767   /* if bit then unpack */
10768   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10769     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10770   else
10771     {
10772       size = AOP_SIZE (right);
10773       offset = 0;
10774
10775       while (size--)
10776         {
10777           char *l = aopGet (right, offset++, FALSE, FALSE);
10778           MOVA (l);
10779           emitcode ("movx", "@dptr,a");
10780           if (size || pi)
10781             emitcode ("inc", "dptr");
10782         }
10783     }
10784   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10785     aopPut (result, "dpl", 0);
10786     aopPut (result, "dph", 1);
10787     pi->generated=1;
10788   }
10789   freeAsmop (result, NULL, ic, TRUE);
10790   freeAsmop (right, NULL, ic, TRUE);
10791 }
10792
10793 /*-----------------------------------------------------------------*/
10794 /* genGenPointerSet - set value from generic pointer space         */
10795 /*-----------------------------------------------------------------*/
10796 static void
10797 genGenPointerSet (operand * right,
10798                   operand * result, iCode * ic, iCode * pi)
10799 {
10800   int size, offset;
10801   sym_link *retype = getSpec (operandType (right));
10802   sym_link *letype = getSpec (operandType (result));
10803
10804   D (emitcode (";", "genGenPointerSet"));
10805
10806   aopOp (result, ic, FALSE);
10807   loadDptrFromOperand (result, TRUE);
10808
10809   /* so dptr now contains the address */
10810   aopOp (right, ic, FALSE);
10811
10812   /* if bit then unpack */
10813   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10814     {
10815       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10816     }
10817   else
10818     {
10819       size = AOP_SIZE (right);
10820       offset = 0;
10821
10822       while (size--)
10823         {
10824           char *l = aopGet (right, offset++, FALSE, FALSE);
10825           MOVA (l);
10826           emitcode ("lcall", "__gptrput");
10827           if (size || pi)
10828             emitcode ("inc", "dptr");
10829         }
10830     }
10831
10832   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10833     aopPut (result, "dpl", 0);
10834     aopPut (result, "dph", 1);
10835     pi->generated=1;
10836   }
10837   freeAsmop (result, NULL, ic, TRUE);
10838   freeAsmop (right, NULL, ic, TRUE);
10839 }
10840
10841 /*-----------------------------------------------------------------*/
10842 /* genPointerSet - stores the value into a pointer location        */
10843 /*-----------------------------------------------------------------*/
10844 static void
10845 genPointerSet (iCode * ic, iCode *pi)
10846 {
10847   operand *right, *result;
10848   sym_link *type, *etype;
10849   int p_type;
10850
10851   D (emitcode (";", "genPointerSet"));
10852
10853   right = IC_RIGHT (ic);
10854   result = IC_RESULT (ic);
10855
10856   /* depending on the type of pointer we need to
10857      move it to the correct pointer register */
10858   type = operandType (result);
10859   etype = getSpec (type);
10860   /* if left is of type of pointer then it is simple */
10861   if (IS_PTR (type) && !IS_FUNC (type->next))
10862     {
10863       p_type = DCL_TYPE (type);
10864     }
10865   else
10866     {
10867       /* we have to go by the storage class */
10868       p_type = PTR_TYPE (SPEC_OCLS (etype));
10869     }
10870
10871   /* special case when cast remat */
10872   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10873       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10874           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10875           type = operandType (result);
10876           p_type = DCL_TYPE (type);
10877   }
10878
10879   /* now that we have the pointer type we assign
10880      the pointer values */
10881   switch (p_type)
10882     {
10883
10884     case POINTER:
10885     case IPOINTER:
10886       genNearPointerSet (right, result, ic, pi);
10887       break;
10888
10889     case PPOINTER:
10890       genPagedPointerSet (right, result, ic, pi);
10891       break;
10892
10893     case FPOINTER:
10894       genFarPointerSet (right, result, ic, pi);
10895       break;
10896
10897     case GPOINTER:
10898       genGenPointerSet (right, result, ic, pi);
10899       break;
10900
10901     default:
10902       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10903               "genPointerSet: illegal pointer type");
10904     }
10905 }
10906
10907 /*-----------------------------------------------------------------*/
10908 /* genIfx - generate code for Ifx statement                        */
10909 /*-----------------------------------------------------------------*/
10910 static void
10911 genIfx (iCode * ic, iCode * popIc)
10912 {
10913   operand *cond = IC_COND (ic);
10914   int isbit = 0;
10915   char *dup = NULL;
10916
10917   D (emitcode (";", "genIfx"));
10918
10919   aopOp (cond, ic, FALSE);
10920
10921   /* get the value into acc */
10922   if (AOP_TYPE (cond) != AOP_CRY)
10923     {
10924       toBoolean (cond);
10925     }
10926   else
10927     {
10928       isbit = 1;
10929       if (AOP(cond)->aopu.aop_dir)
10930         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10931     }
10932
10933   /* the result is now in the accumulator or a directly addressable bit */
10934   freeAsmop (cond, NULL, ic, TRUE);
10935
10936   /* if there was something to be popped then do it */
10937   if (popIc)
10938     genIpop (popIc);
10939
10940   /* if the condition is a bit variable */
10941   if (isbit && dup)
10942     genIfxJump(ic, dup, NULL, NULL, NULL);
10943   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10944     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10945   else if (isbit && !IS_ITEMP (cond))
10946     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10947   else
10948     genIfxJump (ic, "a", NULL, NULL, NULL);
10949
10950   ic->generated = 1;
10951 }
10952
10953 /*-----------------------------------------------------------------*/
10954 /* genAddrOf - generates code for address of                       */
10955 /*-----------------------------------------------------------------*/
10956 static void
10957 genAddrOf (iCode * ic)
10958 {
10959   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
10960   int size, offset;
10961
10962   D (emitcode (";", "genAddrOf"));
10963
10964   aopOp (IC_RESULT (ic), ic, FALSE);
10965
10966   /* if the operand is on the stack then we
10967      need to get the stack offset of this
10968      variable */
10969   if (sym->onStack)
10970     {
10971       /* if it has an offset then we need to compute it */
10972       if (sym->stack)
10973         {
10974           int stack_offset = ((sym->stack < 0) ?
10975                               ((char) (sym->stack - _G.nRegsSaved)) :
10976                               ((char) sym->stack)) & 0xff;
10977           if ((abs(stack_offset) == 1) &&
10978               !AOP_NEEDSACC(IC_RESULT (ic)) &&
10979               !isOperandVolatile (IC_RESULT (ic), FALSE))
10980             {
10981               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10982               if (stack_offset > 0)
10983                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10984               else
10985                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
10986             }
10987           else
10988             {
10989               emitcode ("mov", "a,%s", SYM_BP (sym));
10990               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
10991               aopPut (IC_RESULT (ic), "a", 0);
10992             }
10993         }
10994       else
10995         {
10996           /* we can just move _bp */
10997           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
10998         }
10999       /* fill the result with zero */
11000       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11001
11002       offset = 1;
11003       while (size--)
11004         {
11005           aopPut (IC_RESULT (ic), zero, offset++);
11006         }
11007       goto release;
11008     }
11009
11010   /* object not on stack then we need the name */
11011   size = AOP_SIZE (IC_RESULT (ic));
11012   offset = 0;
11013
11014   while (size--)
11015     {
11016       char s[SDCC_NAME_MAX];
11017       if (offset)
11018         sprintf (s, "#(%s >> %d)",
11019                  sym->rname,
11020                  offset * 8);
11021       else
11022         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11023       aopPut (IC_RESULT (ic), s, offset++);
11024     }
11025
11026 release:
11027   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11028
11029 }
11030
11031 /*-----------------------------------------------------------------*/
11032 /* genFarFarAssign - assignment when both are in far space         */
11033 /*-----------------------------------------------------------------*/
11034 static void
11035 genFarFarAssign (operand * result, operand * right, iCode * ic)
11036 {
11037   int size = AOP_SIZE (right);
11038   int offset = 0;
11039   char *l;
11040
11041   D (emitcode (";", "genFarFarAssign"));
11042
11043   /* first push the right side on to the stack */
11044   while (size--)
11045     {
11046       l = aopGet (right, offset++, FALSE, FALSE);
11047       MOVA (l);
11048       emitcode ("push", "acc");
11049     }
11050
11051   freeAsmop (right, NULL, ic, FALSE);
11052   /* now assign DPTR to result */
11053   aopOp (result, ic, FALSE);
11054   size = AOP_SIZE (result);
11055   while (size--)
11056     {
11057       emitcode ("pop", "acc");
11058       aopPut (result, "a", --offset);
11059     }
11060   freeAsmop (result, NULL, ic, FALSE);
11061 }
11062
11063 /*-----------------------------------------------------------------*/
11064 /* genAssign - generate code for assignment                        */
11065 /*-----------------------------------------------------------------*/
11066 static void
11067 genAssign (iCode * ic)
11068 {
11069   operand *result, *right;
11070   int size, offset;
11071   unsigned long lit = 0L;
11072
11073   D (emitcode (";", "genAssign"));
11074
11075   result = IC_RESULT (ic);
11076   right = IC_RIGHT (ic);
11077
11078   /* if they are the same */
11079   if (operandsEqu (result, right) &&
11080       !isOperandVolatile (result, FALSE) &&
11081       !isOperandVolatile (right, FALSE))
11082     return;
11083
11084   aopOp (right, ic, FALSE);
11085
11086   /* special case both in far space */
11087   if (AOP_TYPE (right) == AOP_DPTR &&
11088       IS_TRUE_SYMOP (result) &&
11089       isOperandInFarSpace (result))
11090     {
11091       genFarFarAssign (result, right, ic);
11092       return;
11093     }
11094
11095   aopOp (result, ic, TRUE);
11096
11097   /* if they are the same registers */
11098   if (sameRegs (AOP (right), AOP (result)) &&
11099       !isOperandVolatile (result, FALSE) &&
11100       !isOperandVolatile (right, FALSE))
11101     goto release;
11102
11103   /* if the result is a bit */
11104   if (AOP_TYPE (result) == AOP_CRY)
11105     {
11106       assignBit (result, right);
11107       goto release;
11108     }
11109
11110   /* bit variables done */
11111   /* general case */
11112   size = AOP_SIZE (result);
11113   offset = 0;
11114   if (AOP_TYPE (right) == AOP_LIT)
11115     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11116
11117   if ((size > 1) &&
11118       (AOP_TYPE (result) != AOP_REG) &&
11119       (AOP_TYPE (right) == AOP_LIT) &&
11120       !IS_FLOAT (operandType (right)) &&
11121       (lit < 256L))
11122     {
11123       while ((size) && (lit))
11124         {
11125           aopPut (result,
11126                   aopGet (right, offset, FALSE, FALSE),
11127                   offset);
11128           lit >>= 8;
11129           offset++;
11130           size--;
11131         }
11132       /* And now fill the rest with zeros. */
11133       if (size)
11134         {
11135           emitcode ("clr", "a");
11136         }
11137       while (size--)
11138         {
11139           aopPut (result, "a", offset);
11140           offset++;
11141         }
11142     }
11143   else
11144     {
11145       while (size--)
11146         {
11147           aopPut (result,
11148                   aopGet (right, offset, FALSE, FALSE),
11149                   offset);
11150           offset++;
11151         }
11152     }
11153
11154 release:
11155   freeAsmop (result, NULL, ic, TRUE);
11156   freeAsmop (right, NULL, ic, TRUE);
11157 }
11158
11159 /*-----------------------------------------------------------------*/
11160 /* genJumpTab - generates code for jump table                      */
11161 /*-----------------------------------------------------------------*/
11162 static void
11163 genJumpTab (iCode * ic)
11164 {
11165   symbol *jtab,*jtablo,*jtabhi;
11166   char *l;
11167   unsigned int count;
11168
11169   D (emitcode (";", "genJumpTab"));
11170
11171   count = elementsInSet( IC_JTLABELS (ic) );
11172
11173   if( count <= 16 )
11174     {
11175       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11176          if the switch argument is in a register.
11177          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11178       /* Peephole may not convert ljmp to sjmp or ret
11179          labelIsReturnOnly & labelInRange must check
11180          currPl->ic->op != JUMPTABLE */
11181       aopOp (IC_JTCOND (ic), ic, FALSE);
11182       /* get the condition into accumulator */
11183       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11184       MOVA (l);
11185       /* multiply by three */
11186       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11187         {
11188           emitcode ("mov", "b,#3");
11189           emitcode ("mul", "ab");
11190         }
11191       else
11192         {
11193           emitcode ("add", "a,acc");
11194           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11195         }
11196       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11197
11198       jtab = newiTempLabel (NULL);
11199       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11200       emitcode ("jmp", "@a+dptr");
11201       emitLabel (jtab);
11202       /* now generate the jump labels */
11203       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11204            jtab = setNextItem (IC_JTLABELS (ic)))
11205         emitcode ("ljmp", "%05d$", jtab->key + 100);
11206     }
11207   else
11208     {
11209       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11210          if the switch argument is in a register.
11211          For n>6 this algorithm may be more compact */
11212       jtablo = newiTempLabel (NULL);
11213       jtabhi = newiTempLabel (NULL);
11214
11215       /* get the condition into accumulator.
11216          Using b as temporary storage, if register push/pop is needed */
11217       aopOp (IC_JTCOND (ic), ic, FALSE);
11218       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11219       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11220           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11221         {
11222           // (MB) what if B is in use???
11223           wassertl(!BINUSE, "B was in use");
11224           emitcode ("mov", "b,%s", l);
11225           l = "b";
11226         }
11227       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11228       MOVA (l);
11229       if( count <= 112 )
11230         {
11231           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11232           emitcode ("movc", "a,@a+pc");
11233           emitcode ("push", "acc");
11234
11235           MOVA (l);
11236           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11237           emitcode ("movc", "a,@a+pc");
11238           emitcode ("push", "acc");
11239         }
11240       else
11241         {
11242           /* this scales up to n<=255, but needs two more bytes
11243              and changes dptr */
11244           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11245           emitcode ("movc", "a,@a+dptr");
11246           emitcode ("push", "acc");
11247
11248           MOVA (l);
11249           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11250           emitcode ("movc", "a,@a+dptr");
11251           emitcode ("push", "acc");
11252         }
11253
11254       emitcode ("ret", "");
11255
11256       /* now generate jump table, LSB */
11257       emitLabel (jtablo);
11258       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11259            jtab = setNextItem (IC_JTLABELS (ic)))
11260         emitcode (".db", "%05d$", jtab->key + 100);
11261
11262       /* now generate jump table, MSB */
11263       emitLabel (jtabhi);
11264       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11265            jtab = setNextItem (IC_JTLABELS (ic)))
11266          emitcode (".db", "%05d$>>8", jtab->key + 100);
11267     }
11268 }
11269
11270 /*-----------------------------------------------------------------*/
11271 /* genCast - gen code for casting                                  */
11272 /*-----------------------------------------------------------------*/
11273 static void
11274 genCast (iCode * ic)
11275 {
11276   operand *result = IC_RESULT (ic);
11277   sym_link *ctype = operandType (IC_LEFT (ic));
11278   sym_link *rtype = operandType (IC_RIGHT (ic));
11279   operand *right = IC_RIGHT (ic);
11280   int size, offset;
11281
11282   D (emitcode (";", "genCast"));
11283
11284   /* if they are equivalent then do nothing */
11285   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11286     return;
11287
11288   aopOp (right, ic, FALSE);
11289   aopOp (result, ic, FALSE);
11290
11291   /* if the result is a bit (and not a bitfield) */
11292   if (IS_BIT (OP_SYMBOL (result)->type))
11293     {
11294       assignBit (result, right);
11295       goto release;
11296     }
11297
11298   /* if they are the same size : or less */
11299   if (AOP_SIZE (result) <= AOP_SIZE (right))
11300     {
11301
11302       /* if they are in the same place */
11303       if (sameRegs (AOP (right), AOP (result)))
11304         goto release;
11305
11306       /* if they in different places then copy */
11307       size = AOP_SIZE (result);
11308       offset = 0;
11309       while (size--)
11310         {
11311           aopPut (result,
11312                   aopGet (right, offset, FALSE, FALSE),
11313                   offset);
11314           offset++;
11315         }
11316       goto release;
11317     }
11318
11319   /* if the result is of type pointer */
11320   if (IS_PTR (ctype))
11321     {
11322
11323       int p_type;
11324       sym_link *type = operandType (right);
11325       sym_link *etype = getSpec (type);
11326
11327       /* pointer to generic pointer */
11328       if (IS_GENPTR (ctype))
11329         {
11330           if (IS_PTR (type))
11331             {
11332               p_type = DCL_TYPE (type);
11333             }
11334           else
11335             {
11336               if (SPEC_SCLS(etype)==S_REGISTER) {
11337                 // let's assume it is a generic pointer
11338                 p_type=GPOINTER;
11339               } else {
11340                 /* we have to go by the storage class */
11341                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11342               }
11343             }
11344
11345           /* the first two bytes are known */
11346           size = GPTRSIZE - 1;
11347           offset = 0;
11348           while (size--)
11349             {
11350               aopPut (result,
11351                       aopGet (right, offset, FALSE, FALSE),
11352                       offset);
11353               offset++;
11354             }
11355           /* the last byte depending on type */
11356             {
11357                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11358                 char gpValStr[10];
11359
11360                 if (gpVal == -1)
11361                 {
11362                     // pointerTypeToGPByte will have bitched.
11363                     exit(1);
11364                 }
11365
11366                 sprintf(gpValStr, "#0x%x", gpVal);
11367                 aopPut (result, gpValStr, GPTRSIZE - 1);
11368             }
11369           goto release;
11370         }
11371
11372       /* just copy the pointers */
11373       size = AOP_SIZE (result);
11374       offset = 0;
11375       while (size--)
11376         {
11377           aopPut (result,
11378                   aopGet (right, offset, FALSE, FALSE),
11379                   offset);
11380           offset++;
11381         }
11382       goto release;
11383     }
11384
11385   /* so we now know that the size of destination is greater
11386      than the size of the source */
11387   /* we move to result for the size of source */
11388   size = AOP_SIZE (right);
11389   offset = 0;
11390   while (size--)
11391     {
11392       aopPut (result,
11393               aopGet (right, offset, FALSE, FALSE),
11394               offset);
11395       offset++;
11396     }
11397
11398   /* now depending on the sign of the source && destination */
11399   size = AOP_SIZE (result) - AOP_SIZE (right);
11400   /* if unsigned or not an integral type */
11401   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11402     {
11403       while (size--)
11404         aopPut (result, zero, offset++);
11405     }
11406   else
11407     {
11408       /* we need to extend the sign :{ */
11409       char *l = aopGet (right, AOP_SIZE (right) - 1,
11410                         FALSE, FALSE);
11411       MOVA (l);
11412       emitcode ("rlc", "a");
11413       emitcode ("subb", "a,acc");
11414       while (size--)
11415         aopPut (result, "a", offset++);
11416     }
11417
11418   /* we are done hurray !!!! */
11419
11420 release:
11421   freeAsmop (result, NULL, ic, TRUE);
11422   freeAsmop (right, NULL, ic, TRUE);
11423 }
11424
11425 /*-----------------------------------------------------------------*/
11426 /* genDjnz - generate decrement & jump if not zero instrucion      */
11427 /*-----------------------------------------------------------------*/
11428 static int
11429 genDjnz (iCode * ic, iCode * ifx)
11430 {
11431   symbol *lbl, *lbl1;
11432   if (!ifx)
11433     return 0;
11434
11435   /* if the if condition has a false label
11436      then we cannot save */
11437   if (IC_FALSE (ifx))
11438     return 0;
11439
11440   /* if the minus is not of the form a = a - 1 */
11441   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11442       !IS_OP_LITERAL (IC_RIGHT (ic)))
11443     return 0;
11444
11445   if (operandLitValue (IC_RIGHT (ic)) != 1)
11446     return 0;
11447
11448   /* if the size of this greater than one then no
11449      saving */
11450   if (getSize (operandType (IC_RESULT (ic))) > 1)
11451     return 0;
11452
11453   /* otherwise we can save BIG */
11454
11455   D (emitcode (";", "genDjnz"));
11456
11457   lbl = newiTempLabel (NULL);
11458   lbl1 = newiTempLabel (NULL);
11459
11460   aopOp (IC_RESULT (ic), ic, FALSE);
11461
11462   if (AOP_NEEDSACC(IC_RESULT(ic)))
11463   {
11464       /* If the result is accessed indirectly via
11465        * the accumulator, we must explicitly write
11466        * it back after the decrement.
11467        */
11468       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11469
11470       if (strcmp(rByte, "a"))
11471       {
11472            /* Something is hopelessly wrong */
11473            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11474                    __FILE__, __LINE__);
11475            /* We can just give up; the generated code will be inefficient,
11476             * but what the hey.
11477             */
11478            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11479            return 0;
11480       }
11481       emitcode ("dec", "%s", rByte);
11482       aopPut (IC_RESULT (ic), rByte, 0);
11483       emitcode ("jnz", "%05d$", lbl->key + 100);
11484   }
11485   else if (IS_AOP_PREG (IC_RESULT (ic)))
11486     {
11487       emitcode ("dec", "%s",
11488                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11489       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11490       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11491       ifx->generated = 1;
11492       emitcode ("jnz", "%05d$", lbl->key + 100);
11493     }
11494   else
11495     {
11496       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11497                 lbl->key + 100);
11498     }
11499   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11500   emitLabel (lbl);
11501   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11502   emitLabel (lbl1);
11503
11504   if (!ifx->generated)
11505       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11506   ifx->generated = 1;
11507   return 1;
11508 }
11509
11510 /*-----------------------------------------------------------------*/
11511 /* genReceive - generate code for a receive iCode                  */
11512 /*-----------------------------------------------------------------*/
11513 static void
11514 genReceive (iCode * ic)
11515 {
11516   int size = getSize (operandType (IC_RESULT (ic)));
11517   int offset = 0;
11518
11519   D (emitcode (";", "genReceive"));
11520
11521   if (ic->argreg == 1)
11522     { /* first parameter */
11523       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11524            isOperandInPagedSpace (IC_RESULT (ic))) &&
11525           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11526            IS_TRUE_SYMOP (IC_RESULT (ic))))
11527         {
11528           regs *tempRegs[4];
11529           int receivingA = 0;
11530           int roffset = 0;
11531
11532           for (offset = 0; offset<size; offset++)
11533             if (!strcmp (fReturn[offset], "a"))
11534               receivingA = 1;
11535
11536           if (!receivingA)
11537             {
11538               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11539                 {
11540                   for (offset = size-1; offset>0; offset--)
11541                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11542                   emitcode("mov","a,%s", fReturn[0]);
11543                   _G.accInUse++;
11544                   aopOp (IC_RESULT (ic), ic, FALSE);
11545                   _G.accInUse--;
11546                   aopPut (IC_RESULT (ic), "a", offset);
11547                   for (offset = 1; offset<size; offset++)
11548                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11549                   goto release;
11550                 }
11551             }
11552           else
11553             {
11554               if (getTempRegs(tempRegs, size, ic))
11555                 {
11556                   for (offset = 0; offset<size; offset++)
11557                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11558                   aopOp (IC_RESULT (ic), ic, FALSE);
11559                   for (offset = 0; offset<size; offset++)
11560                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11561                   goto release;
11562                 }
11563             }
11564
11565           offset = fReturnSizeMCS51 - size;
11566           while (size--)
11567             {
11568               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11569                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11570               offset++;
11571             }
11572           aopOp (IC_RESULT (ic), ic, FALSE);
11573           size = AOP_SIZE (IC_RESULT (ic));
11574           offset = 0;
11575           while (size--)
11576             {
11577               emitcode ("pop", "acc");
11578               aopPut (IC_RESULT (ic), "a", offset++);
11579             }
11580         }
11581       else
11582         {
11583           _G.accInUse++;
11584           aopOp (IC_RESULT (ic), ic, FALSE);
11585           _G.accInUse--;
11586           assignResultValue (IC_RESULT (ic), NULL);
11587         }
11588     }
11589   else if (ic->argreg > 12)
11590     { /* bit parameters */
11591       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
11592         {
11593           aopOp (IC_RESULT (ic), ic, FALSE);
11594           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11595           outBitC(IC_RESULT (ic));
11596         }
11597     }
11598   else
11599     { /* other parameters */
11600       int rb1off ;
11601       aopOp (IC_RESULT (ic), ic, FALSE);
11602       rb1off = ic->argreg;
11603       while (size--)
11604         {
11605           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11606         }
11607     }
11608
11609 release:
11610   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11611 }
11612
11613 /*-----------------------------------------------------------------*/
11614 /* genDummyRead - generate code for dummy read of volatiles        */
11615 /*-----------------------------------------------------------------*/
11616 static void
11617 genDummyRead (iCode * ic)
11618 {
11619   operand *op;
11620   int size, offset;
11621
11622   D (emitcode(";", "genDummyRead"));
11623
11624   op = IC_RIGHT (ic);
11625   if (op && IS_SYMOP (op))
11626     {
11627       aopOp (op, ic, FALSE);
11628
11629       /* if the result is a bit */
11630       if (AOP_TYPE (op) == AOP_CRY)
11631         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11632       else
11633         {
11634           /* bit variables done */
11635           /* general case */
11636           size = AOP_SIZE (op);
11637           offset = 0;
11638           while (size--)
11639           {
11640             MOVA (aopGet (op, offset, FALSE, FALSE));
11641             offset++;
11642           }
11643         }
11644
11645       freeAsmop (op, NULL, ic, TRUE);
11646     }
11647
11648   op = IC_LEFT (ic);
11649   if (op && IS_SYMOP (op))
11650     {
11651       aopOp (op, ic, FALSE);
11652
11653       /* if the result is a bit */
11654       if (AOP_TYPE (op) == AOP_CRY)
11655         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11656       else
11657         {
11658           /* bit variables done */
11659           /* general case */
11660           size = AOP_SIZE (op);
11661           offset = 0;
11662           while (size--)
11663           {
11664             MOVA (aopGet (op, offset, FALSE, FALSE));
11665             offset++;
11666           }
11667         }
11668
11669       freeAsmop (op, NULL, ic, TRUE);
11670     }
11671 }
11672
11673 /*-----------------------------------------------------------------*/
11674 /* genCritical - generate code for start of a critical sequence    */
11675 /*-----------------------------------------------------------------*/
11676 static void
11677 genCritical (iCode *ic)
11678 {
11679   symbol *tlbl = newiTempLabel (NULL);
11680
11681   D (emitcode(";", "genCritical"));
11682
11683   if (IC_RESULT (ic))
11684     {
11685       aopOp (IC_RESULT (ic), ic, TRUE);
11686       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11687       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11688       aopPut (IC_RESULT (ic), zero, 0);
11689       emitLabel (tlbl);
11690       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11691     }
11692   else
11693     {
11694       emitcode ("setb", "c");
11695       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11696       emitcode ("clr", "c");
11697       emitLabel (tlbl);
11698       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11699     }
11700 }
11701
11702 /*-----------------------------------------------------------------*/
11703 /* genEndCritical - generate code for end of a critical sequence   */
11704 /*-----------------------------------------------------------------*/
11705 static void
11706 genEndCritical (iCode *ic)
11707 {
11708   D(emitcode(";", "genEndCritical"));
11709
11710   if (IC_RIGHT (ic))
11711     {
11712       aopOp (IC_RIGHT (ic), ic, FALSE);
11713       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11714         {
11715           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11716           emitcode ("mov", "ea,c");
11717         }
11718       else
11719         {
11720           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11721             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11722           emitcode ("rrc", "a");
11723           emitcode ("mov", "ea,c");
11724         }
11725       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11726     }
11727   else
11728     {
11729       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11730       emitcode ("mov", "ea,c");
11731     }
11732 }
11733
11734 /*-----------------------------------------------------------------*/
11735 /* gen51Code - generate code for 8051 based controllers            */
11736 /*-----------------------------------------------------------------*/
11737 void
11738 gen51Code (iCode * lic)
11739 {
11740   iCode *ic;
11741   int cln = 0;
11742   /* int cseq = 0; */
11743
11744   _G.currentFunc = NULL;
11745   lineHead = lineCurr = NULL;
11746
11747   /* print the allocation information */
11748   if (allocInfo && currFunc)
11749     printAllocInfo (currFunc, codeOutBuf);
11750   /* if debug information required */
11751   if (options.debug && currFunc)
11752     {
11753       debugFile->writeFunction (currFunc, lic);
11754     }
11755   /* stack pointer name */
11756   if (options.useXstack)
11757     spname = "_spx";
11758   else
11759     spname = "sp";
11760
11761
11762   for (ic = lic; ic; ic = ic->next)
11763     {
11764       _G.current_iCode = ic;
11765
11766       if (ic->lineno && cln != ic->lineno)
11767         {
11768           if (options.debug)
11769             {
11770               debugFile->writeCLine (ic);
11771             }
11772           if (!options.noCcodeInAsm) {
11773             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11774                       printCLine(ic->filename, ic->lineno));
11775           }
11776           cln = ic->lineno;
11777         }
11778       #if 0
11779       if (ic->seqPoint && ic->seqPoint != cseq)
11780         {
11781           emitcode (";", "sequence point %d", ic->seqPoint);
11782           cseq = ic->seqPoint;
11783         }
11784       #endif
11785       if (options.iCodeInAsm) {
11786         char regsInUse[80];
11787         int i;
11788         char *iLine;
11789
11790         #if 0
11791         for (i=0; i<8; i++) {
11792           sprintf (&regsInUse[i],
11793                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11794         regsInUse[i]=0;
11795         #else
11796         strcpy (regsInUse, "--------");
11797         for (i=0; i < 8; i++) {
11798           if (bitVectBitValue (ic->rMask, i))
11799             {
11800               int offset = regs8051[i].offset;
11801               regsInUse[offset] = offset + '0'; /* show rMask */
11802             }
11803         #endif
11804         }
11805         iLine = printILine(ic);
11806         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11807         dbuf_free(iLine);
11808       }
11809       /* if the result is marked as
11810          spilt and rematerializable or code for
11811          this has already been generated then
11812          do nothing */
11813       if (resultRemat (ic) || ic->generated)
11814         continue;
11815
11816       /* depending on the operation */
11817       switch (ic->op)
11818         {
11819         case '!':
11820           genNot (ic);
11821           break;
11822
11823         case '~':
11824           genCpl (ic);
11825           break;
11826
11827         case UNARYMINUS:
11828           genUminus (ic);
11829           break;
11830
11831         case IPUSH:
11832           genIpush (ic);
11833           break;
11834
11835         case IPOP:
11836           /* IPOP happens only when trying to restore a
11837              spilt live range, if there is an ifx statement
11838              following this pop then the if statement might
11839              be using some of the registers being popped which
11840              would destory the contents of the register so
11841              we need to check for this condition and handle it */
11842           if (ic->next &&
11843               ic->next->op == IFX &&
11844               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11845             genIfx (ic->next, ic);
11846           else
11847             genIpop (ic);
11848           break;
11849
11850         case CALL:
11851           genCall (ic);
11852           break;
11853
11854         case PCALL:
11855           genPcall (ic);
11856           break;
11857
11858         case FUNCTION:
11859           genFunction (ic);
11860           break;
11861
11862         case ENDFUNCTION:
11863           genEndFunction (ic);
11864           break;
11865
11866         case RETURN:
11867           genRet (ic);
11868           break;
11869
11870         case LABEL:
11871           genLabel (ic);
11872           break;
11873
11874         case GOTO:
11875           genGoto (ic);
11876           break;
11877
11878         case '+':
11879           genPlus (ic);
11880           break;
11881
11882         case '-':
11883           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11884             genMinus (ic);
11885           break;
11886
11887         case '*':
11888           genMult (ic);
11889           break;
11890
11891         case '/':
11892           genDiv (ic);
11893           break;
11894
11895         case '%':
11896           genMod (ic);
11897           break;
11898
11899         case '>':
11900           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11901           break;
11902
11903         case '<':
11904           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11905           break;
11906
11907         case LE_OP:
11908         case GE_OP:
11909         case NE_OP:
11910
11911           /* note these two are xlated by algebraic equivalence
11912              in decorateType() in SDCCast.c */
11913           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11914                   "got '>=' or '<=' shouldn't have come here");
11915           break;
11916
11917         case EQ_OP:
11918           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11919           break;
11920
11921         case AND_OP:
11922           genAndOp (ic);
11923           break;
11924
11925         case OR_OP:
11926           genOrOp (ic);
11927           break;
11928
11929         case '^':
11930           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11931           break;
11932
11933         case '|':
11934           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11935           break;
11936
11937         case BITWISEAND:
11938           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11939           break;
11940
11941         case INLINEASM:
11942           genInline (ic);
11943           break;
11944
11945         case RRC:
11946           genRRC (ic);
11947           break;
11948
11949         case RLC:
11950           genRLC (ic);
11951           break;
11952
11953         case GETHBIT:
11954           genGetHbit (ic);
11955           break;
11956
11957         case GETABIT:
11958           genGetAbit (ic);
11959           break;
11960
11961         case GETBYTE:
11962           genGetByte (ic);
11963           break;
11964
11965         case GETWORD:
11966           genGetWord (ic);
11967           break;
11968
11969         case LEFT_OP:
11970           genLeftShift (ic);
11971           break;
11972
11973         case RIGHT_OP:
11974           genRightShift (ic);
11975           break;
11976
11977         case GET_VALUE_AT_ADDRESS:
11978           genPointerGet (ic,
11979                          hasInc (IC_LEFT (ic), ic,
11980                                  getSize (operandType (IC_RESULT (ic)))),
11981                          ifxForOp (IC_RESULT (ic), ic) );
11982           break;
11983
11984         case '=':
11985           if (POINTER_SET (ic))
11986             genPointerSet (ic,
11987                            hasInc (IC_RESULT (ic), ic,
11988                                    getSize (operandType (IC_RIGHT (ic)))));
11989           else
11990             genAssign (ic);
11991           break;
11992
11993         case IFX:
11994           genIfx (ic, NULL);
11995           break;
11996
11997         case ADDRESS_OF:
11998           genAddrOf (ic);
11999           break;
12000
12001         case JUMPTABLE:
12002           genJumpTab (ic);
12003           break;
12004
12005         case CAST:
12006           genCast (ic);
12007           break;
12008
12009         case RECEIVE:
12010           genReceive (ic);
12011           break;
12012
12013         case SEND:
12014           addSet (&_G.sendSet, ic);
12015           break;
12016
12017         case DUMMY_READ_VOLATILE:
12018           genDummyRead (ic);
12019           break;
12020
12021         case CRITICAL:
12022           genCritical (ic);
12023           break;
12024
12025         case ENDCRITICAL:
12026           genEndCritical (ic);
12027           break;
12028
12029         case SWAP:
12030           genSwap (ic);
12031           break;
12032
12033         default:
12034           ic = ic;
12035         }
12036     }
12037
12038   _G.current_iCode = NULL;
12039
12040   /* now we are ready to call the
12041      peep hole optimizer */
12042   if (!options.nopeep)
12043     peepHole (&lineHead);
12044
12045   /* now do the actual printing */
12046   printLine (lineHead, codeOutBuf);
12047   return;
12048 }