* src/mcs51/gen.c (genUnpackBits): don't generate ifxJump, instead return
[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_OP_ACCUSE (op))
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_OP_ACCUSE (op))
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_OP_ACCUSE (op))
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_OP_ACCUSE (op))
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 - rematerializes 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         {
733           sym_link *from_type = operandType(IC_RIGHT(ic));
734           aop->aopu.aop_immd.from_cast_remat = 1;
735           ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
736           ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
737           continue;
738         }
739       else break;
740
741       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
742     }
743
744   if (val)
745     {
746       SNPRINTF (buffer, sizeof(buffer),
747                 "(%s %c 0x%04x)",
748                 OP_SYMBOL (IC_LEFT (ic))->rname,
749                 val >= 0 ? '+' : '-',
750                 abs (val) & 0xffff);
751     }
752   else
753     {
754       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
755     }
756
757   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
758   /* set immd2 field if required */
759   if (aop->aopu.aop_immd.from_cast_remat)
760     {
761       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
762       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
763     }
764
765   return aop;
766 }
767
768 /*-----------------------------------------------------------------*/
769 /* regsInCommon - two operands have some registers in common       */
770 /*-----------------------------------------------------------------*/
771 static bool
772 regsInCommon (operand * op1, operand * op2)
773 {
774   symbol *sym1, *sym2;
775   int i;
776
777   /* if they have registers in common */
778   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
779     return FALSE;
780
781   sym1 = OP_SYMBOL (op1);
782   sym2 = OP_SYMBOL (op2);
783
784   if (sym1->nRegs == 0 || sym2->nRegs == 0)
785     return FALSE;
786
787   for (i = 0; i < sym1->nRegs; i++)
788     {
789       int j;
790       if (!sym1->regs[i])
791         continue;
792
793       for (j = 0; j < sym2->nRegs; j++)
794         {
795           if (!sym2->regs[j])
796             continue;
797
798           if (sym2->regs[j] == sym1->regs[i])
799             return TRUE;
800         }
801     }
802
803   return FALSE;
804 }
805
806 /*-----------------------------------------------------------------*/
807 /* operandsEqu - equivalent                                        */
808 /*-----------------------------------------------------------------*/
809 static bool
810 operandsEqu (operand * op1, operand * op2)
811 {
812   symbol *sym1, *sym2;
813
814   /* if they're not symbols */
815   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
816     return FALSE;
817
818   sym1 = OP_SYMBOL (op1);
819   sym2 = OP_SYMBOL (op2);
820
821   /* if both are itemps & one is spilt
822      and the other is not then false */
823   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
824       sym1->isspilt != sym2->isspilt)
825     return FALSE;
826
827   /* if they are the same */
828   if (sym1 == sym2)
829     return TRUE;
830
831   /* if they have the same rname */
832   if (sym1->rname[0] && sym2->rname[0] &&
833       strcmp (sym1->rname, sym2->rname) == 0 &&
834       !(IS_PARM (op2) && IS_ITEMP (op1)))
835     return TRUE;
836
837   /* if left is a tmp & right is not */
838   if (IS_ITEMP (op1) &&
839       !IS_ITEMP (op2) &&
840       sym1->isspilt &&
841       (sym1->usl.spillLoc == sym2))
842     return TRUE;
843
844   if (IS_ITEMP (op2) &&
845       !IS_ITEMP (op1) &&
846       sym2->isspilt &&
847       sym1->level > 0 &&
848       (sym2->usl.spillLoc == sym1))
849     return TRUE;
850
851   return FALSE;
852 }
853
854 /*-----------------------------------------------------------------*/
855 /* sameByte - two asmops have the same address at given offsets    */
856 /*-----------------------------------------------------------------*/
857 static bool
858 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
859 {
860   if (aop1 == aop2 && off1 == off2)
861     return TRUE;
862
863   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
864     return FALSE;
865
866   if (aop1->type != aop2->type)
867     return FALSE;
868
869   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
870     return FALSE;
871
872   return TRUE;
873 }
874
875 /*-----------------------------------------------------------------*/
876 /* sameRegs - two asmops have the same registers                   */
877 /*-----------------------------------------------------------------*/
878 static bool
879 sameRegs (asmop * aop1, asmop * aop2)
880 {
881   int i;
882
883   if (aop1 == aop2)
884     return TRUE;
885
886   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
887     return FALSE;
888
889   if (aop1->type != aop2->type)
890     return FALSE;
891
892   if (aop1->size != aop2->size)
893     return FALSE;
894
895   for (i = 0; i < aop1->size; i++)
896     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
897       return FALSE;
898
899   return TRUE;
900 }
901
902 /*-----------------------------------------------------------------*/
903 /* aopOp - allocates an asmop for an operand  :                    */
904 /*-----------------------------------------------------------------*/
905 static void
906 aopOp (operand * op, iCode * ic, bool result)
907 {
908   asmop *aop;
909   symbol *sym;
910   int i;
911
912   if (!op)
913     return;
914
915   /* if this a literal */
916   if (IS_OP_LITERAL (op))
917     {
918       op->aop = aop = newAsmop (AOP_LIT);
919       aop->aopu.aop_lit = op->operand.valOperand;
920       aop->size = getSize (operandType (op));
921       return;
922     }
923
924   /* if already has a asmop then continue */
925   if (op->aop)
926     {
927       op->aop->allocated++;
928       return;
929     }
930
931   /* if the underlying symbol has a aop */
932   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
933     {
934       op->aop = OP_SYMBOL (op)->aop;
935       op->aop->allocated++;
936       return;
937     }
938
939   /* if this is a true symbol */
940   if (IS_TRUE_SYMOP (op))
941     {
942       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
943       return;
944     }
945
946   /* this is a temporary : this has
947      only five choices :
948      a) register
949      b) spillocation
950      c) rematerialize
951      d) conditional
952      e) can be a return use only */
953
954   sym = OP_SYMBOL (op);
955
956   /* if the type is a conditional */
957   if (sym->regType == REG_CND)
958     {
959       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
960       aop->size = sym->ruonly ? 1 : 0;
961       return;
962     }
963
964   /* if it is spilt then two situations
965      a) is rematerialize
966      b) has a spill location */
967   if (sym->isspilt || sym->nRegs == 0)
968     {
969
970       /* rematerialize it NOW */
971       if (sym->remat)
972         {
973           sym->aop = op->aop = aop = aopForRemat (sym);
974           aop->size = operandSize (op);
975           return;
976         }
977
978       if (sym->accuse)
979         {
980           int i;
981           sym->aop = op->aop = aop = newAsmop (AOP_ACC);
982           aop->size = getSize (sym->type);
983           for (i = 0; i < 2; i++)
984             aop->aopu.aop_str[i] = accUse[i];
985           return;
986         }
987
988       if (sym->ruonly)
989         {
990           unsigned i;
991
992           sym->aop = op->aop = aop = newAsmop (AOP_STR);
993           aop->size = getSize (sym->type);
994           for (i = 0; i < fReturnSizeMCS51; i++)
995             aop->aopu.aop_str[i] = fReturn[i];
996           return;
997         }
998
999       if (sym->usl.spillLoc)
1000         {
1001           asmop *oldAsmOp = NULL;
1002
1003           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1004             {
1005               /* force a new aop if sizes differ */
1006               oldAsmOp = sym->usl.spillLoc->aop;
1007               sym->usl.spillLoc->aop = NULL;
1008             }
1009           sym->aop = op->aop = aop =
1010                      aopForSym (ic, sym->usl.spillLoc, result);
1011           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1012             {
1013               /* Don't reuse the new aop, go with the last one */
1014               sym->usl.spillLoc->aop = oldAsmOp;
1015             }
1016           aop->size = getSize (sym->type);
1017           return;
1018         }
1019
1020       /* else must be a dummy iTemp */
1021       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1022       aop->size = getSize (sym->type);
1023       return;
1024     }
1025
1026   /* if the type is a bit register */
1027   if (sym->regType == REG_BIT)
1028     {
1029       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1030       aop->size = sym->nRegs;//1???
1031       aop->aopu.aop_reg[0] = sym->regs[0];
1032       aop->aopu.aop_dir = sym->regs[0]->name;
1033       return;
1034     }
1035
1036   /* must be in a register */
1037   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1038   aop->size = sym->nRegs;
1039   for (i = 0; i < sym->nRegs; i++)
1040     aop->aopu.aop_reg[i] = sym->regs[i];
1041 }
1042
1043 /*-----------------------------------------------------------------*/
1044 /* freeAsmop - free up the asmop given to an operand               */
1045 /*----------------------------------------------------------------*/
1046 static void
1047 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1048 {
1049   asmop *aop;
1050
1051   if (!op)
1052     aop = aaop;
1053   else
1054     aop = op->aop;
1055
1056   if (!aop)
1057     return;
1058
1059   aop->allocated--;
1060
1061   if (aop->allocated)
1062     goto dealloc;
1063
1064   /* depending on the asmop type only three cases need work
1065      AOP_R0, AOP_R1 & AOP_STK */
1066   switch (aop->type)
1067     {
1068     case AOP_R0:
1069       if (R0INB)
1070         {
1071           emitcode ("mov", "r0,b");
1072           R0INB--;
1073         }
1074       else if (_G.r0Pushed)
1075         {
1076           if (pop)
1077             {
1078               emitcode ("pop", "ar0");
1079               _G.r0Pushed--;
1080             }
1081         }
1082       bitVectUnSetBit (ic->rUsed, R0_IDX);
1083       break;
1084
1085     case AOP_R1:
1086       if (R1INB)
1087         {
1088           emitcode ("mov", "r1,b");
1089           R1INB--;
1090         }
1091       else if (_G.r1Pushed)
1092         {
1093           if (pop)
1094             {
1095               emitcode ("pop", "ar1");
1096               _G.r1Pushed--;
1097             }
1098         }
1099       bitVectUnSetBit (ic->rUsed, R1_IDX);
1100       break;
1101
1102     case AOP_STK:
1103       {
1104         int sz = aop->size;
1105         int stk = aop->aopu.aop_stk + aop->size - 1;
1106         bitVectUnSetBit (ic->rUsed, R0_IDX);
1107         bitVectUnSetBit (ic->rUsed, R1_IDX);
1108
1109         getFreePtr (ic, &aop, FALSE);
1110
1111         if (stk)
1112           {
1113             emitcode ("mov", "a,_bp");
1114             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1115             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1116           }
1117         else
1118           {
1119             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1120           }
1121
1122         while (sz--)
1123           {
1124             emitcode ("pop", "acc");
1125             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1126             if (!sz)
1127               break;
1128             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1129           }
1130         op->aop = aop;
1131         freeAsmop (op, NULL, ic, TRUE);
1132         if (_G.r1Pushed)
1133           {
1134             emitcode ("pop", "ar1");
1135             _G.r1Pushed--;
1136           }
1137         if (_G.r0Pushed)
1138           {
1139             emitcode ("pop", "ar0");
1140             _G.r0Pushed--;
1141           }
1142       }
1143       break;
1144     }
1145
1146 dealloc:
1147   /* all other cases just dealloc */
1148   if (op)
1149     {
1150       op->aop = NULL;
1151       if (IS_SYMOP (op))
1152         {
1153           OP_SYMBOL (op)->aop = NULL;
1154           /* if the symbol has a spill */
1155           if (SPIL_LOC (op))
1156             SPIL_LOC (op)->aop = NULL;
1157         }
1158     }
1159 }
1160
1161 /*------------------------------------------------------------------*/
1162 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1163 /*                      pop r0 or r1 off stack if pushed            */
1164 /*------------------------------------------------------------------*/
1165 static void
1166 freeForBranchAsmop (operand * op)
1167 {
1168   asmop *aop;
1169
1170   if (!op)
1171     return;
1172
1173   aop = op->aop;
1174
1175   if (!aop)
1176     return;
1177
1178   if (!aop->allocated)
1179     return;
1180
1181   switch (aop->type)
1182     {
1183     case AOP_R0:
1184       if (R0INB)
1185         {
1186           emitcode ("mov", "r0,b");
1187         }
1188       else if (_G.r0Pushed)
1189         {
1190           emitcode ("pop", "ar0");
1191         }
1192       break;
1193
1194     case AOP_R1:
1195       if (R1INB)
1196         {
1197           emitcode ("mov", "r1,b");
1198         }
1199       else if (_G.r1Pushed)
1200         {
1201           emitcode ("pop", "ar1");
1202         }
1203       break;
1204
1205     case AOP_STK:
1206       {
1207         int sz = aop->size;
1208         int stk = aop->aopu.aop_stk + aop->size - 1;
1209
1210         emitcode ("mov", "b,r0");
1211         if (stk)
1212           {
1213             emitcode ("mov", "a,_bp");
1214             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1215             emitcode ("mov", "r0,a");
1216           }
1217         else
1218           {
1219             emitcode ("mov", "r0,_bp");
1220           }
1221
1222         while (sz--)
1223           {
1224             emitcode ("pop", "acc");
1225             emitcode ("mov", "@r0,a");
1226             if (!sz)
1227               break;
1228             emitcode ("dec", "r0");
1229           }
1230         emitcode ("mov", "r0,b");
1231       }
1232     }
1233
1234 }
1235
1236 /*-----------------------------------------------------------------*/
1237 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1238 /*                 clobber the accumulator                         */
1239 /*-----------------------------------------------------------------*/
1240 static bool
1241 aopGetUsesAcc (operand * oper, int offset)
1242 {
1243   asmop * aop = AOP (oper);
1244
1245   if (offset > (aop->size - 1))
1246     return FALSE;
1247
1248   switch (aop->type)
1249     {
1250
1251     case AOP_R0:
1252     case AOP_R1:
1253       if (aop->paged)
1254         return TRUE;
1255       return FALSE;
1256     case AOP_DPTR:
1257       return TRUE;
1258     case AOP_IMMD:
1259       return FALSE;
1260     case AOP_DIR:
1261       return FALSE;
1262     case AOP_REG:
1263       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1264       return FALSE;
1265     case AOP_CRY:
1266       return TRUE;
1267     case AOP_ACC:
1268       if (offset)
1269         return FALSE;
1270       return TRUE;
1271     case AOP_LIT:
1272       return FALSE;
1273     case AOP_STR:
1274       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1275         return TRUE;
1276       return FALSE;
1277     case AOP_DUMMY:
1278       return FALSE;
1279     default:
1280       /* Error case --- will have been caught already */
1281       wassert(0);
1282       return FALSE;
1283     }
1284 }
1285
1286 /*-------------------------------------------------------------------*/
1287 /* aopGet - for fetching value of the aop                            */
1288 /*-------------------------------------------------------------------*/
1289 static char *
1290 aopGet (operand * oper, int offset, bool bit16, bool dname)
1291 {
1292   asmop * aop = AOP (oper);
1293
1294   /* offset is greater than
1295      size then zero */
1296   if (offset > (aop->size - 1) &&
1297       aop->type != AOP_LIT)
1298     return zero;
1299
1300   /* depending on type */
1301   switch (aop->type)
1302     {
1303     case AOP_DUMMY:
1304       return zero;
1305
1306     case AOP_R0:
1307     case AOP_R1:
1308       /* if we need to increment it */
1309       while (offset > aop->coff)
1310         {
1311           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1312           aop->coff++;
1313         }
1314
1315       while (offset < aop->coff)
1316         {
1317           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1318           aop->coff--;
1319         }
1320
1321       aop->coff = offset;
1322       if (aop->paged)
1323         {
1324           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1325           return (dname ? "acc" : "a");
1326         }
1327       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1328       return Safe_strdup(buffer);
1329
1330     case AOP_DPTR:
1331       if (aop->code && aop->coff==0 && offset>=1) {
1332         emitcode ("mov", "a,#0x%02x", offset);
1333         emitcode ("movc", "a,@a+dptr");
1334         return (dname ? "acc" : "a");
1335       }
1336
1337       while (offset > aop->coff)
1338         {
1339           emitcode ("inc", "dptr");
1340           aop->coff++;
1341         }
1342
1343       while (offset < aop->coff)
1344         {
1345           emitcode ("lcall", "__decdptr");
1346           aop->coff--;
1347         }
1348
1349       aop->coff = offset;
1350       if (aop->code)
1351         {
1352           emitcode ("clr", "a");
1353           emitcode ("movc", "a,@a+dptr");
1354         }
1355       else
1356         {
1357           emitcode ("movx", "a,@dptr");
1358         }
1359       return (dname ? "acc" : "a");
1360
1361     case AOP_IMMD:
1362       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1363         {
1364           SNPRINTF(buffer, sizeof(buffer),
1365                    "%s",aop->aopu.aop_immd.aop_immd2);
1366         }
1367       else if (bit16)
1368         {
1369           SNPRINTF(buffer, sizeof(buffer),
1370                    "#%s", aop->aopu.aop_immd.aop_immd1);
1371         }
1372       else if (offset)
1373         {
1374           SNPRINTF (buffer, sizeof(buffer),
1375                     "#(%s >> %d)",
1376                     aop->aopu.aop_immd.aop_immd1,
1377                     offset * 8);
1378         }
1379       else
1380         {
1381           SNPRINTF (buffer, sizeof(buffer),
1382                     "#%s",
1383                     aop->aopu.aop_immd.aop_immd1);
1384         }
1385       return Safe_strdup(buffer);
1386
1387     case AOP_DIR:
1388       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1389         {
1390           SNPRINTF (buffer, sizeof(buffer),
1391                     "(%s >> %d)",
1392                     aop->aopu.aop_dir, offset * 8);
1393         }
1394       else if (offset)
1395         {
1396           SNPRINTF (buffer, sizeof(buffer),
1397                     "(%s + %d)",
1398                     aop->aopu.aop_dir,
1399                     offset);
1400         }
1401       else
1402         {
1403           SNPRINTF (buffer, sizeof(buffer),
1404                     "%s",
1405                     aop->aopu.aop_dir);
1406         }
1407
1408       return Safe_strdup(buffer);
1409
1410     case AOP_REG:
1411       if (dname)
1412         return aop->aopu.aop_reg[offset]->dname;
1413       else
1414         return aop->aopu.aop_reg[offset]->name;
1415
1416     case AOP_CRY:
1417       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1418       emitcode ("clr", "a");
1419       emitcode ("rlc", "a");
1420       return (dname ? "acc" : "a");
1421
1422     case AOP_ACC:
1423       if (!offset && dname)
1424         return "acc";
1425       return aop->aopu.aop_str[offset];
1426
1427     case AOP_LIT:
1428       return aopLiteral (aop->aopu.aop_lit, offset);
1429
1430     case AOP_STR:
1431       aop->coff = offset;
1432       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1433           dname)
1434         return "acc";
1435
1436       return aop->aopu.aop_str[offset];
1437
1438     }
1439
1440   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1441           "aopget got unsupported aop->type");
1442   exit (1);
1443 }
1444
1445 /*-----------------------------------------------------------------*/
1446 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1447 /*                 clobber the accumulator                         */
1448 /*-----------------------------------------------------------------*/
1449 static bool
1450 aopPutUsesAcc (operand * oper, const char *s, int offset)
1451 {
1452   asmop * aop = AOP (oper);
1453
1454   if (offset > (aop->size - 1))
1455     return FALSE;
1456
1457   switch (aop->type)
1458     {
1459     case AOP_DUMMY:
1460       return TRUE;
1461     case AOP_DIR:
1462       return FALSE;
1463     case AOP_REG:
1464       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1465       return FALSE;
1466     case AOP_DPTR:
1467       return TRUE;
1468     case AOP_R0:
1469     case AOP_R1:
1470       return ((aop->paged) || (*s == '@'));
1471     case AOP_STK:
1472       return (*s == '@');
1473     case AOP_CRY:
1474       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1475     case AOP_STR:
1476       return FALSE;
1477     case AOP_IMMD:
1478       return FALSE;
1479     case AOP_ACC:
1480       return FALSE;
1481     default:
1482       /* Error case --- will have been caught already */
1483       wassert(0);
1484       return FALSE;
1485     }
1486 }
1487
1488 /*-----------------------------------------------------------------*/
1489 /* aopPut - puts a string for a aop and indicates if acc is in use */
1490 /*-----------------------------------------------------------------*/
1491 static bool
1492 aopPut (operand * result, const char *s, int offset)
1493 {
1494   bool bvolatile = isOperandVolatile (result, FALSE);
1495   bool accuse = FALSE;
1496   asmop * aop = AOP (result);
1497   const char *d = NULL;
1498
1499   if (aop->size && offset > (aop->size - 1))
1500     {
1501       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1502               "aopPut got offset > aop->size");
1503       exit (1);
1504     }
1505
1506   /* will assign value to value */
1507   /* depending on where it is ofcourse */
1508   switch (aop->type)
1509     {
1510     case AOP_DUMMY:
1511       MOVA (s);         /* read s in case it was volatile */
1512       accuse = TRUE;
1513       break;
1514
1515     case AOP_DIR:
1516       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1517         {
1518           SNPRINTF (buffer, sizeof(buffer),
1519                     "(%s >> %d)",
1520                     aop->aopu.aop_dir, offset * 8);
1521         }
1522       else if (offset)
1523         {
1524           SNPRINTF (buffer, sizeof(buffer),
1525                     "(%s + %d)",
1526                     aop->aopu.aop_dir, offset);
1527         }
1528       else
1529         {
1530           SNPRINTF (buffer, sizeof(buffer),
1531                     "%s",
1532                     aop->aopu.aop_dir);
1533         }
1534
1535       if (strcmp (buffer, s) || bvolatile)
1536         {
1537           emitcode ("mov", "%s,%s", buffer, s);
1538         }
1539       if (!strcmp (buffer, "acc"))
1540         {
1541           accuse = TRUE;
1542         }
1543       break;
1544
1545     case AOP_REG:
1546       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1547           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1548         {
1549           if (*s == '@' ||
1550               strcmp (s, "r0") == 0 ||
1551               strcmp (s, "r1") == 0 ||
1552               strcmp (s, "r2") == 0 ||
1553               strcmp (s, "r3") == 0 ||
1554               strcmp (s, "r4") == 0 ||
1555               strcmp (s, "r5") == 0 ||
1556               strcmp (s, "r6") == 0 ||
1557               strcmp (s, "r7") == 0)
1558             {
1559               emitcode ("mov", "%s,%s",
1560                         aop->aopu.aop_reg[offset]->dname, s);
1561             }
1562           else
1563             {
1564               emitcode ("mov", "%s,%s",
1565                         aop->aopu.aop_reg[offset]->name, s);
1566             }
1567         }
1568       break;
1569
1570     case AOP_DPTR:
1571       if (aop->code)
1572         {
1573           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1574                   "aopPut writing to code space");
1575           exit (1);
1576         }
1577
1578       while (offset > aop->coff)
1579         {
1580           aop->coff++;
1581           emitcode ("inc", "dptr");
1582         }
1583
1584       while (offset < aop->coff)
1585         {
1586           aop->coff--;
1587           emitcode ("lcall", "__decdptr");
1588         }
1589
1590       aop->coff = offset;
1591
1592       /* if not in accumulator */
1593       MOVA (s);
1594
1595       emitcode ("movx", "@dptr,a");
1596       break;
1597
1598     case AOP_R0:
1599     case AOP_R1:
1600       while (offset > aop->coff)
1601         {
1602           aop->coff++;
1603           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1604         }
1605       while (offset < aop->coff)
1606         {
1607           aop->coff--;
1608           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1609         }
1610       aop->coff = offset;
1611
1612       if (aop->paged)
1613         {
1614           MOVA (s);
1615           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1616         }
1617       else if (*s == '@')
1618         {
1619           MOVA (s);
1620           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1621         }
1622       else if (strcmp (s, "r0") == 0 ||
1623                strcmp (s, "r1") == 0 ||
1624                strcmp (s, "r2") == 0 ||
1625                strcmp (s, "r3") == 0 ||
1626                strcmp (s, "r4") == 0 ||
1627                strcmp (s, "r5") == 0 ||
1628                strcmp (s, "r6") == 0 ||
1629                strcmp (s, "r7") == 0)
1630         {
1631           char buffer[10];
1632           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1633           emitcode ("mov", "@%s,%s",
1634                     aop->aopu.aop_ptr->name, buffer);
1635         }
1636       else
1637         {
1638           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1639         }
1640       break;
1641
1642     case AOP_STK:
1643       if (strcmp (s, "a") == 0)
1644         {
1645           emitcode ("push", "acc");
1646         }
1647       else if (*s=='@')
1648         {
1649           MOVA(s);
1650           emitcode ("push", "acc");
1651         }
1652       else if (strcmp (s, "r0") == 0 ||
1653                strcmp (s, "r1") == 0 ||
1654                strcmp (s, "r2") == 0 ||
1655                strcmp (s, "r3") == 0 ||
1656                strcmp (s, "r4") == 0 ||
1657                strcmp (s, "r5") == 0 ||
1658                strcmp (s, "r6") == 0 ||
1659                strcmp (s, "r7") == 0)
1660         {
1661           char buffer[10];
1662           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1663           emitcode ("push", buffer);
1664         }
1665       else
1666         {
1667           emitcode ("push", s);
1668         }
1669
1670       break;
1671
1672     case AOP_CRY:
1673       // destination is carry for return-use-only
1674       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1675       // source is no literal and not in carry
1676       if ((s != zero) && (s != one) && strcmp (s, "c"))
1677         {
1678           MOVA (s);
1679           /* set C, if a >= 1 */
1680           emitcode ("add", "a,#0xff");
1681           s = "c";
1682         }
1683       // now source is zero, one or carry
1684
1685       /* if result no bit variable */
1686       if (!d)
1687         {
1688           if (!strcmp (s, "c"))
1689             {
1690               /* inefficient: move carry into A and use jz/jnz */
1691               emitcode ("clr", "a");
1692               emitcode ("rlc", "a");
1693               accuse = TRUE;
1694             }
1695           else
1696             {
1697               MOVA (s);
1698               accuse = TRUE;
1699             }
1700         }
1701       else if (s == zero)
1702           emitcode ("clr", "%s", d);
1703       else if (s == one)
1704           emitcode ("setb", "%s", d);
1705       else if (strcmp (s, d))
1706           emitcode ("mov", "%s,c", d);
1707       break;
1708
1709     case AOP_STR:
1710       aop->coff = offset;
1711       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1712         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1713       break;
1714
1715     case AOP_ACC:
1716       accuse = TRUE;
1717       aop->coff = offset;
1718       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1719         break;
1720
1721       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1722         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1723       break;
1724
1725     default:
1726       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1727               "aopPut got unsupported aop->type");
1728       exit (1);
1729     }
1730
1731     return accuse;
1732 }
1733
1734
1735 #if 0
1736 /*-----------------------------------------------------------------*/
1737 /* pointToEnd :- points to the last byte of the operand            */
1738 /*-----------------------------------------------------------------*/
1739 static void
1740 pointToEnd (asmop * aop)
1741 {
1742   int count;
1743   if (!aop)
1744     return;
1745
1746   aop->coff = count = (aop->size - 1);
1747   switch (aop->type)
1748     {
1749     case AOP_R0:
1750     case AOP_R1:
1751       while (count--)
1752         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1753       break;
1754     case AOP_DPTR:
1755       while (count--)
1756         emitcode ("inc", "dptr");
1757       break;
1758     }
1759
1760 }
1761 #endif
1762
1763 /*-----------------------------------------------------------------*/
1764 /* reAdjustPreg - points a register back to where it should        */
1765 /*-----------------------------------------------------------------*/
1766 static void
1767 reAdjustPreg (asmop * aop)
1768 {
1769   if ((aop->coff==0) || (aop->size <= 1))
1770     return;
1771
1772   switch (aop->type)
1773     {
1774     case AOP_R0:
1775     case AOP_R1:
1776       while (aop->coff--)
1777         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1778       break;
1779     case AOP_DPTR:
1780       while (aop->coff--)
1781         {
1782           emitcode ("lcall", "__decdptr");
1783         }
1784       break;
1785     }
1786   aop->coff = 0;
1787 }
1788
1789 /*-----------------------------------------------------------------*/
1790 /* opIsGptr: returns non-zero if the passed operand is       */
1791 /* a generic pointer type.             */
1792 /*-----------------------------------------------------------------*/
1793 static int
1794 opIsGptr (operand * op)
1795 {
1796   sym_link *type = operandType (op);
1797
1798   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1799     {
1800       return 1;
1801     }
1802   return 0;
1803 }
1804
1805 /*-----------------------------------------------------------------*/
1806 /* getDataSize - get the operand data size                         */
1807 /*-----------------------------------------------------------------*/
1808 static int
1809 getDataSize (operand * op)
1810 {
1811   int size;
1812   size = AOP_SIZE (op);
1813   if (size == GPTRSIZE)
1814     {
1815       sym_link *type = operandType (op);
1816       if (IS_GENPTR (type))
1817         {
1818           /* generic pointer; arithmetic operations
1819            * should ignore the high byte (pointer type).
1820            */
1821           size--;
1822         }
1823     }
1824   return size;
1825 }
1826
1827 /*-----------------------------------------------------------------*/
1828 /* outAcc - output Acc                                             */
1829 /*-----------------------------------------------------------------*/
1830 static void
1831 outAcc (operand * result)
1832 {
1833   int size, offset;
1834   size = getDataSize (result);
1835   if (size)
1836     {
1837       aopPut (result, "a", 0);
1838       size--;
1839       offset = 1;
1840       /* unsigned or positive */
1841       while (size--)
1842         {
1843           aopPut (result, zero, offset++);
1844         }
1845     }
1846 }
1847
1848 /*-----------------------------------------------------------------*/
1849 /* outBitC - output a bit C                                        */
1850 /*-----------------------------------------------------------------*/
1851 static void
1852 outBitC (operand * result)
1853 {
1854   /* if the result is bit */
1855   if (AOP_TYPE (result) == AOP_CRY)
1856     {
1857       if (!IS_OP_RUONLY (result))
1858         aopPut (result, "c", 0);
1859     }
1860   else if (AOP_TYPE (result) != AOP_DUMMY)
1861     {
1862       emitcode ("clr", "a");
1863       emitcode ("rlc", "a");
1864       outAcc (result);
1865     }
1866 }
1867
1868 /*-----------------------------------------------------------------*/
1869 /* toBoolean - emit code for orl a,operator(sizeop)                */
1870 /*-----------------------------------------------------------------*/
1871 static void
1872 toBoolean (operand * oper)
1873 {
1874   int size = AOP_SIZE (oper) - 1;
1875   int offset = 1;
1876   bool AccUsed = FALSE;
1877   bool pushedB;
1878
1879   while (!AccUsed && size--)
1880     {
1881       AccUsed |= aopGetUsesAcc(oper, offset++);
1882     }
1883
1884   size = AOP_SIZE (oper) - 1;
1885   offset = 1;
1886   MOVA (aopGet (oper, 0, FALSE, FALSE));
1887   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1888     {
1889       pushedB = pushB ();
1890       emitcode("mov", "b,a");
1891       while (--size)
1892         {
1893           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1894           emitcode ("orl", "b,a");
1895         }
1896       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1897       emitcode ("orl", "a,b");
1898       popB (pushedB);
1899     }
1900   else
1901     {
1902       while (size--)
1903         {
1904           emitcode ("orl", "a,%s",
1905                     aopGet (oper, offset++, FALSE, FALSE));
1906         }
1907     }
1908 }
1909
1910 /*-----------------------------------------------------------------*/
1911 /* toCarry - make boolean and move into carry                      */
1912 /*-----------------------------------------------------------------*/
1913 static void
1914 toCarry (operand * oper)
1915 {
1916   /* if the operand is a literal then
1917      we know what the value is */
1918   if (AOP_TYPE (oper) == AOP_LIT)
1919     {
1920       if ((int) operandLitValue (oper))
1921         SETC;
1922       else
1923         CLRC;
1924     }
1925   else if (AOP_TYPE (oper) == AOP_CRY)
1926     {
1927       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1928     }
1929   else
1930     {
1931       /* or the operand into a */
1932       toBoolean (oper);
1933       /* set C, if a >= 1 */
1934       emitcode ("add", "a,#0xff");
1935     }
1936 }
1937
1938 /*-----------------------------------------------------------------*/
1939 /* assignBit - assign operand to bit operand                       */
1940 /*-----------------------------------------------------------------*/
1941 static void
1942 assignBit (operand * result, operand * right)
1943 {
1944   /* if the right side is a literal then
1945      we know what the value is */
1946   if (AOP_TYPE (right) == AOP_LIT)
1947     {
1948       if ((int) operandLitValue (right))
1949         aopPut (result, one, 0);
1950       else
1951         aopPut (result, zero, 0);
1952     }
1953   else
1954     {
1955       toCarry (right);
1956       aopPut (result, "c", 0);
1957     }
1958 }
1959
1960
1961 /*-------------------------------------------------------------------*/
1962 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1963 /*-------------------------------------------------------------------*/
1964 static char *
1965 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1966 {
1967   char * l;
1968
1969   if (aopGetUsesAcc (oper, offset))
1970     {
1971       emitcode("mov", "b,a");
1972       MOVA (aopGet (oper, offset, bit16, dname));
1973       emitcode("xch", "a,b");
1974       aopPut (oper, "a", offset);
1975       emitcode("xch", "a,b");
1976       l = "b";
1977     }
1978   else
1979     {
1980       l = aopGet (oper, offset, bit16, dname);
1981       emitcode("xch", "a,%s", l);
1982     }
1983   return l;
1984 }
1985
1986
1987 /*-----------------------------------------------------------------*/
1988 /* genNot - generate code for ! operation                          */
1989 /*-----------------------------------------------------------------*/
1990 static void
1991 genNot (iCode * ic)
1992 {
1993   symbol *tlbl;
1994
1995   D (emitcode (";", "genNot"));
1996
1997   /* assign asmOps to operand & result */
1998   aopOp (IC_LEFT (ic), ic, FALSE);
1999   aopOp (IC_RESULT (ic), ic, TRUE);
2000
2001   /* if in bit space then a special case */
2002   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2003     {
2004       /* if left==result then cpl bit */
2005       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2006         {
2007           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2008         }
2009       else
2010         {
2011           toCarry (IC_LEFT (ic));
2012           emitcode ("cpl", "c");
2013           outBitC (IC_RESULT (ic));
2014         }
2015       goto release;
2016     }
2017
2018   toBoolean (IC_LEFT (ic));
2019
2020   /* set C, if a == 0 */
2021   tlbl = newiTempLabel (NULL);
2022   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2023   emitLabel (tlbl);
2024   outBitC (IC_RESULT (ic));
2025
2026 release:
2027   /* release the aops */
2028   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2029   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2030 }
2031
2032
2033 /*-----------------------------------------------------------------*/
2034 /* genCpl - generate code for complement                           */
2035 /*-----------------------------------------------------------------*/
2036 static void
2037 genCpl (iCode * ic)
2038 {
2039   int offset = 0;
2040   int size;
2041   symbol *tlbl;
2042   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2043
2044   D(emitcode (";", "genCpl"));
2045
2046   /* assign asmOps to operand & result */
2047   aopOp (IC_LEFT (ic), ic, FALSE);
2048   aopOp (IC_RESULT (ic), ic, TRUE);
2049
2050   /* special case if in bit space */
2051   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2052     {
2053       char *l;
2054
2055       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2056           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2057         {
2058           /* promotion rules are responsible for this strange result:
2059              bit -> int -> ~int -> bit
2060              uchar -> int -> ~int -> bit
2061           */
2062           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2063           goto release;
2064         }
2065
2066       tlbl=newiTempLabel(NULL);
2067       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2068       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2069           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2070           IS_AOP_PREG (IC_LEFT (ic)))
2071         {
2072           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2073         }
2074       else
2075         {
2076           MOVA (l);
2077           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2078         }
2079       emitLabel (tlbl);
2080       outBitC (IC_RESULT(ic));
2081       goto release;
2082     }
2083
2084   size = AOP_SIZE (IC_RESULT (ic));
2085   while (size--)
2086     {
2087       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2088       MOVA (l);
2089       emitcode ("cpl", "a");
2090       aopPut (IC_RESULT (ic), "a", offset++);
2091     }
2092
2093
2094 release:
2095   /* release the aops */
2096   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2097   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2098 }
2099
2100 /*-----------------------------------------------------------------*/
2101 /* genUminusFloat - unary minus for floating points                */
2102 /*-----------------------------------------------------------------*/
2103 static void
2104 genUminusFloat (operand * op, operand * result)
2105 {
2106   int size, offset = 0;
2107   char *l;
2108
2109   D (emitcode (";", "genUminusFloat"));
2110
2111   /* for this we just copy and then flip the bit */
2112
2113   size = AOP_SIZE (op) - 1;
2114
2115   while (size--)
2116     {
2117       aopPut (result,
2118               aopGet (op, offset, FALSE, FALSE),
2119               offset);
2120       offset++;
2121     }
2122
2123   l = aopGet (op, offset, FALSE, FALSE);
2124   MOVA (l);
2125
2126   emitcode ("cpl", "acc.7");
2127   aopPut (result, "a", offset);
2128 }
2129
2130 /*-----------------------------------------------------------------*/
2131 /* genUminus - unary minus code generation                         */
2132 /*-----------------------------------------------------------------*/
2133 static void
2134 genUminus (iCode * ic)
2135 {
2136   int offset, size;
2137   sym_link *optype;
2138
2139   D (emitcode (";", "genUminus"));
2140
2141   /* assign asmops */
2142   aopOp (IC_LEFT (ic), ic, FALSE);
2143   aopOp (IC_RESULT (ic), ic, TRUE);
2144
2145   /* if both in bit space then special
2146      case */
2147   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2148       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2149     {
2150
2151       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2152       emitcode ("cpl", "c");
2153       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2154       goto release;
2155     }
2156
2157   optype = operandType (IC_LEFT (ic));
2158
2159   /* if float then do float stuff */
2160   if (IS_FLOAT (optype))
2161     {
2162       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2163       goto release;
2164     }
2165
2166   /* otherwise subtract from zero */
2167   size = AOP_SIZE (IC_LEFT (ic));
2168   offset = 0;
2169   while (size--)
2170     {
2171       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2172       if (!strcmp (l, "a"))
2173         {
2174           if (offset == 0)
2175             SETC;
2176           emitcode ("cpl", "a");
2177           emitcode ("addc", "a,#0");
2178         }
2179       else
2180         {
2181           if (offset == 0)
2182             CLRC;
2183           emitcode ("clr", "a");
2184           emitcode ("subb", "a,%s", l);
2185         }
2186       aopPut (IC_RESULT (ic), "a", offset++);
2187     }
2188
2189   /* if any remaining bytes in the result */
2190   /* we just need to propagate the sign   */
2191   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2192     {
2193       emitcode ("rlc", "a");
2194       emitcode ("subb", "a,acc");
2195       while (size--)
2196         aopPut (IC_RESULT (ic), "a", offset++);
2197     }
2198
2199 release:
2200   /* release the aops */
2201   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2202   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2203 }
2204
2205 /*-----------------------------------------------------------------*/
2206 /* saveRegisters - will look for a call and save the registers     */
2207 /*-----------------------------------------------------------------*/
2208 static void
2209 saveRegisters (iCode * lic)
2210 {
2211   int i;
2212   iCode *ic;
2213   bitVect *rsave;
2214
2215   /* look for call */
2216   for (ic = lic; ic; ic = ic->next)
2217     if (ic->op == CALL || ic->op == PCALL)
2218       break;
2219
2220   if (!ic)
2221     {
2222       fprintf (stderr, "found parameter push with no function call\n");
2223       return;
2224     }
2225
2226   /* if the registers have been saved already or don't need to be then
2227      do nothing */
2228   if (ic->regsSaved)
2229     return;
2230   if (IS_SYMOP(IC_LEFT(ic)) &&
2231       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2232        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2233     return;
2234
2235   /* save the registers in use at this time but skip the
2236      ones for the result */
2237   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2238                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2239
2240   ic->regsSaved = 1;
2241   if (options.useXstack)
2242     {
2243       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2244       int nBits = bitVectnBitsOn (rsavebits);
2245       int count = bitVectnBitsOn (rsave);
2246
2247       if (nBits != 0)
2248         {
2249           count = count - nBits + 1;
2250           /* remove all but the first bits as they are pushed all at once */
2251           rsave = bitVectCplAnd (rsave, rsavebits);
2252           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2253         }
2254       freeBitVect (rsavebits);
2255
2256       if (count == 1)
2257         {
2258           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2259           if (reg->type == REG_BIT)
2260             {
2261               emitcode ("mov", "a,%s", reg->base);
2262             }
2263           else
2264             {
2265               emitcode ("mov", "a,%s", reg->name);
2266             }
2267           emitcode ("mov", "r0,%s", spname);
2268           emitcode ("inc", "%s", spname);// allocate before use
2269           emitcode ("movx", "@r0,a");
2270           if (bitVectBitValue (rsave, R0_IDX))
2271             emitcode ("mov", "r0,a");
2272         }
2273       else if (count != 0)
2274         {
2275           if (bitVectBitValue (rsave, R0_IDX))
2276             {
2277               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2278             }
2279           emitcode ("mov", "r0,%s", spname);
2280           MOVA ("r0");
2281           emitcode ("add", "a,#%d", count);
2282           emitcode ("mov", "%s,a", spname);
2283           for (i = 0; i < mcs51_nRegs; i++)
2284             {
2285               if (bitVectBitValue (rsave, i))
2286                 {
2287                   regs * reg = REG_WITH_INDEX (i);
2288                   if (i == R0_IDX)
2289                     {
2290                       emitcode ("pop", "acc");
2291                       emitcode ("push", "acc");
2292                     }
2293                   else if (reg->type == REG_BIT)
2294                     {
2295                       emitcode ("mov", "a,%s", reg->base);
2296                     }
2297                   else
2298                     {
2299                       emitcode ("mov", "a,%s", reg->name);
2300                     }
2301                   emitcode ("movx", "@r0,a");
2302                   if (--count)
2303                     {
2304                       emitcode ("inc", "r0");
2305                     }
2306                 }
2307             }
2308           if (bitVectBitValue (rsave, R0_IDX))
2309             {
2310               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2311             }
2312         }
2313     }
2314   else
2315     {
2316       bool bits_pushed = FALSE;
2317       for (i = 0; i < mcs51_nRegs; i++)
2318         {
2319           if (bitVectBitValue (rsave, i))
2320             {
2321               bits_pushed = pushReg (i, bits_pushed);
2322             }
2323         }
2324     }
2325   freeBitVect (rsave);
2326 }
2327
2328 /*-----------------------------------------------------------------*/
2329 /* unsaveRegisters - pop the pushed registers                      */
2330 /*-----------------------------------------------------------------*/
2331 static void
2332 unsaveRegisters (iCode * ic)
2333 {
2334   int i;
2335   bitVect *rsave;
2336
2337   /* restore the registers in use at this time but skip the
2338      ones for the result */
2339   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2340                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2341
2342   if (options.useXstack)
2343     {
2344       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2345       int nBits = bitVectnBitsOn (rsavebits);
2346       int count = bitVectnBitsOn (rsave);
2347
2348       if (nBits != 0)
2349         {
2350           count = count - nBits + 1;
2351           /* remove all but the first bits as they are popped all at once */
2352           rsave = bitVectCplAnd (rsave, rsavebits);
2353           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2354         }
2355       freeBitVect (rsavebits);
2356
2357       if (count == 1)
2358         {
2359           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2360           emitcode ("mov", "r0,%s", spname);
2361           emitcode ("dec", "r0");
2362           emitcode ("movx", "a,@r0");
2363           if (reg->type == REG_BIT)
2364             {
2365               emitcode ("mov", "%s,a", reg->base);
2366             }
2367           else
2368             {
2369               emitcode ("mov", "%s,a", reg->name);
2370             }
2371           emitcode ("dec", "%s", spname);
2372         }
2373       else if (count != 0)
2374         {
2375           emitcode ("mov", "r0,%s", spname);
2376           for (i = mcs51_nRegs; i >= 0; i--)
2377             {
2378               if (bitVectBitValue (rsave, i))
2379                 {
2380                   regs * reg = REG_WITH_INDEX (i);
2381                   emitcode ("dec", "r0");
2382                   emitcode ("movx", "a,@r0");
2383                   if (i == R0_IDX)
2384                     {
2385                       emitcode ("push", "acc");
2386                     }
2387                   else if (reg->type == REG_BIT)
2388                     {
2389                       emitcode ("mov", "%s,a", reg->base);
2390                     }
2391                   else
2392                     {
2393                       emitcode ("mov", "%s,a", reg->name);
2394                     }
2395                 }
2396             }
2397           emitcode ("mov", "%s,r0", spname);
2398           if (bitVectBitValue (rsave, R0_IDX))
2399             {
2400               emitcode ("pop", "ar0");
2401             }
2402         }
2403     }
2404   else
2405     {
2406       bool bits_popped = FALSE;
2407       for (i = mcs51_nRegs; i >= 0; i--)
2408         {
2409           if (bitVectBitValue (rsave, i))
2410             {
2411               bits_popped = popReg (i, bits_popped);
2412             }
2413         }
2414     }
2415   freeBitVect (rsave);
2416 }
2417
2418
2419 /*-----------------------------------------------------------------*/
2420 /* pushSide -                                                      */
2421 /*-----------------------------------------------------------------*/
2422 static void
2423 pushSide (operand * oper, int size)
2424 {
2425   int offset = 0;
2426   while (size--)
2427     {
2428       char *l = aopGet (oper, offset++, FALSE, TRUE);
2429       if (AOP_TYPE (oper) != AOP_REG &&
2430           AOP_TYPE (oper) != AOP_DIR &&
2431           strcmp (l, "a"))
2432         {
2433           MOVA (l);
2434           emitcode ("push", "acc");
2435         }
2436       else
2437         {
2438           emitcode ("push", "%s", l);
2439         }
2440     }
2441 }
2442
2443 /*-----------------------------------------------------------------*/
2444 /* assignResultValue - also indicates if acc is in use afterwards  */
2445 /*-----------------------------------------------------------------*/
2446 static bool
2447 assignResultValue (operand * oper, operand * func)
2448 {
2449   int offset = 0;
2450   int size = AOP_SIZE (oper);
2451   bool accuse = FALSE;
2452   bool pushedA = FALSE;
2453
2454   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2455     {
2456       outBitC (oper);
2457       return FALSE;
2458     }
2459
2460   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2461     {
2462       emitcode ("push", "acc");
2463       pushedA = TRUE;
2464     }
2465   while (size--)
2466     {
2467       if ((offset == 3) && pushedA)
2468         emitcode ("pop", "acc");
2469       accuse |= aopPut (oper, fReturn[offset], offset);
2470       offset++;
2471     }
2472   return accuse;
2473 }
2474
2475
2476 /*-----------------------------------------------------------------*/
2477 /* genXpush - pushes onto the external stack                       */
2478 /*-----------------------------------------------------------------*/
2479 static void
2480 genXpush (iCode * ic)
2481 {
2482   asmop *aop = newAsmop (0);
2483   regs *r;
2484   int size, offset = 0;
2485
2486   D (emitcode (";", "genXpush"));
2487
2488   aopOp (IC_LEFT (ic), ic, FALSE);
2489   r = getFreePtr (ic, &aop, FALSE);
2490
2491   size = AOP_SIZE (IC_LEFT (ic));
2492
2493   if (size == 1)
2494     {
2495       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2496       emitcode ("mov", "%s,%s", r->name, spname);
2497       emitcode ("inc", "%s", spname); // allocate space first
2498       emitcode ("movx", "@%s,a", r->name);
2499     }
2500   else
2501     {
2502       // allocate space first
2503       emitcode ("mov", "%s,%s", r->name, spname);
2504       MOVA (r->name);
2505       emitcode ("add", "a,#%d", size);
2506       emitcode ("mov", "%s,a", spname);
2507
2508       while (size--)
2509         {
2510           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2511           emitcode ("movx", "@%s,a", r->name);
2512           emitcode ("inc", "%s", r->name);
2513         }
2514     }
2515
2516   freeAsmop (NULL, aop, ic, TRUE);
2517   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2518 }
2519
2520 /*-----------------------------------------------------------------*/
2521 /* genIpush - generate code for pushing this gets a little complex */
2522 /*-----------------------------------------------------------------*/
2523 static void
2524 genIpush (iCode * ic)
2525 {
2526   int size, offset = 0;
2527   char *l;
2528   char *prev = "";
2529
2530   D (emitcode (";", "genIpush"));
2531
2532   /* if this is not a parm push : ie. it is spill push
2533      and spill push is always done on the local stack */
2534   if (!ic->parmPush)
2535     {
2536
2537       /* and the item is spilt then do nothing */
2538       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2539         return;
2540
2541       aopOp (IC_LEFT (ic), ic, FALSE);
2542       size = AOP_SIZE (IC_LEFT (ic));
2543       /* push it on the stack */
2544       while (size--)
2545         {
2546           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2547           if (*l == '#')
2548             {
2549               MOVA (l);
2550               l = "acc";
2551             }
2552           emitcode ("push", "%s", l);
2553         }
2554       return;
2555     }
2556
2557   /* this is a parameter push: in this case we call
2558      the routine to find the call and save those
2559      registers that need to be saved */
2560   saveRegisters (ic);
2561
2562   /* if use external stack then call the external
2563      stack pushing routine */
2564   if (options.useXstack)
2565     {
2566       genXpush (ic);
2567       return;
2568     }
2569
2570   /* then do the push */
2571   aopOp (IC_LEFT (ic), ic, FALSE);
2572
2573   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2574   size = AOP_SIZE (IC_LEFT (ic));
2575
2576   while (size--)
2577     {
2578       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2579       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2580           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2581         {
2582           if (strcmp (l, prev) || *l == '@')
2583             MOVA (l);
2584           emitcode ("push", "acc");
2585         }
2586       else
2587         {
2588           emitcode ("push", "%s", l);
2589         }
2590       prev = l;
2591     }
2592
2593   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2594 }
2595
2596 /*-----------------------------------------------------------------*/
2597 /* genIpop - recover the registers: can happen only for spilling   */
2598 /*-----------------------------------------------------------------*/
2599 static void
2600 genIpop (iCode * ic)
2601 {
2602   int size, offset;
2603
2604   D (emitcode (";", "genIpop"));
2605
2606   /* if the temp was not pushed then */
2607   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2608     return;
2609
2610   aopOp (IC_LEFT (ic), ic, FALSE);
2611   size = AOP_SIZE (IC_LEFT (ic));
2612   offset = (size - 1);
2613   while (size--)
2614     {
2615       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2616                                      FALSE, TRUE));
2617     }
2618
2619   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2620 }
2621
2622 /*-----------------------------------------------------------------*/
2623 /* saveRBank - saves an entire register bank on the stack          */
2624 /*-----------------------------------------------------------------*/
2625 static void
2626 saveRBank (int bank, iCode * ic, bool pushPsw)
2627 {
2628   int i;
2629   int count = 8 + (pushPsw ? 1 : 0);
2630   asmop *aop = NULL;
2631   regs *r = NULL;
2632
2633   if (options.useXstack)
2634     {
2635       if (!ic)
2636         {
2637           /* Assume r0 is available for use. */
2638           r = REG_WITH_INDEX (R0_IDX);
2639         }
2640       else
2641         {
2642           aop = newAsmop (0);
2643           r = getFreePtr (ic, &aop, FALSE);
2644         }
2645       // allocate space first
2646       emitcode ("mov", "%s,%s", r->name, spname);
2647       MOVA (r->name);
2648       emitcode ("add", "a,#%d", count);
2649       emitcode ("mov", "%s,a", spname);
2650     }
2651
2652   for (i = 0; i < 8; i++)
2653     {
2654       if (options.useXstack)
2655         {
2656           emitcode ("mov", "a,(%s+%d)",
2657                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2658           emitcode ("movx", "@%s,a", r->name);
2659           if (--count)
2660             emitcode ("inc", "%s", r->name);
2661         }
2662       else
2663         emitcode ("push", "(%s+%d)",
2664                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2665     }
2666
2667   if (pushPsw)
2668     {
2669       if (options.useXstack)
2670         {
2671           emitcode ("mov", "a,psw");
2672           emitcode ("movx", "@%s,a", r->name);
2673         }
2674       else
2675         {
2676           emitcode ("push", "psw");
2677         }
2678
2679       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2680     }
2681
2682   if (aop)
2683     {
2684       freeAsmop (NULL, aop, ic, TRUE);
2685     }
2686
2687   if (ic)
2688     {
2689       ic->bankSaved = 1;
2690     }
2691 }
2692
2693 /*-----------------------------------------------------------------*/
2694 /* unsaveRBank - restores the register bank from stack             */
2695 /*-----------------------------------------------------------------*/
2696 static void
2697 unsaveRBank (int bank, iCode * ic, bool popPsw)
2698 {
2699   int i;
2700   asmop *aop = NULL;
2701   regs *r = NULL;
2702
2703   if (options.useXstack)
2704     {
2705       if (!ic)
2706         {
2707           /* Assume r0 is available for use. */
2708           r = REG_WITH_INDEX (R0_IDX);;
2709         }
2710       else
2711         {
2712           aop = newAsmop (0);
2713           r = getFreePtr (ic, &aop, FALSE);
2714         }
2715       emitcode ("mov", "%s,%s", r->name, spname);
2716     }
2717
2718   if (popPsw)
2719     {
2720       if (options.useXstack)
2721         {
2722           emitcode ("dec", "%s", r->name);
2723           emitcode ("movx", "a,@%s", r->name);
2724           emitcode ("mov", "psw,a");
2725         }
2726       else
2727         {
2728           emitcode ("pop", "psw");
2729         }
2730     }
2731
2732   for (i = 7; i >= 0; i--)
2733     {
2734       if (options.useXstack)
2735         {
2736           emitcode ("dec", "%s", r->name);
2737           emitcode ("movx", "a,@%s", r->name);
2738           emitcode ("mov", "(%s+%d),a",
2739                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2740         }
2741       else
2742         {
2743           emitcode ("pop", "(%s+%d)",
2744                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2745         }
2746     }
2747
2748   if (options.useXstack)
2749     {
2750       emitcode ("mov", "%s,%s", spname, r->name);
2751     }
2752
2753   if (aop)
2754     {
2755       freeAsmop (NULL, aop, ic, TRUE);
2756     }
2757 }
2758
2759 /*-----------------------------------------------------------------*/
2760 /* genSend - gen code for SEND                                     */
2761 /*-----------------------------------------------------------------*/
2762 static void genSend(set *sendSet)
2763 {
2764   iCode *sic;
2765   int bit_count = 0;
2766
2767   /* first we do all bit parameters */
2768   for (sic = setFirstItem (sendSet); sic;
2769        sic = setNextItem (sendSet))
2770     {
2771       if (sic->argreg > 12)
2772         {
2773           int bit = sic->argreg-13;
2774
2775           aopOp (IC_LEFT (sic), sic, FALSE);
2776
2777           /* if left is a literal then
2778              we know what the value is */
2779           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2780             {
2781               if (((int) operandLitValue (IC_LEFT (sic))))
2782                   emitcode ("setb", "b[%d]", bit);
2783               else
2784                   emitcode ("clr", "b[%d]", bit);
2785             }
2786           else
2787             {
2788               /* we need to or */
2789               toCarry (IC_LEFT (sic));
2790               emitcode ("mov", "b[%d],c", bit);
2791             }
2792           bit_count++;
2793           BitBankUsed = 1;
2794
2795           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2796         }
2797     }
2798
2799   if (bit_count)
2800     {
2801       saveRegisters (setFirstItem (sendSet));
2802       emitcode ("mov", "bits,b");
2803     }
2804
2805   /* then we do all other parameters */
2806   for (sic = setFirstItem (sendSet); sic;
2807        sic = setNextItem (sendSet))
2808     {
2809       if (sic->argreg <= 12)
2810         {
2811           int size, offset = 0;
2812           aopOp (IC_LEFT (sic), sic, FALSE);
2813           size = AOP_SIZE (IC_LEFT (sic));
2814
2815           if (sic->argreg == 1)
2816             {
2817               while (size--)
2818                 {
2819                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2820                   if (strcmp (l, fReturn[offset]))
2821                     {
2822                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2823                     }
2824                   offset++;
2825                 }
2826             }
2827           else
2828             {
2829               while (size--)
2830                 {
2831                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2832                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2833                   offset++;
2834                 }
2835             }
2836           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2837         }
2838     }
2839 }
2840
2841 /*-----------------------------------------------------------------*/
2842 /* selectRegBank - emit code to select the register bank           */
2843 /*-----------------------------------------------------------------*/
2844 static void
2845 selectRegBank (short bank, bool keepFlags)
2846 {
2847   /* if f.e. result is in carry */
2848   if (keepFlags)
2849     {
2850       emitcode ("anl", "psw,#0xE7");
2851       if (bank)
2852         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2853     }
2854   else
2855     {
2856       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2857     }
2858 }
2859
2860 /*-----------------------------------------------------------------*/
2861 /* genCall - generates a call statement                            */
2862 /*-----------------------------------------------------------------*/
2863 static void
2864 genCall (iCode * ic)
2865 {
2866   sym_link *dtype;
2867   sym_link *etype;
2868 //  bool restoreBank = FALSE;
2869   bool swapBanks = FALSE;
2870   bool accuse = FALSE;
2871   bool accPushed = FALSE;
2872   bool resultInF0 = FALSE;
2873   bool assignResultGenerated = FALSE;
2874
2875   D (emitcode (";", "genCall"));
2876
2877   dtype = operandType (IC_LEFT (ic));
2878   etype = getSpec(dtype);
2879   /* if send set is not empty then assign */
2880   if (_G.sendSet)
2881     {
2882         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2883             genSend(reverseSet(_G.sendSet));
2884         } else {
2885             genSend(_G.sendSet);
2886         }
2887       _G.sendSet = NULL;
2888     }
2889
2890   /* if we are calling a not _naked function that is not using
2891      the same register bank then we need to save the
2892      destination registers on the stack */
2893   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2894       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2895        !IFFUNC_ISISR (dtype))
2896     {
2897       swapBanks = TRUE;
2898     }
2899
2900   /* if caller saves & we have not saved then */
2901   if (!ic->regsSaved)
2902       saveRegisters (ic);
2903
2904   if (swapBanks)
2905     {
2906         emitcode ("mov", "psw,#0x%02x",
2907            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2908     }
2909
2910   /* make the call */
2911   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2912     {
2913       if (IFFUNC_CALLEESAVES(dtype))
2914         {
2915           werror (E_BANKED_WITH_CALLEESAVES);
2916         }
2917       else
2918         {
2919           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2920                      OP_SYMBOL (IC_LEFT (ic))->rname :
2921                      OP_SYMBOL (IC_LEFT (ic))->name);
2922
2923           emitcode ("mov", "r0,#%s", l);
2924           emitcode ("mov", "r1,#(%s >> 8)", l);
2925           emitcode ("mov", "r2,#(%s >> 16)", l);
2926           emitcode ("lcall", "__sdcc_banked_call");
2927         }
2928     }
2929   else
2930     {
2931       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2932                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2933                                 OP_SYMBOL (IC_LEFT (ic))->name));
2934     }
2935
2936   if (swapBanks)
2937     {
2938       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2939     }
2940
2941   /* if we need assign a result value */
2942   if ((IS_ITEMP (IC_RESULT (ic)) &&
2943        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2944        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2945         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2946         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2947       IS_TRUE_SYMOP (IC_RESULT (ic)))
2948     {
2949
2950       _G.accInUse++;
2951       aopOp (IC_RESULT (ic), ic, FALSE);
2952       _G.accInUse--;
2953
2954       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2955       assignResultGenerated = TRUE;
2956
2957       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2958     }
2959
2960   /* adjust the stack for parameters if required */
2961   if (ic->parmBytes)
2962     {
2963       int i;
2964       if (ic->parmBytes > 3)
2965         {
2966           if (accuse)
2967             {
2968               emitcode ("push", "acc");
2969               accPushed = TRUE;
2970             }
2971           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2972               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2973               !assignResultGenerated)
2974             {
2975               emitcode ("mov", "F0,c");
2976               resultInF0 = TRUE;
2977             }
2978
2979           emitcode ("mov", "a,%s", spname);
2980           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2981           emitcode ("mov", "%s,a", spname);
2982
2983           /* unsaveRegisters from xstack needs acc, but */
2984           /* unsaveRegisters from stack needs this popped */
2985           if (accPushed && !options.useXstack)
2986             {
2987               emitcode ("pop", "acc");
2988               accPushed = FALSE;
2989             }
2990         }
2991       else
2992         for (i = 0; i < ic->parmBytes; i++)
2993           emitcode ("dec", "%s", spname);
2994     }
2995
2996   /* if we had saved some registers then unsave them */
2997   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2998     {
2999       if (accuse && !accPushed && options.useXstack)
3000         {
3001           /* xstack needs acc, but doesn't touch normal stack */
3002           emitcode ("push", "acc");
3003           accPushed = TRUE;
3004         }
3005       unsaveRegisters (ic);
3006     }
3007
3008 //  /* if register bank was saved then pop them */
3009 //  if (restoreBank)
3010 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3011
3012   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3013     {
3014       if (resultInF0)
3015           emitcode ("mov", "c,F0");
3016
3017       aopOp (IC_RESULT (ic), ic, FALSE);
3018       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3019       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3020     }
3021
3022   if (accPushed)
3023     emitcode ("pop", "acc");
3024 }
3025
3026 /*-----------------------------------------------------------------*/
3027 /* genPcall - generates a call by pointer statement                */
3028 /*-----------------------------------------------------------------*/
3029 static void
3030 genPcall (iCode * ic)
3031 {
3032   sym_link *dtype;
3033   sym_link *etype;
3034   symbol *rlbl = newiTempLabel (NULL);
3035 //  bool restoreBank=FALSE;
3036   bool swapBanks = FALSE;
3037   bool resultInF0 = FALSE;
3038
3039   D (emitcode (";", "genPcall"));
3040
3041   dtype = operandType (IC_LEFT (ic))->next;
3042   etype = getSpec(dtype);
3043   /* if caller saves & we have not saved then */
3044   if (!ic->regsSaved)
3045     saveRegisters (ic);
3046
3047   /* if we are calling a not _naked function that is not using
3048      the same register bank then we need to save the
3049      destination registers on the stack */
3050   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3051       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3052       !IFFUNC_ISISR (dtype))
3053     {
3054 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3055 //    restoreBank=TRUE;
3056       swapBanks = TRUE;
3057       // need caution message to user here
3058     }
3059
3060   if (IS_LITERAL (etype))
3061     {
3062       /* if send set is not empty then assign */
3063       if (_G.sendSet)
3064         {
3065           genSend(reverseSet(_G.sendSet));
3066           _G.sendSet = NULL;
3067         }
3068
3069       if (swapBanks)
3070         {
3071           emitcode ("mov", "psw,#0x%02x",
3072            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3073         }
3074
3075       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3076         {
3077           if (IFFUNC_CALLEESAVES (dtype))
3078             {
3079               werror (E_BANKED_WITH_CALLEESAVES);
3080             }
3081           else
3082             {
3083               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3084
3085               emitcode ("mov", "r0,#%s", l);
3086               emitcode ("mov", "r1,#(%s >> 8)", l);
3087               emitcode ("mov", "r2,#(%s >> 16)", l);
3088               emitcode ("lcall", "__sdcc_banked_call");
3089             }
3090         }
3091       else
3092         {
3093           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3094         }
3095     }
3096   else
3097     {
3098       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3099         {
3100           if (IFFUNC_CALLEESAVES (dtype))
3101             {
3102               werror (E_BANKED_WITH_CALLEESAVES);
3103             }
3104           else
3105             {
3106               aopOp (IC_LEFT (ic), ic, FALSE);
3107
3108               if (!swapBanks)
3109                 {
3110                   /* what if aopGet needs r0 or r1 ??? */
3111                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3112                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3113                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3114                 }
3115               else
3116                 {
3117                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3118                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3119                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3120                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3121                 }
3122
3123               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3124
3125               /* if send set is not empty then assign */
3126               if (_G.sendSet)
3127                 {
3128                   genSend(reverseSet(_G.sendSet));
3129                   _G.sendSet = NULL;
3130                 }
3131
3132               if (swapBanks)
3133                 {
3134                   emitcode ("mov", "psw,#0x%02x",
3135                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3136                 }
3137
3138               /* make the call */
3139               emitcode ("lcall", "__sdcc_banked_call");
3140             }
3141         }
3142       else if (_G.sendSet)
3143         {
3144           /* push the return address on to the stack */
3145           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3146           emitcode ("push", "acc");
3147           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3148           emitcode ("push", "acc");
3149
3150           /* now push the calling address */
3151           aopOp (IC_LEFT (ic), ic, FALSE);
3152
3153           pushSide (IC_LEFT (ic), FPTRSIZE);
3154
3155           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3156
3157           /* if send set is not empty the assign */
3158           if (_G.sendSet)
3159             {
3160               genSend(reverseSet(_G.sendSet));
3161               _G.sendSet = NULL;
3162             }
3163
3164           if (swapBanks)
3165             {
3166               emitcode ("mov", "psw,#0x%02x",
3167                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3168             }
3169
3170           /* make the call */
3171           emitcode ("ret", "");
3172           emitLabel (rlbl);
3173         }
3174       else /* the send set is empty */
3175         {
3176           char *l;
3177           /* now get the calling address into dptr */
3178           aopOp (IC_LEFT (ic), ic, FALSE);
3179
3180           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3181           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3182             {
3183               emitcode ("mov", "r0,%s", l);
3184               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3185               emitcode ("mov", "dph,%s", l);
3186               emitcode ("mov", "dpl,r0");
3187             }
3188           else
3189             {
3190               emitcode ("mov", "dpl,%s", l);
3191               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3192               emitcode ("mov", "dph,%s", l);
3193             }
3194
3195           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3196
3197           if (swapBanks)
3198             {
3199               emitcode ("mov", "psw,#0x%02x",
3200                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3201             }
3202
3203           /* make the call */
3204           emitcode ("lcall", "__sdcc_call_dptr");
3205         }
3206     }
3207   if (swapBanks)
3208     {
3209       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3210     }
3211
3212   /* if we need assign a result value */
3213   if ((IS_ITEMP (IC_RESULT (ic)) &&
3214        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3215        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3216         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3217       IS_TRUE_SYMOP (IC_RESULT (ic)))
3218     {
3219
3220       _G.accInUse++;
3221       aopOp (IC_RESULT (ic), ic, FALSE);
3222       _G.accInUse--;
3223
3224       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3225
3226       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3227     }
3228
3229   /* adjust the stack for parameters if required */
3230   if (ic->parmBytes)
3231     {
3232       int i;
3233       if (ic->parmBytes > 3)
3234         {
3235           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3236               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3237             {
3238               emitcode ("mov", "F0,c");
3239               resultInF0 = TRUE;
3240             }
3241
3242           emitcode ("mov", "a,%s", spname);
3243           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3244           emitcode ("mov", "%s,a", spname);
3245         }
3246       else
3247         for (i = 0; i < ic->parmBytes; i++)
3248           emitcode ("dec", "%s", spname);
3249     }
3250
3251 //  /* if register bank was saved then unsave them */
3252 //  if (restoreBank)
3253 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3254
3255   /* if we had saved some registers then unsave them */
3256   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3257     unsaveRegisters (ic);
3258
3259   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3260     {
3261       if (resultInF0)
3262           emitcode ("mov", "c,F0");
3263
3264       aopOp (IC_RESULT (ic), ic, FALSE);
3265       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3266       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3267     }
3268 }
3269
3270 /*-----------------------------------------------------------------*/
3271 /* resultRemat - result  is rematerializable                       */
3272 /*-----------------------------------------------------------------*/
3273 static int
3274 resultRemat (iCode * ic)
3275 {
3276   if (SKIP_IC (ic) || ic->op == IFX)
3277     return 0;
3278
3279   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3280     {
3281       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3282       if (sym->remat && !POINTER_SET (ic))
3283         return 1;
3284     }
3285
3286   return 0;
3287 }
3288
3289 /*-----------------------------------------------------------------*/
3290 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3291 /*-----------------------------------------------------------------*/
3292 static int
3293 regsCmp(void *p1, void *p2)
3294 {
3295   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3296 }
3297
3298 static bool
3299 inExcludeList (char *s)
3300 {
3301   const char *p = setFirstItem(options.excludeRegsSet);
3302
3303   if (p == NULL || STRCASECMP(p, "none") == 0)
3304     return FALSE;
3305
3306
3307   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3308 }
3309
3310 /*-----------------------------------------------------------------*/
3311 /* genFunction - generated code for function entry                 */
3312 /*-----------------------------------------------------------------*/
3313 static void
3314 genFunction (iCode * ic)
3315 {
3316   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3317   sym_link *ftype;
3318   bool     switchedPSW = FALSE;
3319   int      calleesaves_saved_register = -1;
3320   int      stackAdjust = sym->stack;
3321   int      accIsFree = sym->recvSize < 4;
3322   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3323   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3324
3325   _G.nRegsSaved = 0;
3326   /* create the function header */
3327   emitcode (";", "-----------------------------------------");
3328   emitcode (";", " function %s", sym->name);
3329   emitcode (";", "-----------------------------------------");
3330
3331   emitcode ("", "%s:", sym->rname);
3332   lineCurr->isLabel = 1;
3333   ftype = operandType (IC_LEFT (ic));
3334   _G.currentFunc = sym;
3335
3336   if (IFFUNC_ISNAKED(ftype))
3337   {
3338       emitcode(";", "naked function: no prologue.");
3339       return;
3340   }
3341
3342   /* here we need to generate the equates for the
3343      register bank if required */
3344   if (FUNC_REGBANK (ftype) != rbank)
3345     {
3346       int i;
3347
3348       rbank = FUNC_REGBANK (ftype);
3349       for (i = 0; i < mcs51_nRegs; i++)
3350         {
3351           if (regs8051[i].type != REG_BIT)
3352             {
3353               if (strcmp (regs8051[i].base, "0") == 0)
3354                 emitcode ("", "%s = 0x%02x",
3355                           regs8051[i].dname,
3356                           8 * rbank + regs8051[i].offset);
3357               else
3358                 emitcode ("", "%s = %s + 0x%02x",
3359                           regs8051[i].dname,
3360                           regs8051[i].base,
3361                           8 * rbank + regs8051[i].offset);
3362             }
3363         }
3364     }
3365
3366   /* if this is an interrupt service routine then
3367      save acc, b, dpl, dph  */
3368   if (IFFUNC_ISISR (sym->type))
3369     {
3370       bitVect *rsavebits;
3371
3372       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3373       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3374         {
3375           emitcode ("push", "bits");
3376           BitBankUsed = 1;
3377         }
3378       freeBitVect (rsavebits);
3379
3380       if (!inExcludeList ("acc"))
3381         emitcode ("push", "acc");
3382       if (!inExcludeList ("b"))
3383         emitcode ("push", "b");
3384       if (!inExcludeList ("dpl"))
3385         emitcode ("push", "dpl");
3386       if (!inExcludeList ("dph"))
3387         emitcode ("push", "dph");
3388       /* if this isr has no bank i.e. is going to
3389          run with bank 0 , then we need to save more
3390          registers :-) */
3391       if (!FUNC_REGBANK (sym->type))
3392         {
3393           int i;
3394
3395           /* if this function does not call any other
3396              function then we can be economical and
3397              save only those registers that are used */
3398           if (!IFFUNC_HASFCALL(sym->type))
3399             {
3400               /* if any registers used */
3401               if (sym->regsUsed)
3402                 {
3403                   /* save the registers used */
3404                   for (i = 0; i < sym->regsUsed->size; i++)
3405                     {
3406                       if (bitVectBitValue (sym->regsUsed, i))
3407                         pushReg (i, TRUE);
3408                     }
3409                 }
3410             }
3411           else
3412             {
3413               /* this function has a function call. We cannot
3414                  determine register usage so we will have to push the
3415                  entire bank */
3416                 saveRBank (0, ic, FALSE);
3417                 if (options.parms_in_bank1) {
3418                     for (i=0; i < 8 ; i++ ) {
3419                         emitcode ("push","%s",rb1regs[i]);
3420                     }
3421                 }
3422             }
3423         }
3424       else
3425         {
3426             /* This ISR uses a non-zero bank.
3427              *
3428              * We assume that the bank is available for our
3429              * exclusive use.
3430              *
3431              * However, if this ISR calls a function which uses some
3432              * other bank, we must save that bank entirely.
3433              */
3434             unsigned long banksToSave = 0;
3435
3436             if (IFFUNC_HASFCALL(sym->type))
3437             {
3438
3439 #define MAX_REGISTER_BANKS 4
3440
3441                 iCode *i;
3442                 int ix;
3443
3444                 for (i = ic; i; i = i->next)
3445                 {
3446                     if (i->op == ENDFUNCTION)
3447                     {
3448                         /* we got to the end OK. */
3449                         break;
3450                     }
3451
3452                     if (i->op == CALL)
3453                     {
3454                         sym_link *dtype;
3455
3456                         dtype = operandType (IC_LEFT(i));
3457                         if (dtype
3458                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3459                         {
3460                              /* Mark this bank for saving. */
3461                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3462                              {
3463                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3464                              }
3465                              else
3466                              {
3467                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3468                              }
3469
3470                              /* And note that we don't need to do it in
3471                               * genCall.
3472                               */
3473                              i->bankSaved = 1;
3474                         }
3475                     }
3476                     if (i->op == PCALL)
3477                     {
3478                         /* This is a mess; we have no idea what
3479                          * register bank the called function might
3480                          * use.
3481                          *
3482                          * The only thing I can think of to do is
3483                          * throw a warning and hope.
3484                          */
3485                         werror(W_FUNCPTR_IN_USING_ISR);
3486                     }
3487                 }
3488
3489                 if (banksToSave && options.useXstack)
3490                 {
3491                     /* Since we aren't passing it an ic,
3492                      * saveRBank will assume r0 is available to abuse.
3493                      *
3494                      * So switch to our (trashable) bank now, so
3495                      * the caller's R0 isn't trashed.
3496                      */
3497                     emitcode ("push", "psw");
3498                     emitcode ("mov", "psw,#0x%02x",
3499                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3500                     switchedPSW = TRUE;
3501                 }
3502
3503                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3504                 {
3505                      if (banksToSave & (1 << ix))
3506                      {
3507                          saveRBank(ix, NULL, FALSE);
3508                      }
3509                 }
3510             }
3511             // TODO: this needs a closer look
3512             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3513         }
3514
3515       /* Set the register bank to the desired value if nothing else */
3516       /* has done so yet. */
3517       if (!switchedPSW)
3518         {
3519           emitcode ("push", "psw");
3520           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3521         }
3522     }
3523   else
3524     {
3525       /* This is a non-ISR function. The caller has already switched register */
3526       /* banks, if necessary, so just handle the callee-saves option. */
3527
3528       /* if callee-save to be used for this function
3529          then save the registers being used in this function */
3530       if (IFFUNC_CALLEESAVES(sym->type))
3531         {
3532           int i;
3533
3534           /* if any registers used */
3535           if (sym->regsUsed)
3536             {
3537               bool bits_pushed = FALSE;
3538               /* save the registers used */
3539               for (i = 0; i < sym->regsUsed->size; i++)
3540                 {
3541                   if (bitVectBitValue (sym->regsUsed, i))
3542                     {
3543                       /* remember one saved register for later usage */
3544                       if (calleesaves_saved_register < 0)
3545                         calleesaves_saved_register = i;
3546                       bits_pushed = pushReg (i, bits_pushed);
3547                       _G.nRegsSaved++;
3548                     }
3549                 }
3550             }
3551         }
3552     }
3553
3554   if (fReentrant)
3555     {
3556       if (options.useXstack)
3557         {
3558           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3559             {
3560               emitcode ("mov", "r0,%s", spname);
3561               emitcode ("inc", "%s", spname);
3562               emitcode ("xch", "a,_bpx");
3563               emitcode ("movx", "@r0,a");
3564               emitcode ("inc", "r0");
3565               emitcode ("mov", "a,r0");
3566               emitcode ("xch", "a,_bpx");
3567             }
3568           if (sym->stack)
3569             {
3570               emitcode ("push", "_bp");     /* save the callers stack  */
3571               emitcode ("mov", "_bp,sp");
3572             }
3573         }
3574       else
3575         {
3576           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3577             {
3578               /* set up the stack */
3579               emitcode ("push", "_bp");     /* save the callers stack  */
3580               emitcode ("mov", "_bp,sp");
3581             }
3582         }
3583     }
3584
3585   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3586   /* before setting up the stack frame completely. */
3587   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3588     {
3589       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3590
3591       if (rsym->isitmp)
3592         {
3593           if (rsym && rsym->regType == REG_CND)
3594             rsym = NULL;
3595           if (rsym && (rsym->accuse || rsym->ruonly))
3596             rsym = NULL;
3597           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3598             rsym = rsym->usl.spillLoc;
3599         }
3600
3601       /* If the RECEIVE operand immediately spills to the first entry on the */
3602       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3603       /* rather than the usual @r0/r1 machinations. */
3604       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3605         {
3606           int ofs;
3607
3608           _G.current_iCode = ric;
3609           D(emitcode (";", "genReceive"));
3610           for (ofs=0; ofs < sym->recvSize; ofs++)
3611             {
3612               if (!strcmp (fReturn[ofs], "a"))
3613                 emitcode ("push", "acc");
3614               else
3615                 emitcode ("push", fReturn[ofs]);
3616             }
3617           stackAdjust -= sym->recvSize;
3618           if (stackAdjust<0)
3619             {
3620               assert (stackAdjust>=0);
3621               stackAdjust = 0;
3622             }
3623           _G.current_iCode = ic;
3624           ric->generated = 1;
3625           accIsFree = 1;
3626         }
3627       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3628       /* to free up the accumulator. */
3629       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3630         {
3631           int ofs;
3632
3633           _G.current_iCode = ric;
3634           D(emitcode (";", "genReceive"));
3635           for (ofs=0; ofs < sym->recvSize; ofs++)
3636             {
3637               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3638             }
3639           _G.current_iCode = ic;
3640           ric->generated = 1;
3641           accIsFree = 1;
3642         }
3643     }
3644
3645   /* adjust the stack for the function */
3646   if (stackAdjust)
3647     {
3648       int i = stackAdjust;
3649       if (i > 256)
3650         werror (W_STACK_OVERFLOW, sym->name);
3651
3652       if (i > 3 && accIsFree)
3653         {
3654           emitcode ("mov", "a,sp");
3655           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3656           emitcode ("mov", "sp,a");
3657         }
3658       else if (i > 5)
3659         {
3660           /* The accumulator is not free, so we will need another register */
3661           /* to clobber. No need to worry about a possible conflict with */
3662           /* the above early RECEIVE optimizations since they would have */
3663           /* freed the accumulator if they were generated. */
3664
3665           if (IFFUNC_CALLEESAVES(sym->type))
3666             {
3667               /* if it's a callee-saves function we need a saved register */
3668               if (calleesaves_saved_register >= 0)
3669                 {
3670                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3671                   emitcode ("mov", "a,sp");
3672                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3673                   emitcode ("mov", "sp,a");
3674                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3675                 }
3676               else
3677                 /* do it the hard way */
3678                 while (i--)
3679                   emitcode ("inc", "sp");
3680             }
3681           else
3682             {
3683               /* not callee-saves, we can clobber r0 */
3684               emitcode ("mov", "r0,a");
3685               emitcode ("mov", "a,sp");
3686               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3687               emitcode ("mov", "sp,a");
3688               emitcode ("mov", "a,r0");
3689             }
3690         }
3691       else
3692         while (i--)
3693           emitcode ("inc", "sp");
3694     }
3695
3696   if (sym->xstack)
3697     {
3698       char i = ((char) sym->xstack & 0xff);
3699
3700       if (i > 3 && accIsFree)
3701         {
3702           emitcode ("mov", "a,_spx");
3703           emitcode ("add", "a,#0x%02x", i & 0xff);
3704           emitcode ("mov", "_spx,a");
3705         }
3706       else if (i > 5)
3707         {
3708           emitcode ("push", "acc");
3709           emitcode ("mov", "a,_spx");
3710           emitcode ("add", "a,#0x%02x", i & 0xff);
3711           emitcode ("mov", "_spx,a");
3712           emitcode ("pop", "acc");
3713         }
3714       else
3715         {
3716           while (i--)
3717             emitcode ("inc", "_spx");
3718         }
3719     }
3720
3721   /* if critical function then turn interrupts off */
3722   if (IFFUNC_ISCRITICAL (ftype))
3723     {
3724       symbol *tlbl = newiTempLabel (NULL);
3725       emitcode ("setb", "c");
3726       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3727       emitcode ("clr", "c");
3728       emitLabel (tlbl);
3729       emitcode ("push", "psw"); /* save old ea via c in psw */
3730     }
3731 }
3732
3733 /*-----------------------------------------------------------------*/
3734 /* genEndFunction - generates epilogue for functions               */
3735 /*-----------------------------------------------------------------*/
3736 static void
3737 genEndFunction (iCode * ic)
3738 {
3739   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3740   lineNode *lnp = lineCurr;
3741   bitVect  *regsUsed;
3742   bitVect  *regsUsedPrologue;
3743   bitVect  *regsUnneeded;
3744   int      idx;
3745
3746   _G.currentFunc = NULL;
3747   if (IFFUNC_ISNAKED(sym->type))
3748   {
3749       emitcode(";", "naked function: no epilogue.");
3750       if (options.debug && currFunc)
3751         debugFile->writeEndFunction (currFunc, ic, 0);
3752       return;
3753   }
3754
3755   if (IFFUNC_ISCRITICAL (sym->type))
3756     {
3757       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3758         {
3759           emitcode ("rlc", "a");   /* save c in a */
3760           emitcode ("pop", "psw"); /* restore ea via c in psw */
3761           emitcode ("mov", "ea,c");
3762           emitcode ("rrc", "a");   /* restore c from a */
3763         }
3764       else
3765         {
3766           emitcode ("pop", "psw"); /* restore ea via c in psw */
3767           emitcode ("mov", "ea,c");
3768         }
3769     }
3770
3771   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3772     {
3773       if (options.useXstack)
3774         {
3775           if (sym->stack)
3776             {
3777               emitcode ("mov", "sp,_bp");
3778               emitcode ("pop", "_bp");
3779             }
3780           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3781             {
3782               emitcode ("xch", "a,_bpx");
3783               emitcode ("mov", "r0,a");
3784               emitcode ("dec", "r0");
3785               emitcode ("movx", "a,@r0");
3786               emitcode ("xch", "a,_bpx");
3787               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3788             }
3789         }
3790       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3791         {
3792           if (sym->stack)
3793             emitcode ("mov", "sp,_bp");
3794           emitcode ("pop", "_bp");
3795         }
3796     }
3797
3798   /* restore the register bank  */
3799   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3800   {
3801     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3802      || !options.useXstack)
3803     {
3804         /* Special case of ISR using non-zero bank with useXstack
3805          * is handled below.
3806          */
3807         emitcode ("pop", "psw");
3808     }
3809   }
3810
3811   if (IFFUNC_ISISR (sym->type))
3812     {
3813       bitVect *rsavebits;
3814
3815       /* now we need to restore the registers */
3816       /* if this isr has no bank i.e. is going to
3817          run with bank 0 , then we need to save more
3818          registers :-) */
3819       if (!FUNC_REGBANK (sym->type))
3820         {
3821           int i;
3822           /* if this function does not call any other
3823              function then we can be economical and
3824              save only those registers that are used */
3825           if (!IFFUNC_HASFCALL(sym->type))
3826             {
3827               /* if any registers used */
3828               if (sym->regsUsed)
3829                 {
3830                   /* save the registers used */
3831                   for (i = sym->regsUsed->size; i >= 0; i--)
3832                     {
3833                       if (bitVectBitValue (sym->regsUsed, i))
3834                         popReg (i, TRUE);
3835                     }
3836                 }
3837             }
3838           else
3839             {
3840               if (options.parms_in_bank1) {
3841                   for (i = 7 ; i >= 0 ; i-- ) {
3842                       emitcode ("pop","%s",rb1regs[i]);
3843                   }
3844               }
3845               /* this function has a function call. We cannot
3846                  determine register usage so we will have to pop the
3847                  entire bank */
3848               unsaveRBank (0, ic, FALSE);
3849             }
3850         }
3851         else
3852         {
3853             /* This ISR uses a non-zero bank.
3854              *
3855              * Restore any register banks saved by genFunction
3856              * in reverse order.
3857              */
3858             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3859             int ix;
3860
3861             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3862             {
3863                 if (savedBanks & (1 << ix))
3864                 {
3865                     unsaveRBank(ix, NULL, FALSE);
3866                 }
3867             }
3868
3869             if (options.useXstack)
3870             {
3871                 /* Restore bank AFTER calling unsaveRBank,
3872                  * since it can trash r0.
3873                  */
3874                 emitcode ("pop", "psw");
3875             }
3876         }
3877
3878       if (!inExcludeList ("dph"))
3879         emitcode ("pop", "dph");
3880       if (!inExcludeList ("dpl"))
3881         emitcode ("pop", "dpl");
3882       if (!inExcludeList ("b"))
3883         emitcode ("pop", "b");
3884       if (!inExcludeList ("acc"))
3885         emitcode ("pop", "acc");
3886
3887       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3888       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3889         emitcode ("pop", "bits");
3890       freeBitVect (rsavebits);
3891
3892       /* if debug then send end of function */
3893       if (options.debug && currFunc)
3894         {
3895           debugFile->writeEndFunction (currFunc, ic, 1);
3896         }
3897
3898       emitcode ("reti", "");
3899     }
3900   else
3901     {
3902       if (IFFUNC_CALLEESAVES(sym->type))
3903         {
3904           int i;
3905
3906           /* if any registers used */
3907           if (sym->regsUsed)
3908             {
3909               /* save the registers used */
3910               for (i = sym->regsUsed->size; i >= 0; i--)
3911                 {
3912                   if (bitVectBitValue (sym->regsUsed, i) ||
3913                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3914                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3915                 }
3916             }
3917           else if (mcs51_ptrRegReq)
3918             {
3919               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3920               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3921             }
3922
3923         }
3924
3925       /* if debug then send end of function */
3926       if (options.debug && currFunc)
3927         {
3928           debugFile->writeEndFunction (currFunc, ic, 1);
3929         }
3930
3931       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3932         {
3933           emitcode ("ljmp", "__sdcc_banked_ret");
3934         }
3935       else
3936         {
3937           emitcode ("ret", "");
3938         }
3939     }
3940
3941   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3942     return;
3943
3944   /* If this was an interrupt handler using bank 0 that called another */
3945   /* function, then all registers must be saved; nothing to optimized. */
3946   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3947       && !FUNC_REGBANK(sym->type))
3948     return;
3949
3950   /* There are no push/pops to optimize if not callee-saves or ISR */
3951   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3952     return;
3953
3954   /* If there were stack parameters, we cannot optimize without also    */
3955   /* fixing all of the stack offsets; this is too dificult to consider. */
3956   if (FUNC_HASSTACKPARM(sym->type))
3957     return;
3958
3959   /* Compute the registers actually used */
3960   regsUsed = newBitVect (mcs51_nRegs);
3961   regsUsedPrologue = newBitVect (mcs51_nRegs);
3962   while (lnp)
3963     {
3964       if (lnp->ic && lnp->ic->op == FUNCTION)
3965         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3966       else
3967         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3968
3969       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3970           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3971         break;
3972       if (!lnp->prev)
3973         break;
3974       lnp = lnp->prev;
3975     }
3976
3977   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3978       && !bitVectBitValue (regsUsed, CND_IDX))
3979     {
3980       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3981       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3982           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3983         bitVectUnSetBit (regsUsed, CND_IDX);
3984     }
3985   else
3986     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3987
3988   /* If this was an interrupt handler that called another function */
3989   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3990   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3991     {
3992       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3993       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3995       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3996       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3997     }
3998
3999   /* Remove the unneeded push/pops */
4000   regsUnneeded = newBitVect (mcs51_nRegs);
4001   while (lnp)
4002     {
4003       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4004         {
4005           if (!strncmp(lnp->line, "push", 4))
4006             {
4007               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4008               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4009                 {
4010                   connectLine (lnp->prev, lnp->next);
4011                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4012                 }
4013             }
4014           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4015             {
4016               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4017               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4018                 {
4019                   connectLine (lnp->prev, lnp->next);
4020                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4021                 }
4022             }
4023         }
4024       lnp = lnp->next;
4025     }
4026
4027   for (idx = 0; idx < regsUnneeded->size; idx++)
4028     if (bitVectBitValue (regsUnneeded, idx))
4029       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4030
4031   freeBitVect (regsUnneeded);
4032   freeBitVect (regsUsed);
4033   freeBitVect (regsUsedPrologue);
4034 }
4035
4036 /*-----------------------------------------------------------------*/
4037 /* genRet - generate code for return statement                     */
4038 /*-----------------------------------------------------------------*/
4039 static void
4040 genRet (iCode * ic)
4041 {
4042   int size, offset = 0, pushed = 0;
4043
4044   D (emitcode (";", "genRet"));
4045
4046   /* if we have no return value then
4047      just generate the "ret" */
4048   if (!IC_LEFT (ic))
4049     goto jumpret;
4050
4051   /* we have something to return then
4052      move the return value into place */
4053   aopOp (IC_LEFT (ic), ic, FALSE);
4054   size = AOP_SIZE (IC_LEFT (ic));
4055
4056   if (IS_BIT(_G.currentFunc->etype))
4057     {
4058       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4059         toCarry (IC_LEFT (ic));
4060     }
4061   else
4062     {
4063       while (size--)
4064         {
4065           char *l;
4066           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4067             {
4068               /* #NOCHANGE */
4069               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4070               emitcode ("push", "%s", l);
4071               pushed++;
4072             }
4073           else
4074             {
4075               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4076               if (strcmp (fReturn[offset], l))
4077                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4078             }
4079         }
4080
4081       while (pushed)
4082         {
4083           pushed--;
4084           if (strcmp (fReturn[pushed], "a"))
4085             emitcode ("pop", fReturn[pushed]);
4086           else
4087             emitcode ("pop", "acc");
4088         }
4089     }
4090   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4091
4092 jumpret:
4093   /* generate a jump to the return label
4094      if the next is not the return statement */
4095   if (!(ic->next && ic->next->op == LABEL &&
4096         IC_LABEL (ic->next) == returnLabel))
4097
4098     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4099
4100 }
4101
4102 /*-----------------------------------------------------------------*/
4103 /* genLabel - generates a label                                    */
4104 /*-----------------------------------------------------------------*/
4105 static void
4106 genLabel (iCode * ic)
4107 {
4108   /* special case never generate */
4109   if (IC_LABEL (ic) == entryLabel)
4110     return;
4111
4112   emitLabel (IC_LABEL (ic));
4113 }
4114
4115 /*-----------------------------------------------------------------*/
4116 /* genGoto - generates a ljmp                                      */
4117 /*-----------------------------------------------------------------*/
4118 static void
4119 genGoto (iCode * ic)
4120 {
4121   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4122 }
4123
4124 /*-----------------------------------------------------------------*/
4125 /* findLabelBackwards: walks back through the iCode chain looking  */
4126 /* for the given label. Returns number of iCode instructions     */
4127 /* between that label and given ic.          */
4128 /* Returns zero if label not found.          */
4129 /*-----------------------------------------------------------------*/
4130 static int
4131 findLabelBackwards (iCode * ic, int key)
4132 {
4133   int count = 0;
4134
4135   while (ic->prev)
4136     {
4137       ic = ic->prev;
4138       count++;
4139
4140       /* If we have any pushes or pops, we cannot predict the distance.
4141          I don't like this at all, this should be dealt with in the
4142          back-end */
4143       if (ic->op == IPUSH || ic->op == IPOP) {
4144         return 0;
4145       }
4146
4147       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4148         {
4149           return count;
4150         }
4151     }
4152
4153   return 0;
4154 }
4155
4156 /*-----------------------------------------------------------------*/
4157 /* genPlusIncr :- does addition with increment if possible         */
4158 /*-----------------------------------------------------------------*/
4159 static bool
4160 genPlusIncr (iCode * ic)
4161 {
4162   unsigned int icount;
4163   unsigned int size = getDataSize (IC_RESULT (ic));
4164
4165   /* will try to generate an increment */
4166   /* if the right side is not a literal
4167      we cannot */
4168   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4169     return FALSE;
4170
4171   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4172
4173   D(emitcode (";","genPlusIncr"));
4174
4175   /* if increment >=16 bits in register or direct space */
4176   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4177         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4178         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4179       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4180       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4181       (size > 1) &&
4182       (icount == 1))
4183     {
4184       symbol *tlbl;
4185       int emitTlbl;
4186       int labelRange;
4187
4188       /* If the next instruction is a goto and the goto target
4189        * is < 10 instructions previous to this, we can generate
4190        * jumps straight to that target.
4191        */
4192       if (ic->next && ic->next->op == GOTO
4193           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4194           && labelRange <= 10)
4195         {
4196           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4197           tlbl = IC_LABEL (ic->next);
4198           emitTlbl = 0;
4199         }
4200       else
4201         {
4202           tlbl = newiTempLabel (NULL);
4203           emitTlbl = 1;
4204         }
4205       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4206       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4207           IS_AOP_PREG (IC_RESULT (ic)))
4208         emitcode ("cjne", "%s,#0x00,%05d$",
4209                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4210                   tlbl->key + 100);
4211       else
4212         {
4213           emitcode ("clr", "a");
4214           emitcode ("cjne", "a,%s,%05d$",
4215                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4216                     tlbl->key + 100);
4217         }
4218
4219       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4220       if (size > 2)
4221         {
4222           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4223               IS_AOP_PREG (IC_RESULT (ic)))
4224             emitcode ("cjne", "%s,#0x00,%05d$",
4225                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4226                       tlbl->key + 100);
4227           else
4228             emitcode ("cjne", "a,%s,%05d$",
4229                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4230                       tlbl->key + 100);
4231
4232           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4233         }
4234       if (size > 3)
4235         {
4236           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4237               IS_AOP_PREG (IC_RESULT (ic)))
4238             emitcode ("cjne", "%s,#0x00,%05d$",
4239                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4240                       tlbl->key + 100);
4241           else
4242             {
4243               emitcode ("cjne", "a,%s,%05d$",
4244                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4245                         tlbl->key + 100);
4246             }
4247           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4248         }
4249
4250       if (emitTlbl)
4251         {
4252           emitLabel (tlbl);
4253         }
4254       return TRUE;
4255     }
4256
4257   /* if result is dptr */
4258   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4259       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4260       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4261       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4262     {
4263       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4264         return FALSE;
4265
4266       if (icount > 9)
4267         return FALSE;
4268
4269       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4270         return FALSE;
4271
4272       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4273       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4274       while (icount--)
4275         emitcode ("inc", "dptr");
4276
4277       return TRUE;
4278     }
4279
4280   /* if the literal value of the right hand side
4281      is greater than 4 then it is not worth it */
4282   if (icount > 4)
4283     return FALSE;
4284
4285   /* if the sizes are greater than 1 then we cannot */
4286   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4287       AOP_SIZE (IC_LEFT (ic)) > 1)
4288     return FALSE;
4289
4290   /* we can if the aops of the left & result match or
4291      if they are in registers and the registers are the
4292      same */
4293   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4294     {
4295       if (icount > 3)
4296         {
4297           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4298           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4299           aopPut (IC_RESULT (ic), "a", 0);
4300         }
4301       else
4302         {
4303           while (icount--)
4304             {
4305               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4306             }
4307         }
4308
4309       return TRUE;
4310     }
4311
4312   if (icount == 1)
4313     {
4314       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4315       emitcode ("inc", "a");
4316       aopPut (IC_RESULT (ic), "a", 0);
4317       return TRUE;
4318     }
4319
4320   return FALSE;
4321 }
4322
4323 /*-----------------------------------------------------------------*/
4324 /* outBitAcc - output a bit in acc                                 */
4325 /*-----------------------------------------------------------------*/
4326 static void
4327 outBitAcc (operand * result)
4328 {
4329   symbol *tlbl = newiTempLabel (NULL);
4330   /* if the result is a bit */
4331   if (AOP_TYPE (result) == AOP_CRY)
4332     {
4333       aopPut (result, "a", 0);
4334     }
4335   else
4336     {
4337       emitcode ("jz", "%05d$", tlbl->key + 100);
4338       emitcode ("mov", "a,%s", one);
4339       emitLabel (tlbl);
4340       outAcc (result);
4341     }
4342 }
4343
4344 /*-----------------------------------------------------------------*/
4345 /* genPlusBits - generates code for addition of two bits           */
4346 /*-----------------------------------------------------------------*/
4347 static void
4348 genPlusBits (iCode * ic)
4349 {
4350   D (emitcode (";", "genPlusBits"));
4351
4352   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4353   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4354     {
4355       symbol *lbl = newiTempLabel (NULL);
4356       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4357       emitcode ("cpl", "c");
4358       emitLabel (lbl);
4359       outBitC (IC_RESULT (ic));
4360     }
4361   else
4362     {
4363       emitcode ("clr", "a");
4364       emitcode ("rlc", "a");
4365       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4366       emitcode ("addc", "a,%s", zero);
4367       outAcc (IC_RESULT (ic));
4368     }
4369 }
4370
4371 #if 0
4372 /* This is the original version of this code.
4373
4374  * This is being kept around for reference,
4375  * because I am not entirely sure I got it right...
4376  */
4377 static void
4378 adjustArithmeticResult (iCode * ic)
4379 {
4380   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4381       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4382       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4383     aopPut (IC_RESULT (ic),
4384             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4385             2);
4386
4387   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4388       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4389       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4390     aopPut (IC_RESULT (ic),
4391             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4392             2);
4393
4394   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4395       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4396       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4397       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4398       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4399     {
4400       char buffer[5];
4401       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4402       aopPut (IC_RESULT (ic), buffer, 2);
4403     }
4404 }
4405 #else
4406 /* This is the pure and virtuous version of this code.
4407  * I'm pretty certain it's right, but not enough to toss the old
4408  * code just yet...
4409  */
4410 static void
4411 adjustArithmeticResult (iCode * ic)
4412 {
4413   if (opIsGptr (IC_RESULT (ic)) &&
4414       opIsGptr (IC_LEFT (ic)) &&
4415       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4416     {
4417       aopPut (IC_RESULT (ic),
4418               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4419               GPTRSIZE - 1);
4420     }
4421
4422   if (opIsGptr (IC_RESULT (ic)) &&
4423       opIsGptr (IC_RIGHT (ic)) &&
4424       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4425     {
4426       aopPut (IC_RESULT (ic),
4427               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4428               GPTRSIZE - 1);
4429     }
4430
4431   if (opIsGptr (IC_RESULT (ic)) &&
4432       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4433       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4434       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4435       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4436     {
4437       char buffer[5];
4438       SNPRINTF (buffer, sizeof(buffer),
4439                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4440       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4441     }
4442 }
4443 #endif
4444
4445 /*-----------------------------------------------------------------*/
4446 /* genPlus - generates code for addition                           */
4447 /*-----------------------------------------------------------------*/
4448 static void
4449 genPlus (iCode * ic)
4450 {
4451   int size, offset = 0;
4452   int skip_bytes = 0;
4453   char *add = "add";
4454   bool swappedLR = FALSE;
4455   operand *leftOp, *rightOp;
4456   operand * op;
4457
4458   D (emitcode (";", "genPlus"));
4459
4460   /* special cases :- */
4461
4462   aopOp (IC_LEFT (ic), ic, FALSE);
4463   aopOp (IC_RIGHT (ic), ic, FALSE);
4464   aopOp (IC_RESULT (ic), ic, TRUE);
4465
4466   /* if literal, literal on the right or
4467      if left requires ACC or right is already
4468      in ACC */
4469   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4470       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4471       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4472     {
4473       operand *t = IC_RIGHT (ic);
4474       IC_RIGHT (ic) = IC_LEFT (ic);
4475       IC_LEFT (ic) = t;
4476       swappedLR = TRUE;
4477     }
4478
4479   /* if both left & right are in bit
4480      space */
4481   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4482       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4483     {
4484       genPlusBits (ic);
4485       goto release;
4486     }
4487
4488   /* if left in bit space & right literal */
4489   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4490       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4491     {
4492       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4493       /* if result in bit space */
4494       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4495         {
4496           if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4497             emitcode ("cpl", "c");
4498           outBitC (IC_RESULT (ic));
4499         }
4500       else
4501         {
4502           size = getDataSize (IC_RESULT (ic));
4503           while (size--)
4504             {
4505               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4506               emitcode ("addc", "a,%s", zero);
4507               aopPut (IC_RESULT (ic), "a", offset++);
4508             }
4509         }
4510       goto release;
4511     }
4512
4513   /* if I can do an increment instead
4514      of add then GOOD for ME */
4515   if (genPlusIncr (ic) == TRUE)
4516     goto release;
4517
4518   size = getDataSize (IC_RESULT (ic));
4519   leftOp = IC_LEFT(ic);
4520   rightOp = IC_RIGHT(ic);
4521   op = IC_LEFT(ic);
4522
4523   /* if this is an add for an array access
4524      at a 256 byte boundary */
4525   if ( 2 == size
4526        && AOP_TYPE (op) == AOP_IMMD
4527        && IS_SYMOP (op)
4528        && IS_SPEC (OP_SYM_ETYPE (op))
4529        && SPEC_ABSA (OP_SYM_ETYPE (op))
4530        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4531      )
4532     {
4533       D(emitcode (";", "genPlus aligned array"));
4534       aopPut (IC_RESULT (ic),
4535               aopGet (rightOp, 0, FALSE, FALSE),
4536               0);
4537
4538       if( 1 == getDataSize (IC_RIGHT (ic)) )
4539         {
4540           aopPut (IC_RESULT (ic),
4541                   aopGet (leftOp, 1, FALSE, FALSE),
4542                   1);
4543         }
4544       else
4545         {
4546           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4547           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4548           aopPut (IC_RESULT (ic), "a", 1);
4549         }
4550       goto release;
4551     }
4552
4553   /* if the lower bytes of a literal are zero skip the addition */
4554   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4555     {
4556        while ((0 == ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4557               (skip_bytes+1 < size))
4558          {
4559            skip_bytes++;
4560          }
4561        if (skip_bytes)
4562          D(emitcode (";", "genPlus shortcut"));
4563     }
4564
4565   while (size--)
4566     {
4567       if( offset >= skip_bytes )
4568         {
4569           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4570             {
4571               bool pushedB;
4572               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4573               pushedB = pushB ();
4574               emitcode("xch", "a,b");
4575               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4576               emitcode (add, "a,b");
4577               popB (pushedB);
4578             }
4579           else if (aopGetUsesAcc (leftOp, offset))
4580             {
4581               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4582               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4583             }
4584           else
4585             {
4586               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4587               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4588             }
4589           aopPut (IC_RESULT (ic), "a", offset);
4590           add = "addc";  /* further adds must propagate carry */
4591         }
4592       else
4593         {
4594           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4595               isOperandVolatile (IC_RESULT (ic), FALSE))
4596             {
4597               /* just move */
4598               aopPut (IC_RESULT (ic),
4599                       aopGet (leftOp, offset, FALSE, FALSE),
4600                       offset);
4601             }
4602         }
4603       offset++;
4604     }
4605
4606   adjustArithmeticResult (ic);
4607
4608 release:
4609   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4610   if (!swappedLR)
4611     {
4612       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4613       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4614     }
4615   else
4616     {
4617       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4618       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4619     }
4620 }
4621
4622 /*-----------------------------------------------------------------*/
4623 /* genMinusDec :- does subtraction with decrement if possible      */
4624 /*-----------------------------------------------------------------*/
4625 static bool
4626 genMinusDec (iCode * ic)
4627 {
4628   unsigned int icount;
4629   unsigned int size = getDataSize (IC_RESULT (ic));
4630
4631   /* will try to generate an increment */
4632   /* if the right side is not a literal
4633      we cannot */
4634   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4635     return FALSE;
4636
4637   /* if the literal value of the right hand side
4638      is greater than 4 then it is not worth it */
4639   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4640     return FALSE;
4641
4642   D (emitcode (";", "genMinusDec"));
4643
4644   /* if decrement >=16 bits in register or direct space */
4645   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4646         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4647         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4648       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4649       (size > 1) &&
4650       (icount == 1))
4651     {
4652       symbol *tlbl;
4653       int emitTlbl;
4654       int labelRange;
4655
4656       /* If the next instruction is a goto and the goto target
4657        * is <= 10 instructions previous to this, we can generate
4658        * jumps straight to that target.
4659        */
4660       if (ic->next && ic->next->op == GOTO
4661           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4662           && labelRange <= 10)
4663         {
4664           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4665           tlbl = IC_LABEL (ic->next);
4666           emitTlbl = 0;
4667         }
4668       else
4669         {
4670           tlbl = newiTempLabel (NULL);
4671           emitTlbl = 1;
4672         }
4673
4674       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4675       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4676           IS_AOP_PREG (IC_RESULT (ic)))
4677         emitcode ("cjne", "%s,#0xff,%05d$"
4678                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4679                   ,tlbl->key + 100);
4680       else
4681         {
4682           emitcode ("mov", "a,#0xff");
4683           emitcode ("cjne", "a,%s,%05d$"
4684                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4685                     ,tlbl->key + 100);
4686         }
4687       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4688       if (size > 2)
4689         {
4690           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4691               IS_AOP_PREG (IC_RESULT (ic)))
4692             emitcode ("cjne", "%s,#0xff,%05d$"
4693                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4694                       ,tlbl->key + 100);
4695           else
4696             {
4697               emitcode ("cjne", "a,%s,%05d$"
4698                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4699                         ,tlbl->key + 100);
4700             }
4701           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4702         }
4703       if (size > 3)
4704         {
4705           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4706               IS_AOP_PREG (IC_RESULT (ic)))
4707             emitcode ("cjne", "%s,#0xff,%05d$"
4708                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4709                       ,tlbl->key + 100);
4710           else
4711             {
4712               emitcode ("cjne", "a,%s,%05d$"
4713                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4714                         ,tlbl->key + 100);
4715             }
4716           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4717         }
4718       if (emitTlbl)
4719         {
4720           emitLabel (tlbl);
4721         }
4722       return TRUE;
4723     }
4724
4725   /* if the sizes are greater than 1 then we cannot */
4726   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4727       AOP_SIZE (IC_LEFT (ic)) > 1)
4728     return FALSE;
4729
4730   /* we can if the aops of the left & result match or
4731      if they are in registers and the registers are the
4732      same */
4733   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4734     {
4735       char *l;
4736
4737       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4738         {
4739           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4740           l = "a";
4741         }
4742       else
4743         {
4744           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4745         }
4746
4747       while (icount--)
4748         {
4749           emitcode ("dec", "%s", l);
4750         }
4751
4752       if (AOP_NEEDSACC (IC_RESULT (ic)))
4753         aopPut (IC_RESULT (ic), "a", 0);
4754
4755       return TRUE;
4756     }
4757
4758   if (icount == 1)
4759     {
4760       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4761       emitcode ("dec", "a");
4762       aopPut (IC_RESULT (ic), "a", 0);
4763       return TRUE;
4764     }
4765
4766   return FALSE;
4767 }
4768
4769 /*-----------------------------------------------------------------*/
4770 /* addSign - complete with sign                                    */
4771 /*-----------------------------------------------------------------*/
4772 static void
4773 addSign (operand * result, int offset, int sign)
4774 {
4775   int size = (getDataSize (result) - offset);
4776   if (size > 0)
4777     {
4778       if (sign)
4779         {
4780           emitcode ("rlc", "a");
4781           emitcode ("subb", "a,acc");
4782           while (size--)
4783             {
4784               aopPut (result, "a", offset++);
4785             }
4786         }
4787       else
4788         {
4789           while (size--)
4790             {
4791               aopPut (result, zero, offset++);
4792             }
4793         }
4794     }
4795 }
4796
4797 /*-----------------------------------------------------------------*/
4798 /* genMinusBits - generates code for subtraction  of two bits      */
4799 /*-----------------------------------------------------------------*/
4800 static void
4801 genMinusBits (iCode * ic)
4802 {
4803   symbol *lbl = newiTempLabel (NULL);
4804
4805   D (emitcode (";", "genMinusBits"));
4806
4807   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4808     {
4809       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4810       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4811       emitcode ("cpl", "c");
4812       emitLabel (lbl);
4813       outBitC (IC_RESULT (ic));
4814     }
4815   else
4816     {
4817       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4818       emitcode ("subb", "a,acc");
4819       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4820       emitcode ("inc", "a");
4821       emitLabel (lbl);
4822       aopPut (IC_RESULT (ic), "a", 0);
4823       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4824     }
4825 }
4826
4827 /*-----------------------------------------------------------------*/
4828 /* genMinus - generates code for subtraction                       */
4829 /*-----------------------------------------------------------------*/
4830 static void
4831 genMinus (iCode * ic)
4832 {
4833   int size, offset = 0;
4834
4835   D (emitcode (";", "genMinus"));
4836
4837   aopOp (IC_LEFT (ic), ic, FALSE);
4838   aopOp (IC_RIGHT (ic), ic, FALSE);
4839   aopOp (IC_RESULT (ic), ic, TRUE);
4840
4841   /* special cases :- */
4842   /* if both left & right are in bit space */
4843   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4844       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4845     {
4846       genMinusBits (ic);
4847       goto release;
4848     }
4849
4850   /* if I can do an decrement instead
4851      of subtract then GOOD for ME */
4852   if (genMinusDec (ic) == TRUE)
4853     goto release;
4854
4855   size = getDataSize (IC_RESULT (ic));
4856
4857   /* if literal, add a,#-lit, else normal subb */
4858   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4859     {
4860       unsigned long lit = 0L;
4861       bool useCarry = FALSE;
4862
4863       lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4864       lit = -(long) lit;
4865
4866       while (size--)
4867         {
4868           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4869             {
4870               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4871               if (!offset && !size && lit== (unsigned long) -1)
4872                 {
4873                   emitcode ("dec", "a");
4874                 }
4875               else if (!useCarry)
4876                 {
4877                   /* first add without previous c */
4878                   emitcode ("add", "a,#0x%02x",
4879                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4880                   useCarry = TRUE;
4881                 }
4882               else
4883                 {
4884                   emitcode ("addc", "a,#0x%02x",
4885                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4886                 }
4887               aopPut (IC_RESULT (ic), "a", offset++);
4888             }
4889           else
4890             {
4891               /* no need to add zeroes */
4892               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4893                 {
4894                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4895                           offset);
4896                 }
4897               offset++;
4898             }
4899         }
4900     }
4901   else
4902     {
4903       operand *leftOp, *rightOp;
4904
4905       leftOp = IC_LEFT(ic);
4906       rightOp = IC_RIGHT(ic);
4907
4908       while (size--)
4909         {
4910           if (aopGetUsesAcc(rightOp, offset)) {
4911             if (aopGetUsesAcc(leftOp, offset)) {
4912               bool pushedB;
4913
4914               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4915               pushedB = pushB ();
4916               emitcode ("mov", "b,a");
4917               if (offset == 0)
4918                 CLRC;
4919               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4920               emitcode ("subb", "a,b");
4921               popB (pushedB);
4922             } else {
4923               /* reverse subtraction with 2's complement */
4924               if (offset == 0)
4925                 emitcode( "setb", "c");
4926               else
4927                 emitcode( "cpl", "c");
4928               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4929               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4930               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4931               emitcode("cpl", "a");
4932               if (size) /* skip if last byte */
4933                 emitcode( "cpl", "c");
4934             }
4935           } else {
4936             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4937             if (offset == 0)
4938               CLRC;
4939             emitcode ("subb", "a,%s",
4940                       aopGet(rightOp, offset, FALSE, TRUE));
4941           }
4942
4943           aopPut (IC_RESULT (ic), "a", offset++);
4944         }
4945     }
4946
4947   adjustArithmeticResult (ic);
4948
4949 release:
4950   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4951   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4952   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4953 }
4954
4955
4956 /*-----------------------------------------------------------------*/
4957 /* genMultbits :- multiplication of bits                           */
4958 /*-----------------------------------------------------------------*/
4959 static void
4960 genMultbits (operand * left,
4961              operand * right,
4962              operand * result)
4963 {
4964   D (emitcode (";", "genMultbits"));
4965
4966   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4967   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4968   outBitC (result);
4969 }
4970
4971 /*-----------------------------------------------------------------*/
4972 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4973 /*-----------------------------------------------------------------*/
4974 static void
4975 genMultOneByte (operand * left,
4976                 operand * right,
4977                 operand * result)
4978 {
4979   symbol *lbl;
4980   int size = AOP_SIZE (result);
4981   bool runtimeSign, compiletimeSign;
4982   bool lUnsigned, rUnsigned, pushedB;
4983
4984   D (emitcode (";", "genMultOneByte"));
4985
4986   if (size < 1 || size > 2)
4987     {
4988       /* this should never happen */
4989       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4990                AOP_SIZE(result), __FILE__, lineno);
4991       exit (1);
4992     }
4993
4994   /* (if two literals: the value is computed before) */
4995   /* if one literal, literal on the right */
4996   if (AOP_TYPE (left) == AOP_LIT)
4997     {
4998       operand *t = right;
4999       right = left;
5000       left = t;
5001       /* emitcode (";", "swapped left and right"); */
5002     }
5003   /* if no literal, unsigned on the right: shorter code */
5004   if (   AOP_TYPE (right) != AOP_LIT
5005       && SPEC_USIGN (getSpec (operandType (left))))
5006     {
5007       operand *t = right;
5008       right = left;
5009       left = t;
5010     }
5011
5012   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5013   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5014
5015   pushedB = pushB ();
5016
5017   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5018                    no need to take care about the signedness! */
5019       || (lUnsigned && rUnsigned))
5020     {
5021       /* just an unsigned 8 * 8 = 8 multiply
5022          or 8u * 8u = 16u */
5023       /* emitcode (";","unsigned"); */
5024       /* TODO: check for accumulator clash between left & right aops? */
5025
5026       if (AOP_TYPE (right) == AOP_LIT)
5027         {
5028           /* moving to accumulator first helps peepholes */
5029           MOVA (aopGet (left, 0, FALSE, FALSE));
5030           MOVB (aopGet (right, 0, FALSE, FALSE));
5031         }
5032       else
5033         {
5034           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5035           MOVA (aopGet (left, 0, FALSE, FALSE));
5036         }
5037
5038       emitcode ("mul", "ab");
5039       aopPut (result, "a", 0);
5040       if (size == 2)
5041         aopPut (result, "b", 1);
5042
5043       popB (pushedB);
5044       return;
5045     }
5046
5047   /* we have to do a signed multiply */
5048   /* emitcode (";", "signed"); */
5049
5050   /* now sign adjust for both left & right */
5051
5052   /* let's see what's needed: */
5053   /* apply negative sign during runtime */
5054   runtimeSign = FALSE;
5055   /* negative sign from literals */
5056   compiletimeSign = FALSE;
5057
5058   if (!lUnsigned)
5059     {
5060       if (AOP_TYPE(left) == AOP_LIT)
5061         {
5062           /* signed literal */
5063           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5064           if (val < 0)
5065             compiletimeSign = TRUE;
5066         }
5067       else
5068         /* signed but not literal */
5069         runtimeSign = TRUE;
5070     }
5071
5072   if (!rUnsigned)
5073     {
5074       if (AOP_TYPE(right) == AOP_LIT)
5075         {
5076           /* signed literal */
5077           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5078           if (val < 0)
5079             compiletimeSign ^= TRUE;
5080         }
5081       else
5082         /* signed but not literal */
5083         runtimeSign = TRUE;
5084     }
5085
5086   /* initialize F0, which stores the runtime sign */
5087   if (runtimeSign)
5088     {
5089       if (compiletimeSign)
5090         emitcode ("setb", "F0"); /* set sign flag */
5091       else
5092         emitcode ("clr", "F0"); /* reset sign flag */
5093     }
5094
5095   /* save the signs of the operands */
5096   if (AOP_TYPE(right) == AOP_LIT)
5097     {
5098       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5099
5100       if (!rUnsigned && val < 0)
5101         emitcode ("mov", "b,#0x%02x", -val);
5102       else
5103         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5104     }
5105   else /* ! literal */
5106     {
5107       if (rUnsigned)  /* emitcode (";", "signed"); */
5108         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5109       else
5110         {
5111           MOVA (aopGet (right, 0, FALSE, FALSE));
5112           lbl = newiTempLabel (NULL);
5113           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5114           emitcode ("cpl", "F0"); /* complement sign flag */
5115           emitcode ("cpl", "a");  /* 2's complement */
5116           emitcode ("inc", "a");
5117           emitLabel (lbl);
5118           emitcode ("mov", "b,a");
5119         }
5120     }
5121
5122   if (AOP_TYPE(left) == AOP_LIT)
5123     {
5124       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5125
5126       if (!lUnsigned && val < 0)
5127         emitcode ("mov", "a,#0x%02x", -val);
5128       else
5129         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5130     }
5131   else /* ! literal */
5132     {
5133       MOVA (aopGet (left, 0, FALSE, FALSE));
5134
5135       if (!lUnsigned)
5136         {
5137           lbl = newiTempLabel (NULL);
5138           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5139           emitcode ("cpl", "F0"); /* complement sign flag */
5140           emitcode ("cpl", "a"); /* 2's complement */
5141           emitcode ("inc", "a");
5142           emitLabel (lbl);
5143         }
5144     }
5145
5146   /* now the multiplication */
5147   emitcode ("mul", "ab");
5148   if (runtimeSign || compiletimeSign)
5149     {
5150       lbl = newiTempLabel (NULL);
5151       if (runtimeSign)
5152         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5153       emitcode ("cpl", "a"); /* lsb 2's complement */
5154       if (size != 2)
5155         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5156       else
5157         {
5158           emitcode ("add", "a,#1"); /* this sets carry flag */
5159           emitcode ("xch", "a,b");
5160           emitcode ("cpl", "a"); /* msb 2's complement */
5161           emitcode ("addc", "a,#0");
5162           emitcode ("xch", "a,b");
5163         }
5164       emitLabel (lbl);
5165     }
5166   aopPut (result, "a", 0);
5167   if (size == 2)
5168     aopPut (result, "b", 1);
5169
5170   popB (pushedB);
5171 }
5172
5173 /*-----------------------------------------------------------------*/
5174 /* genMult - generates code for multiplication                     */
5175 /*-----------------------------------------------------------------*/
5176 static void
5177 genMult (iCode * ic)
5178 {
5179   operand *left = IC_LEFT (ic);
5180   operand *right = IC_RIGHT (ic);
5181   operand *result = IC_RESULT (ic);
5182
5183   D (emitcode (";", "genMult"));
5184
5185   /* assign the asmops */
5186   aopOp (left, ic, FALSE);
5187   aopOp (right, ic, FALSE);
5188   aopOp (result, ic, TRUE);
5189
5190   /* special cases first */
5191   /* both are bits */
5192   if (AOP_TYPE (left) == AOP_CRY &&
5193       AOP_TYPE (right) == AOP_CRY)
5194     {
5195       genMultbits (left, right, result);
5196       goto release;
5197     }
5198
5199   /* if both are of size == 1 */
5200 #if 0 // one of them can be a sloc shared with the result
5201     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5202 #else
5203   if (getSize(operandType(left)) == 1 &&
5204       getSize(operandType(right)) == 1)
5205 #endif
5206     {
5207       genMultOneByte (left, right, result);
5208       goto release;
5209     }
5210
5211   /* should have been converted to function call */
5212     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5213              getSize(OP_SYMBOL(right)->type));
5214   assert (0);
5215
5216 release:
5217   freeAsmop (result, NULL, ic, TRUE);
5218   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5219   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5220 }
5221
5222 /*-----------------------------------------------------------------*/
5223 /* genDivbits :- division of bits                                  */
5224 /*-----------------------------------------------------------------*/
5225 static void
5226 genDivbits (operand * left,
5227             operand * right,
5228             operand * result)
5229 {
5230   char *l;
5231   bool pushedB;
5232
5233   D(emitcode (";", "genDivbits"));
5234
5235   pushedB = pushB ();
5236
5237   /* the result must be bit */
5238   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5239   l = aopGet (left, 0, FALSE, FALSE);
5240
5241   MOVA (l);
5242
5243   emitcode ("div", "ab");
5244   emitcode ("rrc", "a");
5245
5246   popB (pushedB);
5247
5248   aopPut (result, "c", 0);
5249 }
5250
5251 /*-----------------------------------------------------------------*/
5252 /* genDivOneByte : 8 bit division                                  */
5253 /*-----------------------------------------------------------------*/
5254 static void
5255 genDivOneByte (operand * left,
5256                operand * right,
5257                operand * result)
5258 {
5259   bool lUnsigned, rUnsigned, pushedB;
5260   bool runtimeSign, compiletimeSign;
5261   bool accuse = FALSE;
5262   bool pushedA = FALSE;
5263   symbol *lbl;
5264   int size, offset;
5265
5266   D(emitcode (";", "genDivOneByte"));
5267
5268   /* Why is it necessary that genDivOneByte() can return an int result?
5269      Have a look at:
5270
5271         volatile unsigned char uc;
5272         volatile signed char sc1, sc2;
5273         volatile int i;
5274
5275         uc  = 255;
5276         sc1 = -1;
5277         i = uc / sc1;
5278
5279      Or:
5280
5281         sc1 = -128;
5282         sc2 = -1;
5283         i = sc1 / sc2;
5284
5285      In all cases a one byte result would overflow, the following cast to int
5286      would return the wrong result.
5287
5288      Two possible solution:
5289         a) cast operands to int, if ((unsigned) / (signed)) or
5290            ((signed) / (signed))
5291         b) return an 16 bit signed int; this is what we're doing here!
5292   */
5293
5294   size = AOP_SIZE (result) - 1;
5295   offset = 1;
5296   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5297   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5298
5299   pushedB = pushB ();
5300
5301   /* signed or unsigned */
5302   if (lUnsigned && rUnsigned)
5303     {
5304       /* unsigned is easy */
5305       MOVB (aopGet (right, 0, FALSE, FALSE));
5306       MOVA (aopGet (left, 0, FALSE, FALSE));
5307       emitcode ("div", "ab");
5308       aopPut (result, "a", 0);
5309       while (size--)
5310         aopPut (result, zero, offset++);
5311
5312       popB (pushedB);
5313       return;
5314     }
5315
5316   /* signed is a little bit more difficult */
5317
5318   /* now sign adjust for both left & right */
5319
5320   /* let's see what's needed: */
5321   /* apply negative sign during runtime */
5322   runtimeSign = FALSE;
5323   /* negative sign from literals */
5324   compiletimeSign = FALSE;
5325
5326   if (!lUnsigned)
5327     {
5328       if (AOP_TYPE(left) == AOP_LIT)
5329         {
5330           /* signed literal */
5331           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5332           if (val < 0)
5333             compiletimeSign = TRUE;
5334         }
5335       else
5336         /* signed but not literal */
5337         runtimeSign = TRUE;
5338     }
5339
5340   if (!rUnsigned)
5341     {
5342       if (AOP_TYPE(right) == AOP_LIT)
5343         {
5344           /* signed literal */
5345           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5346           if (val < 0)
5347             compiletimeSign ^= TRUE;
5348         }
5349       else
5350         /* signed but not literal */
5351         runtimeSign = TRUE;
5352     }
5353
5354   /* initialize F0, which stores the runtime sign */
5355   if (runtimeSign)
5356     {
5357       if (compiletimeSign)
5358         emitcode ("setb", "F0"); /* set sign flag */
5359       else
5360         emitcode ("clr", "F0"); /* reset sign flag */
5361     }
5362
5363   /* save the signs of the operands */
5364   if (AOP_TYPE(right) == AOP_LIT)
5365     {
5366       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5367
5368       if (!rUnsigned && val < 0)
5369         emitcode ("mov", "b,#0x%02x", -val);
5370       else
5371         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5372     }
5373   else /* ! literal */
5374     {
5375       if (rUnsigned)
5376         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5377       else
5378         {
5379           MOVA (aopGet (right, 0, FALSE, FALSE));
5380           lbl = newiTempLabel (NULL);
5381           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5382           emitcode ("cpl", "F0"); /* complement sign flag */
5383           emitcode ("cpl", "a");  /* 2's complement */
5384           emitcode ("inc", "a");
5385           emitLabel (lbl);
5386           emitcode ("mov", "b,a");
5387         }
5388     }
5389
5390   if (AOP_TYPE(left) == AOP_LIT)
5391     {
5392       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5393
5394       if (!lUnsigned && val < 0)
5395         emitcode ("mov", "a,#0x%02x", -val);
5396       else
5397         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5398     }
5399   else /* ! literal */
5400     {
5401       MOVA (aopGet (left, 0, FALSE, FALSE));
5402
5403       if (!lUnsigned)
5404         {
5405           lbl = newiTempLabel (NULL);
5406           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5407           emitcode ("cpl", "F0"); /* complement sign flag */
5408           emitcode ("cpl", "a");  /* 2's complement */
5409           emitcode ("inc", "a");
5410           emitLabel (lbl);
5411         }
5412     }
5413
5414   /* now the division */
5415   emitcode ("div", "ab");
5416
5417   if (runtimeSign || compiletimeSign)
5418     {
5419       lbl = newiTempLabel (NULL);
5420       if (runtimeSign)
5421         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5422       emitcode ("cpl", "a"); /* lsb 2's complement */
5423       emitcode ("inc", "a");
5424       emitLabel (lbl);
5425
5426       accuse = aopPut (result, "a", 0);
5427       if (size > 0)
5428         {
5429           /* msb is 0x00 or 0xff depending on the sign */
5430           if (runtimeSign)
5431             {
5432               if (accuse)
5433                 {
5434                   emitcode ("push", "acc");
5435                   pushedA = TRUE;
5436                 }
5437               emitcode ("mov", "c,F0");
5438               emitcode ("subb", "a,acc");
5439               while (size--)
5440                 aopPut (result, "a", offset++);
5441             }
5442           else /* compiletimeSign */
5443             {
5444               if (aopPutUsesAcc (result, "#0xFF", offset))
5445                 {
5446                   emitcode ("push", "acc");
5447                   pushedA = TRUE;
5448                 }
5449               while (size--)
5450                 aopPut (result, "#0xff", offset++);
5451             }
5452         }
5453     }
5454   else
5455     {
5456       aopPut (result, "a", 0);
5457       while (size--)
5458         aopPut (result, zero, offset++);
5459     }
5460
5461   if (pushedA)
5462     emitcode ("pop", "acc");
5463   popB (pushedB);
5464 }
5465
5466 /*-----------------------------------------------------------------*/
5467 /* genDiv - generates code for division                            */
5468 /*-----------------------------------------------------------------*/
5469 static void
5470 genDiv (iCode * ic)
5471 {
5472   operand *left = IC_LEFT (ic);
5473   operand *right = IC_RIGHT (ic);
5474   operand *result = IC_RESULT (ic);
5475
5476   D (emitcode (";", "genDiv"));
5477
5478   /* assign the asmops */
5479   aopOp (left, ic, FALSE);
5480   aopOp (right, ic, FALSE);
5481   aopOp (result, ic, TRUE);
5482
5483   /* special cases first */
5484   /* both are bits */
5485   if (AOP_TYPE (left) == AOP_CRY &&
5486       AOP_TYPE (right) == AOP_CRY)
5487     {
5488       genDivbits (left, right, result);
5489       goto release;
5490     }
5491
5492   /* if both are of size == 1 */
5493   if (AOP_SIZE (left) == 1 &&
5494       AOP_SIZE (right) == 1)
5495     {
5496       genDivOneByte (left, right, result);
5497       goto release;
5498     }
5499
5500   /* should have been converted to function call */
5501   assert (0);
5502 release:
5503   freeAsmop (result, NULL, ic, TRUE);
5504   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5505   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5506 }
5507
5508 /*-----------------------------------------------------------------*/
5509 /* genModbits :- modulus of bits                                   */
5510 /*-----------------------------------------------------------------*/
5511 static void
5512 genModbits (operand * left,
5513             operand * right,
5514             operand * result)
5515 {
5516   char *l;
5517   bool pushedB;
5518
5519   D (emitcode (";", "genModbits"));
5520
5521   pushedB = pushB ();
5522
5523   /* the result must be bit */
5524   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5525   l = aopGet (left, 0, FALSE, FALSE);
5526
5527   MOVA (l);
5528
5529   emitcode ("div", "ab");
5530   emitcode ("mov", "a,b");
5531   emitcode ("rrc", "a");
5532
5533   popB (pushedB);
5534
5535   aopPut (result, "c", 0);
5536 }
5537
5538 /*-----------------------------------------------------------------*/
5539 /* genModOneByte : 8 bit modulus                                   */
5540 /*-----------------------------------------------------------------*/
5541 static void
5542 genModOneByte (operand * left,
5543                operand * right,
5544                operand * result)
5545 {
5546   bool lUnsigned, rUnsigned, pushedB;
5547   bool runtimeSign, compiletimeSign;
5548   symbol *lbl;
5549   int size, offset;
5550
5551   D (emitcode (";", "genModOneByte"));
5552
5553   size = AOP_SIZE (result) - 1;
5554   offset = 1;
5555   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5556   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5557
5558   /* if right is a literal, check it for 2^n */
5559   if (AOP_TYPE(right) == AOP_LIT)
5560     {
5561       unsigned char val = abs((int) operandLitValue(right));
5562       symbol *lbl2 = NULL;
5563
5564       switch (val)
5565         {
5566           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5567           case 2:
5568           case 4:
5569           case 8:
5570           case 16:
5571           case 32:
5572           case 64:
5573           case 128:
5574             if (lUnsigned)
5575               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5576                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5577               /* because iCode should have been changed to genAnd  */
5578               /* see file "SDCCopt.c", function "convertToFcall()" */
5579
5580             MOVA (aopGet (left, 0, FALSE, FALSE));
5581             emitcode ("mov", "c,acc.7");
5582             emitcode ("anl", "a,#0x%02x", val - 1);
5583             lbl = newiTempLabel (NULL);
5584             emitcode ("jz", "%05d$", (lbl->key + 100));
5585             emitcode ("jnc", "%05d$", (lbl->key + 100));
5586             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5587             if (size)
5588               {
5589                 int size2 = size;
5590                 int offs2 = offset;
5591
5592                 aopPut (result, "a", 0);
5593                 while (size2--)
5594                   aopPut (result, "#0xff", offs2++);
5595                 lbl2 = newiTempLabel (NULL);
5596                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5597               }
5598             emitLabel (lbl);
5599             aopPut (result, "a", 0);
5600             while (size--)
5601               aopPut (result, zero, offset++);
5602             if (lbl2)
5603               {
5604                 emitLabel (lbl2);
5605               }
5606             return;
5607
5608           default:
5609             break;
5610         }
5611     }
5612
5613   pushedB = pushB ();
5614
5615   /* signed or unsigned */
5616   if (lUnsigned && rUnsigned)
5617     {
5618       /* unsigned is easy */
5619       MOVB (aopGet (right, 0, FALSE, FALSE));
5620       MOVA (aopGet (left, 0, FALSE, FALSE));
5621       emitcode ("div", "ab");
5622       aopPut (result, "b", 0);
5623       while (size--)
5624         aopPut (result, zero, offset++);
5625
5626       popB (pushedB);
5627       return;
5628     }
5629
5630   /* signed is a little bit more difficult */
5631
5632   /* now sign adjust for both left & right */
5633
5634   /* modulus: sign of the right operand has no influence on the result! */
5635   if (AOP_TYPE(right) == AOP_LIT)
5636     {
5637       signed char val = (char) operandLitValue(right);
5638
5639       if (!rUnsigned && val < 0)
5640         emitcode ("mov", "b,#0x%02x", -val);
5641       else
5642         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5643     }
5644   else /* not literal */
5645     {
5646       if (rUnsigned)
5647         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5648       else
5649         {
5650           MOVA (aopGet (right, 0, FALSE, FALSE));
5651           lbl = newiTempLabel (NULL);
5652           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5653           emitcode ("cpl", "a"); /* 2's complement */
5654           emitcode ("inc", "a");
5655           emitLabel (lbl);
5656           emitcode ("mov", "b,a");
5657         }
5658     }
5659
5660   /* let's see what's needed: */
5661   /* apply negative sign during runtime */
5662   runtimeSign = FALSE;
5663   /* negative sign from literals */
5664   compiletimeSign = FALSE;
5665
5666   /* sign adjust left side */
5667   if (AOP_TYPE(left) == AOP_LIT)
5668     {
5669       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5670
5671       if (!lUnsigned && val < 0)
5672         {
5673           compiletimeSign = TRUE; /* set sign flag */
5674           emitcode ("mov", "a,#0x%02x", -val);
5675         }
5676       else
5677         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5678     }
5679   else /* ! literal */
5680     {
5681       MOVA (aopGet (left, 0, FALSE, FALSE));
5682
5683       if (!lUnsigned)
5684         {
5685           runtimeSign = TRUE;
5686           emitcode ("clr", "F0"); /* clear sign flag */
5687
5688           lbl = newiTempLabel (NULL);
5689           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5690           emitcode ("setb", "F0"); /* set sign flag */
5691           emitcode ("cpl", "a");   /* 2's complement */
5692           emitcode ("inc", "a");
5693           emitLabel (lbl);
5694         }
5695     }
5696
5697   /* now the modulus */
5698   emitcode ("div", "ab");
5699
5700   if (runtimeSign || compiletimeSign)
5701     {
5702       emitcode ("mov", "a,b");
5703       lbl = newiTempLabel (NULL);
5704       if (runtimeSign)
5705         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5706       emitcode ("cpl", "a"); /* 2's complement */
5707       emitcode ("inc", "a");
5708       emitLabel (lbl);
5709
5710       aopPut (result, "a", 0);
5711       if (size > 0)
5712         {
5713           /* msb is 0x00 or 0xff depending on the sign */
5714           if (runtimeSign)
5715             {
5716               emitcode ("mov", "c,F0");
5717               emitcode ("subb", "a,acc");
5718               while (size--)
5719                 aopPut (result, "a", offset++);
5720             }
5721           else /* compiletimeSign */
5722             while (size--)
5723               aopPut (result, "#0xff", offset++);
5724         }
5725     }
5726   else
5727     {
5728       aopPut (result, "b", 0);
5729       while (size--)
5730         aopPut (result, zero, offset++);
5731     }
5732
5733   popB (pushedB);
5734 }
5735
5736 /*-----------------------------------------------------------------*/
5737 /* genMod - generates code for division                            */
5738 /*-----------------------------------------------------------------*/
5739 static void
5740 genMod (iCode * ic)
5741 {
5742   operand *left = IC_LEFT (ic);
5743   operand *right = IC_RIGHT (ic);
5744   operand *result = IC_RESULT (ic);
5745
5746   D (emitcode (";", "genMod"));
5747
5748   /* assign the asmops */
5749   aopOp (left, ic, FALSE);
5750   aopOp (right, ic, FALSE);
5751   aopOp (result, ic, TRUE);
5752
5753   /* special cases first */
5754   /* both are bits */
5755   if (AOP_TYPE (left) == AOP_CRY &&
5756       AOP_TYPE (right) == AOP_CRY)
5757     {
5758       genModbits (left, right, result);
5759       goto release;
5760     }
5761
5762   /* if both are of size == 1 */
5763   if (AOP_SIZE (left) == 1 &&
5764       AOP_SIZE (right) == 1)
5765     {
5766       genModOneByte (left, right, result);
5767       goto release;
5768     }
5769
5770   /* should have been converted to function call */
5771   assert (0);
5772
5773 release:
5774   freeAsmop (result, NULL, ic, TRUE);
5775   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5776   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5777 }
5778
5779 /*-----------------------------------------------------------------*/
5780 /* genIfxJump :- will create a jump depending on the ifx           */
5781 /*-----------------------------------------------------------------*/
5782 static void
5783 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5784 {
5785   symbol *jlbl;
5786   symbol *tlbl = newiTempLabel (NULL);
5787   char *inst;
5788
5789   D (emitcode (";", "genIfxJump"));
5790
5791   /* if true label then we jump if condition
5792      supplied is true */
5793   if (IC_TRUE (ic))
5794     {
5795       jlbl = IC_TRUE (ic);
5796       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5797                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5798     }
5799   else
5800     {
5801       /* false label is present */
5802       jlbl = IC_FALSE (ic);
5803       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5804                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5805     }
5806   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5807     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5808   else
5809     emitcode (inst, "%05d$", tlbl->key + 100);
5810   freeForBranchAsmop (result);
5811   freeForBranchAsmop (right);
5812   freeForBranchAsmop (left);
5813   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5814   emitLabel (tlbl);
5815
5816   /* mark the icode as generated */
5817   ic->generated = 1;
5818 }
5819
5820 /*-----------------------------------------------------------------*/
5821 /* genCmp :- greater or less than comparison                       */
5822 /*-----------------------------------------------------------------*/
5823 static void
5824 genCmp (operand * left, operand * right,
5825         operand * result, iCode * ifx, int sign, iCode *ic)
5826 {
5827   int size, offset = 0;
5828   unsigned long lit = 0L;
5829   bool rightInB;
5830
5831   D (emitcode (";", "genCmp"));
5832
5833   /* if left & right are bit variables */
5834   if (AOP_TYPE (left) == AOP_CRY &&
5835       AOP_TYPE (right) == AOP_CRY)
5836     {
5837       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5838       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5839     }
5840   else
5841     {
5842       /* subtract right from left if at the
5843          end the carry flag is set then we know that
5844          left is greater than right */
5845       size = max (AOP_SIZE (left), AOP_SIZE (right));
5846
5847       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5848       if ((size == 1) && !sign &&
5849           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5850         {
5851           symbol *lbl = newiTempLabel (NULL);
5852           emitcode ("cjne", "%s,%s,%05d$",
5853                     aopGet (left, offset, FALSE, FALSE),
5854                     aopGet (right, offset, FALSE, FALSE),
5855                     lbl->key + 100);
5856           emitLabel (lbl);
5857         }
5858       else
5859         {
5860           if (AOP_TYPE (right) == AOP_LIT)
5861             {
5862               lit = ulFromVal (AOP (right)->aopu.aop_lit);
5863               /* optimize if(x < 0) or if(x >= 0) */
5864               if (lit == 0L)
5865                 {
5866                   if (!sign)
5867                     {
5868                       CLRC;
5869                     }
5870                   else
5871                     {
5872                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5873                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5874                         {
5875                           genIfxJump (ifx, "acc.7", left, right, result);
5876                           freeAsmop (right, NULL, ic, TRUE);
5877                           freeAsmop (left, NULL, ic, TRUE);
5878
5879                           return;
5880                         }
5881                       else
5882                         {
5883                           emitcode ("rlc", "a");
5884                         }
5885                     }
5886                   goto release;
5887                 }
5888               else
5889                 {//nonzero literal
5890                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5891                   while (size && (bytelit == 0))
5892                     {
5893                       offset++;
5894                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5895                       size--;
5896                     }
5897                   CLRC;
5898                   while (size--)
5899                     {
5900                       MOVA (aopGet (left, offset, FALSE, FALSE));
5901                       if (sign && size == 0)
5902                         {
5903                           emitcode ("xrl", "a,#0x80");
5904                           emitcode ("subb", "a,#0x%02x",
5905                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5906                         }
5907                       else
5908                         {
5909                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5910                         }
5911                       offset++;
5912                     }
5913                   goto release;
5914                 }
5915             }
5916           CLRC;
5917           while (size--)
5918             {
5919               bool pushedB = FALSE;
5920               rightInB = aopGetUsesAcc(right, offset);
5921               if (rightInB)
5922                 {
5923                   pushedB = pushB ();
5924                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5925                 }
5926               MOVA (aopGet (left, offset, FALSE, FALSE));
5927               if (sign && size == 0)
5928                 {
5929                   emitcode ("xrl", "a,#0x80");
5930                   if (!rightInB)
5931                     {
5932                       pushedB = pushB ();
5933                       rightInB++;
5934                       MOVB (aopGet (right, offset, FALSE, FALSE));
5935                     }
5936                   emitcode ("xrl", "b,#0x80");
5937                   emitcode ("subb", "a,b");
5938                 }
5939               else
5940                 {
5941                   if (rightInB)
5942                     emitcode ("subb", "a,b");
5943                   else
5944                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5945                 }
5946               if (rightInB)
5947                 popB (pushedB);
5948               offset++;
5949             }
5950         }
5951     }
5952
5953 release:
5954   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5955   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5956   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5957     {
5958       outBitC (result);
5959     }
5960   else
5961     {
5962       /* if the result is used in the next
5963          ifx conditional branch then generate
5964          code a little differently */
5965       if (ifx)
5966         {
5967           genIfxJump (ifx, "c", NULL, NULL, result);
5968         }
5969       else
5970         {
5971           outBitC (result);
5972         }
5973       /* leave the result in acc */
5974     }
5975 }
5976
5977 /*-----------------------------------------------------------------*/
5978 /* genCmpGt :- greater than comparison                             */
5979 /*-----------------------------------------------------------------*/
5980 static void
5981 genCmpGt (iCode * ic, iCode * ifx)
5982 {
5983   operand *left, *right, *result;
5984   sym_link *letype, *retype;
5985   int sign;
5986
5987   D (emitcode (";", "genCmpGt"));
5988
5989   left = IC_LEFT (ic);
5990   right = IC_RIGHT (ic);
5991   result = IC_RESULT (ic);
5992
5993   letype = getSpec (operandType (left));
5994   retype = getSpec (operandType (right));
5995   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5996            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5997   /* assign the asmops */
5998   aopOp (result, ic, TRUE);
5999   aopOp (left, ic, FALSE);
6000   aopOp (right, ic, FALSE);
6001
6002   genCmp (right, left, result, ifx, sign, ic);
6003
6004   freeAsmop (result, NULL, ic, TRUE);
6005 }
6006
6007 /*-----------------------------------------------------------------*/
6008 /* genCmpLt - less than comparisons                                */
6009 /*-----------------------------------------------------------------*/
6010 static void
6011 genCmpLt (iCode * ic, iCode * ifx)
6012 {
6013   operand *left, *right, *result;
6014   sym_link *letype, *retype;
6015   int sign;
6016
6017   D (emitcode (";", "genCmpLt"));
6018
6019   left = IC_LEFT (ic);
6020   right = IC_RIGHT (ic);
6021   result = IC_RESULT (ic);
6022
6023   letype = getSpec (operandType (left));
6024   retype = getSpec (operandType (right));
6025   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6026            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6027   /* assign the asmops */
6028   aopOp (result, ic, TRUE);
6029   aopOp (left, ic, FALSE);
6030   aopOp (right, ic, FALSE);
6031
6032   genCmp (left, right, result, ifx, sign, ic);
6033
6034   freeAsmop (result, NULL, ic, TRUE);
6035 }
6036
6037 /*-----------------------------------------------------------------*/
6038 /* gencjneshort - compare and jump if not equal                    */
6039 /*-----------------------------------------------------------------*/
6040 static void
6041 gencjneshort (operand * left, operand * right, symbol * lbl)
6042 {
6043   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6044   int offset = 0;
6045   unsigned long lit = 0L;
6046
6047   D (emitcode (";", "gencjneshort"));
6048
6049   /* if the left side is a literal or
6050      if the right is in a pointer register and left
6051      is not */
6052   if ((AOP_TYPE (left) == AOP_LIT)  ||
6053       (AOP_TYPE (left) == AOP_IMMD) ||
6054       (AOP_TYPE (left) == AOP_DIR)  ||
6055       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6056     {
6057       operand *t = right;
6058       right = left;
6059       left = t;
6060     }
6061
6062   if (AOP_TYPE (right) == AOP_LIT)
6063     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6064
6065   /* if the right side is a literal then anything goes */
6066   if (AOP_TYPE (right) == AOP_LIT &&
6067       AOP_TYPE (left) != AOP_DIR  &&
6068       AOP_TYPE (left) != AOP_IMMD)
6069     {
6070       while (size--)
6071         {
6072           emitcode ("cjne", "%s,%s,%05d$",
6073                     aopGet (left, offset, FALSE, FALSE),
6074                     aopGet (right, offset, FALSE, FALSE),
6075                     lbl->key + 100);
6076           offset++;
6077         }
6078     }
6079
6080   /* if the right side is in a register or in direct space or
6081      if the left is a pointer register & right is not */
6082   else if (AOP_TYPE (right) == AOP_REG ||
6083            AOP_TYPE (right) == AOP_DIR ||
6084            AOP_TYPE (right) == AOP_LIT ||
6085            AOP_TYPE (right) == AOP_IMMD ||
6086            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6087            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6088     {
6089       while (size--)
6090         {
6091           MOVA (aopGet (left, offset, FALSE, FALSE));
6092           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6093               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6094             emitcode ("jnz", "%05d$", lbl->key + 100);
6095           else
6096             emitcode ("cjne", "a,%s,%05d$",
6097                       aopGet (right, offset, FALSE, TRUE),
6098                       lbl->key + 100);
6099           offset++;
6100         }
6101     }
6102   else
6103     {
6104       /* right is a pointer reg need both a & b */
6105       while (size--)
6106         {
6107           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6108           wassertl(!BINUSE, "B was in use");
6109           MOVB (aopGet (left, offset, FALSE, FALSE));
6110           MOVA (aopGet (right, offset, FALSE, FALSE));
6111           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6112           offset++;
6113         }
6114     }
6115 }
6116
6117 /*-----------------------------------------------------------------*/
6118 /* gencjne - compare and jump if not equal                         */
6119 /*-----------------------------------------------------------------*/
6120 static void
6121 gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
6122 {
6123   symbol *tlbl = newiTempLabel (NULL);
6124
6125   D (emitcode (";", "gencjne"));
6126
6127   gencjneshort (left, right, lbl);
6128
6129   if (useCarry)
6130       SETC;
6131   else
6132       MOVA (one);
6133   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6134   emitLabel (lbl);
6135   if (useCarry)
6136       CLRC;
6137   else
6138       MOVA (zero);
6139   emitLabel (tlbl);
6140 }
6141
6142 /*-----------------------------------------------------------------*/
6143 /* genCmpEq - generates code for equal to                          */
6144 /*-----------------------------------------------------------------*/
6145 static void
6146 genCmpEq (iCode * ic, iCode * ifx)
6147 {
6148   bool swappedLR = FALSE;
6149   operand *left, *right, *result;
6150
6151   D (emitcode (";", "genCmpEq"));
6152
6153   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6154   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6155   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6156
6157   /* if literal, literal on the right or
6158      if the right is in a pointer register and left
6159      is not */
6160   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6161       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6162     {
6163       operand *t = IC_RIGHT (ic);
6164       IC_RIGHT (ic) = IC_LEFT (ic);
6165       IC_LEFT (ic) = t;
6166       swappedLR = TRUE;
6167     }
6168
6169   if (ifx && !AOP_SIZE (result))
6170     {
6171       symbol *tlbl;
6172       /* if they are both bit variables */
6173       if (AOP_TYPE (left) == AOP_CRY &&
6174           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6175         {
6176           if (AOP_TYPE (right) == AOP_LIT)
6177             {
6178               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6179               if (lit == 0L)
6180                 {
6181                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6182                   emitcode ("cpl", "c");
6183                 }
6184               else if (lit == 1L)
6185                 {
6186                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6187                 }
6188               else
6189                 {
6190                   emitcode ("clr", "c");
6191                 }
6192               /* AOP_TYPE(right) == AOP_CRY */
6193             }
6194           else
6195             {
6196               symbol *lbl = newiTempLabel (NULL);
6197               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6198               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6199               emitcode ("cpl", "c");
6200               emitLabel (lbl);
6201             }
6202           /* if true label then we jump if condition
6203              supplied is true */
6204           tlbl = newiTempLabel (NULL);
6205           if (IC_TRUE (ifx))
6206             {
6207               emitcode ("jnc", "%05d$", tlbl->key + 100);
6208               freeForBranchAsmop (result);
6209               freeForBranchAsmop (right);
6210               freeForBranchAsmop (left);
6211               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6212             }
6213           else
6214             {
6215               emitcode ("jc", "%05d$", tlbl->key + 100);
6216               freeForBranchAsmop (result);
6217               freeForBranchAsmop (right);
6218               freeForBranchAsmop (left);
6219               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6220             }
6221           emitLabel (tlbl);
6222         }
6223       else
6224         {
6225           tlbl = newiTempLabel (NULL);
6226           gencjneshort (left, right, tlbl);
6227           if (IC_TRUE (ifx))
6228             {
6229               freeForBranchAsmop (result);
6230               freeForBranchAsmop (right);
6231               freeForBranchAsmop (left);
6232               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6233               emitLabel (tlbl);
6234             }
6235           else
6236             {
6237               symbol *lbl = newiTempLabel (NULL);
6238               emitcode ("sjmp", "%05d$", lbl->key + 100);
6239               emitLabel (tlbl);
6240               freeForBranchAsmop (result);
6241               freeForBranchAsmop (right);
6242               freeForBranchAsmop (left);
6243               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6244               emitLabel (lbl);
6245             }
6246         }
6247       /* mark the icode as generated */
6248       ifx->generated = 1;
6249       goto release;
6250     }
6251
6252   /* if they are both bit variables */
6253   if (AOP_TYPE (left) == AOP_CRY &&
6254       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6255     {
6256       if (AOP_TYPE (right) == AOP_LIT)
6257         {
6258           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6259           if (lit == 0L)
6260             {
6261               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6262               emitcode ("cpl", "c");
6263             }
6264           else if (lit == 1L)
6265             {
6266               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6267             }
6268           else
6269             {
6270               emitcode ("clr", "c");
6271             }
6272           /* AOP_TYPE(right) == AOP_CRY */
6273         }
6274       else
6275         {
6276           symbol *lbl = newiTempLabel (NULL);
6277           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6278           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6279           emitcode ("cpl", "c");
6280           emitLabel (lbl);
6281         }
6282       /* c = 1 if egal */
6283       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6284         {
6285           outBitC (result);
6286           goto release;
6287         }
6288       if (ifx)
6289         {
6290           genIfxJump (ifx, "c", left, right, result);
6291           goto release;
6292         }
6293       /* if the result is used in an arithmetic operation
6294          then put the result in place */
6295       outBitC (result);
6296     }
6297   else
6298     {
6299       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6300         {
6301           gencjne (left, right, newiTempLabel (NULL), TRUE);
6302           aopPut (result, "c", 0);
6303           goto release;
6304         }
6305       gencjne (left, right, newiTempLabel (NULL), FALSE);
6306       if (ifx)
6307         {
6308           genIfxJump (ifx, "a", left, right, result);
6309           goto release;
6310         }
6311       /* if the result is used in an arithmetic operation
6312          then put the result in place */
6313       if (AOP_TYPE (result) != AOP_CRY)
6314         outAcc (result);
6315       /* leave the result in acc */
6316     }
6317
6318 release:
6319   freeAsmop (result, NULL, ic, TRUE);
6320   if (!swappedLR)
6321     {
6322       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6323       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6324     }
6325   else
6326     {
6327       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6328       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6329     }
6330 }
6331
6332 /*-----------------------------------------------------------------*/
6333 /* ifxForOp - returns the icode containing the ifx for operand     */
6334 /*-----------------------------------------------------------------*/
6335 static iCode *
6336 ifxForOp (operand * op, iCode * ic)
6337 {
6338   /* if true symbol then needs to be assigned */
6339   if (IS_TRUE_SYMOP (op))
6340     return NULL;
6341
6342   /* if this has register type condition and
6343      the next instruction is ifx with the same operand
6344      and live to of the operand is upto the ifx only then */
6345   if (ic->next &&
6346       ic->next->op == IFX &&
6347       IC_COND (ic->next)->key == op->key &&
6348       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6349     return ic->next;
6350
6351   return NULL;
6352 }
6353
6354 /*-----------------------------------------------------------------*/
6355 /* hasInc - operand is incremented before any other use            */
6356 /*-----------------------------------------------------------------*/
6357 static iCode *
6358 hasInc (operand *op, iCode *ic, int osize)
6359 {
6360   sym_link *type = operandType(op);
6361   sym_link *retype = getSpec (type);
6362   iCode *lic = ic->next;
6363   int isize ;
6364
6365   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6366   if (!IS_SYMOP(op)) return NULL;
6367
6368   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6369   if (IS_AGGREGATE(type->next)) return NULL;
6370   if (osize != (isize = getSize(type->next))) return NULL;
6371
6372   while (lic) {
6373     /* if operand of the form op = op + <sizeof *op> */
6374     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6375         isOperandEqual(IC_RESULT(lic),op) &&
6376         isOperandLiteral(IC_RIGHT(lic)) &&
6377         operandLitValue(IC_RIGHT(lic)) == isize) {
6378       return lic;
6379     }
6380     /* if the operand used or deffed */
6381     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6382       return NULL;
6383     }
6384     /* if GOTO or IFX */
6385     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6386     lic = lic->next;
6387   }
6388   return NULL;
6389 }
6390
6391 /*-----------------------------------------------------------------*/
6392 /* genAndOp - for && operation                                     */
6393 /*-----------------------------------------------------------------*/
6394 static void
6395 genAndOp (iCode * ic)
6396 {
6397   operand *left, *right, *result;
6398   symbol *tlbl;
6399
6400   D (emitcode (";", "genAndOp"));
6401
6402   /* note here that && operations that are in an
6403      if statement are taken away by backPatchLabels
6404      only those used in arthmetic operations remain */
6405   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6406   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6407   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6408
6409   /* if both are bit variables */
6410   if (AOP_TYPE (left) == AOP_CRY &&
6411       AOP_TYPE (right) == AOP_CRY)
6412     {
6413       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6414       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6415       outBitC (result);
6416     }
6417   else
6418     {
6419       tlbl = newiTempLabel (NULL);
6420       toBoolean (left);
6421       emitcode ("jz", "%05d$", tlbl->key + 100);
6422       toBoolean (right);
6423       emitLabel (tlbl);
6424       outBitAcc (result);
6425     }
6426
6427   freeAsmop (result, NULL, ic, TRUE);
6428   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6429   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6430 }
6431
6432
6433 /*-----------------------------------------------------------------*/
6434 /* genOrOp - for || operation                                      */
6435 /*-----------------------------------------------------------------*/
6436 static void
6437 genOrOp (iCode * ic)
6438 {
6439   operand *left, *right, *result;
6440   symbol *tlbl;
6441
6442   D (emitcode (";", "genOrOp"));
6443
6444   /* note here that || operations that are in an
6445      if statement are taken away by backPatchLabels
6446      only those used in arthmetic operations remain */
6447   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6448   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6449   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6450
6451   /* if both are bit variables */
6452   if (AOP_TYPE (left) == AOP_CRY &&
6453       AOP_TYPE (right) == AOP_CRY)
6454     {
6455       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6456       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6457       outBitC (result);
6458     }
6459   else
6460     {
6461       tlbl = newiTempLabel (NULL);
6462       toBoolean (left);
6463       emitcode ("jnz", "%05d$", tlbl->key + 100);
6464       toBoolean (right);
6465       emitLabel (tlbl);
6466       outBitAcc (result);
6467     }
6468
6469   freeAsmop (result, NULL, ic, TRUE);
6470   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6471   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6472 }
6473
6474 /*-----------------------------------------------------------------*/
6475 /* isLiteralBit - test if lit == 2^n                               */
6476 /*-----------------------------------------------------------------*/
6477 static int
6478 isLiteralBit (unsigned long lit)
6479 {
6480   unsigned long pw[32] =
6481   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6482    0x100L, 0x200L, 0x400L, 0x800L,
6483    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6484    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6485    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6486    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6487    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6488   int idx;
6489
6490   for (idx = 0; idx < 32; idx++)
6491     if (lit == pw[idx])
6492       return idx + 1;
6493   return 0;
6494 }
6495
6496 /*-----------------------------------------------------------------*/
6497 /* continueIfTrue -                                                */
6498 /*-----------------------------------------------------------------*/
6499 static void
6500 continueIfTrue (iCode * ic)
6501 {
6502   if (IC_TRUE (ic))
6503     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6504   ic->generated = 1;
6505 }
6506
6507 /*-----------------------------------------------------------------*/
6508 /* jmpIfTrue -                                                     */
6509 /*-----------------------------------------------------------------*/
6510 static void
6511 jumpIfTrue (iCode * ic)
6512 {
6513   if (!IC_TRUE (ic))
6514     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6515   ic->generated = 1;
6516 }
6517
6518 /*-----------------------------------------------------------------*/
6519 /* jmpTrueOrFalse -                                                */
6520 /*-----------------------------------------------------------------*/
6521 static void
6522 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6523 {
6524   // ugly but optimized by peephole
6525   if (IC_TRUE (ic))
6526     {
6527       symbol *nlbl = newiTempLabel (NULL);
6528       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6529       emitLabel (tlbl);
6530       freeForBranchAsmop (result);
6531       freeForBranchAsmop (right);
6532       freeForBranchAsmop (left);
6533       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6534       emitLabel (nlbl);
6535     }
6536   else
6537     {
6538       freeForBranchAsmop (result);
6539       freeForBranchAsmop (right);
6540       freeForBranchAsmop (left);
6541       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6542       emitLabel (tlbl);
6543     }
6544   ic->generated = 1;
6545 }
6546
6547 /*-----------------------------------------------------------------*/
6548 /* genAnd  - code for and                                          */
6549 /*-----------------------------------------------------------------*/
6550 static void
6551 genAnd (iCode * ic, iCode * ifx)
6552 {
6553   operand *left, *right, *result;
6554   int size, offset = 0;
6555   unsigned long lit = 0L;
6556   int bytelit = 0;
6557   char buffer[10];
6558
6559   D (emitcode (";", "genAnd"));
6560
6561   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6562   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6563   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6564
6565 #ifdef DEBUG_TYPE
6566   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6567             AOP_TYPE (result),
6568             AOP_TYPE (left), AOP_TYPE (right));
6569   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6570             AOP_SIZE (result),
6571             AOP_SIZE (left), AOP_SIZE (right));
6572 #endif
6573
6574   /* if left is a literal & right is not then exchange them */
6575   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6576       AOP_NEEDSACC (left))
6577     {
6578       operand *tmp = right;
6579       right = left;
6580       left = tmp;
6581     }
6582
6583   /* if result = right then exchange left and right */
6584   if (sameRegs (AOP (result), AOP (right)))
6585     {
6586       operand *tmp = right;
6587       right = left;
6588       left = tmp;
6589     }
6590
6591   /* if right is bit then exchange them */
6592   if (AOP_TYPE (right) == AOP_CRY &&
6593       AOP_TYPE (left) != AOP_CRY)
6594     {
6595       operand *tmp = right;
6596       right = left;
6597       left = tmp;
6598     }
6599   if (AOP_TYPE (right) == AOP_LIT)
6600     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6601
6602   size = AOP_SIZE (result);
6603
6604   // if(bit & yy)
6605   // result = bit & yy;
6606   if (AOP_TYPE (left) == AOP_CRY)
6607     {
6608       // c = bit & literal;
6609       if (AOP_TYPE (right) == AOP_LIT)
6610         {
6611           if (lit & 1)
6612             {
6613               if (size && sameRegs (AOP (result), AOP (left)))
6614                 // no change
6615                 goto release;
6616               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6617             }
6618           else
6619             {
6620               // bit(result) = 0;
6621               if (size && (AOP_TYPE (result) == AOP_CRY))
6622                 {
6623                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6624                   goto release;
6625                 }
6626               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6627                 {
6628                   jumpIfTrue (ifx);
6629                   goto release;
6630                 }
6631               emitcode ("clr", "c");
6632             }
6633         }
6634       else
6635         {
6636           if (AOP_TYPE (right) == AOP_CRY)
6637             {
6638               // c = bit & bit;
6639               if (IS_OP_ACCUSE (left))
6640                 {
6641                   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6642                 }
6643               else
6644                 {
6645                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6646                   emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6647                 }
6648             }
6649           else
6650             {
6651               // c = bit & val;
6652               MOVA (aopGet (right, 0, FALSE, FALSE));
6653               // c = lsb
6654               emitcode ("rrc", "a");
6655               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6656             }
6657         }
6658       // bit = c
6659       // val = c
6660       if (size)
6661         outBitC (result);
6662       // if(bit & ...)
6663       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6664         genIfxJump (ifx, "c", left, right, result);
6665       goto release;
6666     }
6667
6668   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6669   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6670   if ((AOP_TYPE (right) == AOP_LIT) &&
6671       (AOP_TYPE (result) == AOP_CRY) &&
6672       (AOP_TYPE (left) != AOP_CRY))
6673     {
6674       int posbit = isLiteralBit (lit);
6675       /* left &  2^n */
6676       if (posbit)
6677         {
6678           posbit--;
6679           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6680           // bit = left & 2^n
6681           if (size)
6682             {
6683               switch (posbit & 0x07)
6684                 {
6685                   case 0: emitcode ("rrc", "a");
6686                           break;
6687                   case 7: emitcode ("rlc", "a");
6688                           break;
6689                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6690                           break;
6691                 }
6692             }
6693           // if(left &  2^n)
6694           else
6695             {
6696               if (ifx)
6697                 {
6698                   SNPRINTF (buffer, sizeof(buffer),
6699                             "acc.%d", posbit & 0x07);
6700                   genIfxJump (ifx, buffer, left, right, result);
6701                 }
6702               else
6703                 {// what is this case? just found it in ds390/gen.c
6704                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6705                 }
6706               goto release;
6707             }
6708         }
6709       else
6710         {
6711           symbol *tlbl = newiTempLabel (NULL);
6712           int sizel = AOP_SIZE (left);
6713           if (size)
6714             emitcode ("setb", "c");
6715           while (sizel--)
6716             {
6717               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6718                 {
6719                   MOVA (aopGet (left, offset, FALSE, FALSE));
6720                   // byte ==  2^n ?
6721                   if ((posbit = isLiteralBit (bytelit)) != 0)
6722                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6723                   else
6724                     {
6725                       if (bytelit != 0x0FFL)
6726                         emitcode ("anl", "a,%s",
6727                                   aopGet (right, offset, FALSE, TRUE));
6728                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6729                     }
6730                 }
6731               offset++;
6732             }
6733           // bit = left & literal
6734           if (size)
6735             {
6736               emitcode ("clr", "c");
6737               emitLabel (tlbl);
6738             }
6739           // if(left & literal)
6740           else
6741             {
6742               if (ifx)
6743                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6744               else
6745                 emitLabel (tlbl);
6746               goto release;
6747             }
6748         }
6749       outBitC (result);
6750       goto release;
6751     }
6752
6753   /* if left is same as result */
6754   if (sameRegs (AOP (result), AOP (left)))
6755     {
6756       for (; size--; offset++)
6757         {
6758           if (AOP_TYPE (right) == AOP_LIT)
6759             {
6760               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6761               if (bytelit == 0x0FF)
6762                 {
6763                   /* dummy read of volatile operand */
6764                   if (isOperandVolatile (left, FALSE))
6765                     MOVA (aopGet (left, offset, FALSE, FALSE));
6766                   else
6767                     continue;
6768                 }
6769               else if (bytelit == 0)
6770                 {
6771                   aopPut (result, zero, offset);
6772                 }
6773               else if (IS_AOP_PREG (result))
6774                 {
6775                   MOVA (aopGet (left, offset, FALSE, TRUE));
6776                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6777                   aopPut (result, "a", offset);
6778                 }
6779               else
6780                 emitcode ("anl", "%s,%s",
6781                           aopGet (left, offset, FALSE, TRUE),
6782                           aopGet (right, offset, FALSE, FALSE));
6783             }
6784           else
6785             {
6786               if (AOP_TYPE (left) == AOP_ACC)
6787                 {
6788                   if (offset)
6789                     emitcode("mov", "a,b");
6790                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6791                 }
6792               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6793                 {
6794                   MOVB (aopGet (left, offset, FALSE, FALSE));
6795                   MOVA (aopGet (right, offset, FALSE, FALSE));
6796                   emitcode ("anl", "a,b");
6797                   aopPut (result, "a", offset);
6798                 }
6799               else if (aopGetUsesAcc (left, offset))
6800                 {
6801                   MOVA (aopGet (left, offset, FALSE, FALSE));
6802                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6803                   aopPut (result, "a", offset);
6804                 }
6805               else
6806                 {
6807                   MOVA (aopGet (right, offset, FALSE, FALSE));
6808                   if (IS_AOP_PREG (result))
6809                     {
6810                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6811                       aopPut (result, "a", offset);
6812                     }
6813                   else
6814                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6815                 }
6816             }
6817         }
6818     }
6819   else
6820     {
6821       // left & result in different registers
6822       if (AOP_TYPE (result) == AOP_CRY)
6823         {
6824           // result = bit
6825           // if(size), result in bit
6826           // if(!size && ifx), conditional oper: if(left & right)
6827           symbol *tlbl = newiTempLabel (NULL);
6828           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6829           if (size)
6830             emitcode ("setb", "c");
6831           while (sizer--)
6832             {
6833               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6834                   && AOP_TYPE(left)==AOP_ACC)
6835                 {
6836                   if (offset)
6837                     emitcode("mov", "a,b");
6838                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6839                 }
6840               else if (AOP_TYPE(left)==AOP_ACC)
6841                 {
6842                   if (!offset)
6843                     {
6844                       bool pushedB = pushB ();
6845                       emitcode("mov", "b,a");
6846                       MOVA (aopGet (right, offset, FALSE, FALSE));
6847                       emitcode("anl", "a,b");
6848                       popB (pushedB);
6849                     }
6850                   else
6851                     {
6852                       MOVA (aopGet (right, offset, FALSE, FALSE));
6853                       emitcode("anl", "a,b");
6854                     }
6855                 }
6856               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6857                 {
6858                   MOVB (aopGet (left, offset, FALSE, FALSE));
6859                   MOVA (aopGet (right, offset, FALSE, FALSE));
6860                   emitcode ("anl", "a,b");
6861                 }
6862               else if (aopGetUsesAcc (left, offset))
6863                 {
6864                   MOVA (aopGet (left, offset, FALSE, FALSE));
6865                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6866                     }
6867               else
6868                 {
6869                   MOVA (aopGet (right, offset, FALSE, FALSE));
6870                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6871                 }
6872
6873               emitcode ("jnz", "%05d$", tlbl->key + 100);
6874               offset++;
6875             }
6876           if (size)
6877             {
6878               CLRC;
6879               emitLabel (tlbl);
6880               outBitC (result);
6881             }
6882           else if (ifx)
6883             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6884           else
6885             emitLabel (tlbl);
6886         }
6887       else
6888         {
6889           for (; (size--); offset++)
6890             {
6891               // normal case
6892               // result = left & right
6893               if (AOP_TYPE (right) == AOP_LIT)
6894                 {
6895                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6896                   if (bytelit == 0x0FF)
6897                     {
6898                       aopPut (result,
6899                               aopGet (left, offset, FALSE, FALSE),
6900                               offset);
6901                       continue;
6902                     }
6903                   else if (bytelit == 0)
6904                     {
6905                       /* dummy read of volatile operand */
6906                       if (isOperandVolatile (left, FALSE))
6907                         MOVA (aopGet (left, offset, FALSE, FALSE));
6908                       aopPut (result, zero, offset);
6909                       continue;
6910                     }
6911                   else if (AOP_TYPE (left) == AOP_ACC)
6912                     {
6913                       if (!offset)
6914                         {
6915                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6916                           aopPut (result, "a", offset);
6917                           continue;
6918                         }
6919                       else
6920                         {
6921                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6922                           aopPut (result, "b", offset);
6923                           continue;
6924                         }
6925                     }
6926                 }
6927               // faster than result <- left, anl result,right
6928               // and better if result is SFR
6929               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6930                   && AOP_TYPE(left)==AOP_ACC)
6931                 {
6932                   if (offset)
6933                     emitcode("mov", "a,b");
6934                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6935                 }
6936               else if (AOP_TYPE(left)==AOP_ACC)
6937                 {
6938                   if (!offset)
6939                     {
6940                       bool pushedB = pushB ();
6941                       emitcode("mov", "b,a");
6942                       MOVA (aopGet (right, offset, FALSE, FALSE));
6943                       emitcode("anl", "a,b");
6944                       popB (pushedB);
6945                     }
6946                   else
6947                     {
6948                       MOVA (aopGet (right, offset, FALSE, FALSE));
6949                       emitcode("anl", "a,b");
6950                     }
6951                 }
6952               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6953                 {
6954                   MOVB (aopGet (left, offset, FALSE, FALSE));
6955                   MOVA (aopGet (right, offset, FALSE, FALSE));
6956                   emitcode ("anl", "a,b");
6957                 }
6958               else if (aopGetUsesAcc (left, offset))
6959                 {
6960                   MOVA (aopGet (left, offset, FALSE, FALSE));
6961                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6962                 }
6963               else
6964                 {
6965                   MOVA (aopGet (right, offset, FALSE, FALSE));
6966                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6967                 }
6968               aopPut (result, "a", offset);
6969             }
6970         }
6971     }
6972
6973 release:
6974   freeAsmop (result, NULL, ic, TRUE);
6975   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6976   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6977 }
6978
6979 /*-----------------------------------------------------------------*/
6980 /* genOr  - code for or                                            */
6981 /*-----------------------------------------------------------------*/
6982 static void
6983 genOr (iCode * ic, iCode * ifx)
6984 {
6985   operand *left, *right, *result;
6986   int size, offset = 0;
6987   unsigned long lit = 0L;
6988   int bytelit = 0;
6989
6990   D (emitcode (";", "genOr"));
6991
6992   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6993   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6994   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6995
6996 #ifdef DEBUG_TYPE
6997   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6998             AOP_TYPE (result),
6999             AOP_TYPE (left), AOP_TYPE (right));
7000   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7001             AOP_SIZE (result),
7002             AOP_SIZE (left), AOP_SIZE (right));
7003 #endif
7004
7005   /* if left is a literal & right is not then exchange them */
7006   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7007       AOP_NEEDSACC (left))
7008     {
7009       operand *tmp = right;
7010       right = left;
7011       left = tmp;
7012     }
7013
7014   /* if result = right then exchange them */
7015   if (sameRegs (AOP (result), AOP (right)))
7016     {
7017       operand *tmp = right;
7018       right = left;
7019       left = tmp;
7020     }
7021
7022   /* if right is bit then exchange them */
7023   if (AOP_TYPE (right) == AOP_CRY &&
7024       AOP_TYPE (left) != AOP_CRY)
7025     {
7026       operand *tmp = right;
7027       right = left;
7028       left = tmp;
7029     }
7030   if (AOP_TYPE (right) == AOP_LIT)
7031     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7032
7033   size = AOP_SIZE (result);
7034
7035   // if(bit | yy)
7036   // xx = bit | yy;
7037   if (AOP_TYPE (left) == AOP_CRY)
7038     {
7039       if (AOP_TYPE (right) == AOP_LIT)
7040         {
7041           // c = bit | literal;
7042           if (lit)
7043             {
7044               // lit != 0 => result = 1
7045               if (AOP_TYPE (result) == AOP_CRY)
7046                 {
7047                   if (size)
7048                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7049                   else if (ifx)
7050                     continueIfTrue (ifx);
7051                   goto release;
7052                 }
7053               emitcode ("setb", "c");
7054             }
7055           else
7056             {
7057               // lit == 0 => result = left
7058               if (size && sameRegs (AOP (result), AOP (left)))
7059                 goto release;
7060               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7061             }
7062         }
7063       else
7064         {
7065           if (AOP_TYPE (right) == AOP_CRY)
7066             {
7067               // c = bit | bit;
7068               if (IS_OP_ACCUSE (left))
7069                 {
7070                   emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7071                 }
7072               else
7073                 {
7074                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7075                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7076                 }
7077             }
7078           else
7079             {
7080               // c = bit | val;
7081               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7082                 {
7083                   symbol *tlbl = newiTempLabel (NULL);
7084                   emitcode ("jb", "%s,%05d$",
7085                             AOP (left)->aopu.aop_dir, tlbl->key + 100);
7086                   toBoolean (right);
7087                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7088                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7089                   goto release;
7090                 }
7091               else
7092                 {
7093                   toCarry (right);
7094                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7095                 }
7096             }
7097         }
7098       // bit = c
7099       // val = c
7100       if (size)
7101         outBitC (result);
7102       // if(bit | ...)
7103       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7104         genIfxJump (ifx, "c", left, right, result);
7105       goto release;
7106     }
7107
7108   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7109   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7110   if ((AOP_TYPE (right) == AOP_LIT) &&
7111       (AOP_TYPE (result) == AOP_CRY) &&
7112       (AOP_TYPE (left) != AOP_CRY))
7113     {
7114       if (lit)
7115         {
7116           // result = 1
7117           if (size)
7118             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7119           else
7120             continueIfTrue (ifx);
7121           goto release;
7122         }
7123       else
7124         {
7125           // lit = 0, result = boolean(left)
7126           if (size)
7127             emitcode ("setb", "c");
7128           toBoolean (right);
7129           if (size)
7130             {
7131               symbol *tlbl = newiTempLabel (NULL);
7132               emitcode ("jnz", "%05d$", tlbl->key + 100);
7133               CLRC;
7134               emitLabel (tlbl);
7135             }
7136           else
7137             {
7138               genIfxJump (ifx, "a", left, right, result);
7139               goto release;
7140             }
7141         }
7142       outBitC (result);
7143       goto release;
7144     }
7145
7146   /* if left is same as result */
7147   if (sameRegs (AOP (result), AOP (left)))
7148     {
7149       for (; size--; offset++)
7150         {
7151           if (AOP_TYPE (right) == AOP_LIT)
7152             {
7153               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7154               if (bytelit == 0)
7155                 {
7156                   /* dummy read of volatile operand */
7157                   if (isOperandVolatile (left, FALSE))
7158                     MOVA (aopGet (left, offset, FALSE, FALSE));
7159                   else
7160                     continue;
7161                 }
7162               else if (bytelit == 0x0FF)
7163                 {
7164                   aopPut (result, "#0xFF", offset);
7165                 }
7166               else if (IS_AOP_PREG (left))
7167                 {
7168                   MOVA (aopGet (left, offset, FALSE, TRUE));
7169                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7170                   aopPut (result, "a", offset);
7171                 }
7172               else
7173                 {
7174                   emitcode ("orl", "%s,%s",
7175                             aopGet (left, offset, FALSE, TRUE),
7176                             aopGet (right, offset, FALSE, FALSE));
7177                 }
7178             }
7179           else
7180             {
7181               if (AOP_TYPE (left) == AOP_ACC)
7182                 {
7183                   if (offset)
7184                     emitcode("mov", "a,b");
7185                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7186                 }
7187               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7188                 {
7189                   MOVB (aopGet (left, offset, FALSE, FALSE));
7190                   MOVA (aopGet (right, offset, FALSE, FALSE));
7191                   emitcode ("orl", "a,b");
7192                   aopPut (result, "a", offset);
7193                 }
7194               else if (aopGetUsesAcc (left, offset))
7195                 {
7196                   MOVA (aopGet (left, offset, FALSE, FALSE));
7197                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7198                   aopPut (result, "a", offset);
7199                 }
7200               else
7201                 {
7202                   MOVA (aopGet (right, offset, FALSE, FALSE));
7203                   if (IS_AOP_PREG (left))
7204                     {
7205                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7206                       aopPut (result, "a", offset);
7207                     }
7208                   else
7209                     {
7210                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7211                     }
7212                 }
7213             }
7214         }
7215     }
7216   else
7217     {
7218       // left & result in different registers
7219       if (AOP_TYPE (result) == AOP_CRY)
7220         {
7221           // result = bit
7222           // if(size), result in bit
7223           // if(!size && ifx), conditional oper: if(left | right)
7224           symbol *tlbl = newiTempLabel (NULL);
7225           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7226           if (size)
7227             emitcode ("setb", "c");
7228           while (sizer--)
7229             {
7230               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7231                   && AOP_TYPE(left)==AOP_ACC)
7232                 {
7233                   if (offset)
7234                     emitcode("mov", "a,b");
7235                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7236                 }
7237               else if (AOP_TYPE(left)==AOP_ACC)
7238                 {
7239                   if (!offset)
7240                     {
7241                       bool pushedB = pushB ();
7242                       emitcode("mov", "b,a");
7243                       MOVA (aopGet (right, offset, FALSE, FALSE));
7244                       emitcode("orl", "a,b");
7245                       popB (pushedB);
7246                     }
7247                   else
7248                     {
7249                       MOVA (aopGet (right, offset, FALSE, FALSE));
7250                       emitcode("orl", "a,b");
7251                     }
7252                 }
7253               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7254                 {
7255                   MOVB (aopGet (left, offset, FALSE, FALSE));
7256                   MOVA (aopGet (right, offset, FALSE, FALSE));
7257                   emitcode ("orl", "a,b");
7258                 }
7259               else if (aopGetUsesAcc (left, offset))
7260                 {
7261                   MOVA (aopGet (left, offset, FALSE, FALSE));
7262                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7263                 }
7264               else
7265                 {
7266                   MOVA (aopGet (right, offset, FALSE, FALSE));
7267                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7268               }
7269
7270               emitcode ("jnz", "%05d$", tlbl->key + 100);
7271               offset++;
7272             }
7273           if (size)
7274             {
7275               CLRC;
7276               emitLabel (tlbl);
7277               outBitC (result);
7278             }
7279           else if (ifx)
7280             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7281           else
7282             emitLabel (tlbl);
7283         }
7284       else
7285         {
7286           for (; (size--); offset++)
7287             {
7288               // normal case
7289               // result = left | right
7290               if (AOP_TYPE (right) == AOP_LIT)
7291                 {
7292                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7293                   if (bytelit == 0)
7294                     {
7295                       aopPut (result,
7296                               aopGet (left, offset, FALSE, FALSE),
7297                               offset);
7298                       continue;
7299                     }
7300                   else if (bytelit == 0x0FF)
7301                     {
7302                       /* dummy read of volatile operand */
7303                       if (isOperandVolatile (left, FALSE))
7304                         MOVA (aopGet (left, offset, FALSE, FALSE));
7305                       aopPut (result, "#0xFF", offset);
7306                       continue;
7307                     }
7308                 }
7309               // faster than result <- left, orl result,right
7310               // and better if result is SFR
7311               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7312                   && AOP_TYPE(left)==AOP_ACC)
7313                 {
7314                   if (offset)
7315                     emitcode("mov", "a,b");
7316                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7317                 }
7318               else if (AOP_TYPE(left)==AOP_ACC)
7319                 {
7320                   if (!offset)
7321                     {
7322                       bool pushedB = pushB ();
7323                       emitcode("mov", "b,a");
7324                       MOVA (aopGet (right, offset, FALSE, FALSE));
7325                       emitcode("orl", "a,b");
7326                       popB (pushedB);
7327                     }
7328                   else
7329                     {
7330                       MOVA (aopGet (right, offset, FALSE, FALSE));
7331                       emitcode("orl", "a,b");
7332                     }
7333                 }
7334               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7335                 {
7336                   MOVB (aopGet (left, offset, FALSE, FALSE));
7337                   MOVA (aopGet (right, offset, FALSE, FALSE));
7338                   emitcode ("orl", "a,b");
7339                 }
7340               else if (aopGetUsesAcc (left, offset))
7341                 {
7342                   MOVA (aopGet (left, offset, FALSE, FALSE));
7343                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7344                 }
7345               else
7346                 {
7347                   MOVA (aopGet (right, offset, FALSE, FALSE));
7348                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7349                 }
7350               aopPut (result, "a", offset);
7351             }
7352         }
7353     }
7354
7355 release:
7356   freeAsmop (result, NULL, ic, TRUE);
7357   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7358   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7359 }
7360
7361 /*-----------------------------------------------------------------*/
7362 /* genXor - code for xclusive or                                   */
7363 /*-----------------------------------------------------------------*/
7364 static void
7365 genXor (iCode * ic, iCode * ifx)
7366 {
7367   operand *left, *right, *result;
7368   int size, offset = 0;
7369   unsigned long lit = 0L;
7370   int bytelit = 0;
7371
7372   D (emitcode (";", "genXor"));
7373
7374   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7375   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7376   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7377
7378 #ifdef DEBUG_TYPE
7379   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7380             AOP_TYPE (result),
7381             AOP_TYPE (left), AOP_TYPE (right));
7382   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7383             AOP_SIZE (result),
7384             AOP_SIZE (left), AOP_SIZE (right));
7385 #endif
7386
7387   /* if left is a literal & right is not ||
7388      if left needs acc & right does not */
7389   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7390       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7391     {
7392       operand *tmp = right;
7393       right = left;
7394       left = tmp;
7395     }
7396
7397   /* if result = right then exchange them */
7398   if (sameRegs (AOP (result), AOP (right)))
7399     {
7400       operand *tmp = right;
7401       right = left;
7402       left = tmp;
7403     }
7404
7405   /* if right is bit then exchange them */
7406   if (AOP_TYPE (right) == AOP_CRY &&
7407       AOP_TYPE (left) != AOP_CRY)
7408     {
7409       operand *tmp = right;
7410       right = left;
7411       left = tmp;
7412     }
7413
7414   if (AOP_TYPE (right) == AOP_LIT)
7415     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7416
7417   size = AOP_SIZE (result);
7418
7419   // if(bit ^ yy)
7420   // xx = bit ^ yy;
7421   if (AOP_TYPE (left) == AOP_CRY)
7422     {
7423       if (AOP_TYPE (right) == AOP_LIT)
7424         {
7425           // c = bit & literal;
7426           if (lit >> 1)
7427             {
7428               // lit>>1  != 0 => result = 1
7429               if (AOP_TYPE (result) == AOP_CRY)
7430                 {
7431                   if (size)
7432                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7433                   else if (ifx)
7434                     continueIfTrue (ifx);
7435                   goto release;
7436                 }
7437               emitcode ("setb", "c");
7438             }
7439           else
7440             {
7441               // lit == (0 or 1)
7442               if (lit == 0)
7443                 {
7444                   // lit == 0, result = left
7445                   if (size && sameRegs (AOP (result), AOP (left)))
7446                     goto release;
7447                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7448                 }
7449               else
7450                 {
7451                   // lit == 1, result = not(left)
7452                   if (size && sameRegs (AOP (result), AOP (left)))
7453                     {
7454                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7455                       goto release;
7456                     }
7457                   else
7458                     {
7459                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7460                       emitcode ("cpl", "c");
7461                     }
7462                 }
7463             }
7464         }
7465       else
7466         {
7467           // right != literal
7468           symbol *tlbl = newiTempLabel (NULL);
7469           if (AOP_TYPE (right) == AOP_CRY)
7470             {
7471               // c = bit ^ bit;
7472               if (IS_OP_ACCUSE (left))
7473                 {// left already is in the carry
7474                   operand *tmp = right;
7475                   right = left;
7476                   left = tmp;
7477                 }
7478               else
7479                 {
7480                   toCarry (right);
7481                 }
7482             }
7483           else
7484             {
7485               // c = bit ^ val
7486               toCarry (right);
7487             }
7488           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7489           emitcode ("cpl", "c");
7490           emitLabel (tlbl);
7491         }
7492       // bit = c
7493       // val = c
7494       if (size)
7495         outBitC (result);
7496       // if(bit ^ ...)
7497       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7498         genIfxJump (ifx, "c", left, right, result);
7499       goto release;
7500     }
7501
7502   /* if left is same as result */
7503   if (sameRegs (AOP (result), AOP (left)))
7504     {
7505       for (; size--; offset++)
7506         {
7507           if (AOP_TYPE (right) == AOP_LIT)
7508             {
7509               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7510               if (bytelit == 0)
7511                 {
7512                   /* dummy read of volatile operand */
7513                   if (isOperandVolatile (left, FALSE))
7514                     MOVA (aopGet (left, offset, FALSE, FALSE));
7515                   else
7516                     continue;
7517                 }
7518               else if (IS_AOP_PREG (left))
7519                 {
7520                   MOVA (aopGet (left, offset, FALSE, TRUE));
7521                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7522                   aopPut (result, "a", offset);
7523                 }
7524               else
7525                 {
7526                   emitcode ("xrl", "%s,%s",
7527                             aopGet (left, offset, FALSE, TRUE),
7528                             aopGet (right, offset, FALSE, FALSE));
7529                 }
7530             }
7531           else
7532             {
7533               if (AOP_TYPE (left) == AOP_ACC)
7534                 {
7535                   if (offset)
7536                     emitcode("mov", "a,b");
7537                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7538                 }
7539               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7540                 {
7541                   MOVB (aopGet (left, offset, FALSE, FALSE));
7542                   MOVA (aopGet (right, offset, FALSE, FALSE));
7543                   emitcode ("xrl", "a,b");
7544                   aopPut (result, "a", offset);
7545                 }
7546               else if (aopGetUsesAcc (left, offset))
7547                 {
7548                   MOVA (aopGet (left, offset, FALSE, FALSE));
7549                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7550                   aopPut (result, "a", offset);
7551                 }
7552               else
7553                 {
7554                   MOVA (aopGet (right, offset, FALSE, FALSE));
7555                   if (IS_AOP_PREG (left))
7556                     {
7557                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7558                       aopPut (result, "a", offset);
7559                     }
7560                   else
7561                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7562                 }
7563             }
7564         }
7565     }
7566   else
7567     {
7568       // left & result in different registers
7569       if (AOP_TYPE (result) == AOP_CRY)
7570         {
7571           // result = bit
7572           // if(size), result in bit
7573           // if(!size && ifx), conditional oper: if(left ^ right)
7574           symbol *tlbl = newiTempLabel (NULL);
7575           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7576
7577           if (size)
7578             emitcode ("setb", "c");
7579           while (sizer--)
7580             {
7581               if ((AOP_TYPE (right) == AOP_LIT) &&
7582                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7583                 {
7584                   MOVA (aopGet (left, offset, FALSE, FALSE));
7585                 }
7586               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7587                   && AOP_TYPE(left)==AOP_ACC)
7588                 {
7589                   if (offset)
7590                     emitcode("mov", "a,b");
7591                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7592                 }
7593               else if (AOP_TYPE(left)==AOP_ACC)
7594                 {
7595                   if (!offset)
7596                     {
7597                       bool pushedB = pushB ();
7598                       emitcode("mov", "b,a");
7599                       MOVA (aopGet (right, offset, FALSE, FALSE));
7600                       emitcode("xrl", "a,b");
7601                       popB (pushedB);
7602                     }
7603                   else
7604                     {
7605                       MOVA (aopGet (right, offset, FALSE, FALSE));
7606                       emitcode("xrl", "a,b");
7607                     }
7608                 }
7609               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7610                 {
7611                   MOVB (aopGet (left, offset, FALSE, FALSE));
7612                   MOVA (aopGet (right, offset, FALSE, FALSE));
7613                   emitcode ("xrl", "a,b");
7614                 }
7615               else if (aopGetUsesAcc (left, offset))
7616                 {
7617                   MOVA (aopGet (left, offset, FALSE, FALSE));
7618                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7619                 }
7620               else
7621                 {
7622                   MOVA (aopGet (right, offset, FALSE, FALSE));
7623                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7624                 }
7625
7626               emitcode ("jnz", "%05d$", tlbl->key + 100);
7627               offset++;
7628             }
7629           if (size)
7630             {
7631               CLRC;
7632               emitLabel (tlbl);
7633               outBitC (result);
7634             }
7635           else if (ifx)
7636             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7637         }
7638       else
7639         {
7640           for (; (size--); offset++)
7641             {
7642               // normal case
7643               // result = left ^ right
7644               if (AOP_TYPE (right) == AOP_LIT)
7645                 {
7646                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7647                   if (bytelit == 0)
7648                     {
7649                       aopPut (result,
7650                               aopGet (left, offset, FALSE, FALSE),
7651                               offset);
7652                       continue;
7653                     }
7654                 }
7655               // faster than result <- left, xrl result,right
7656               // and better if result is SFR
7657               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7658                   && AOP_TYPE(left)==AOP_ACC)
7659                 {
7660                   if (offset)
7661                     emitcode("mov", "a,b");
7662                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7663                 }
7664               else if (AOP_TYPE(left)==AOP_ACC)
7665                 {
7666                   if (!offset)
7667                     {
7668                       bool pushedB = pushB ();
7669                       emitcode("mov", "b,a");
7670                       MOVA (aopGet (right, offset, FALSE, FALSE));
7671                       emitcode("xrl", "a,b");
7672                       popB (pushedB);
7673                     }
7674                   else
7675                     {
7676                       MOVA (aopGet (right, offset, FALSE, FALSE));
7677                       emitcode("xrl", "a,b");
7678                     }
7679                 }
7680               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7681                 {
7682                   MOVB (aopGet (left, offset, FALSE, FALSE));
7683                   MOVA (aopGet (right, offset, FALSE, FALSE));
7684                   emitcode ("xrl", "a,b");
7685                 }
7686               else if (aopGetUsesAcc (left, offset))
7687                 {
7688                   MOVA (aopGet (left, offset, FALSE, FALSE));
7689                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7690                 }
7691               else
7692                 {
7693                   MOVA (aopGet (right, offset, FALSE, FALSE));
7694                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7695                 }
7696               aopPut (result, "a", offset);
7697             }
7698         }
7699     }
7700
7701 release:
7702   freeAsmop (result, NULL, ic, TRUE);
7703   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7704   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7705 }
7706
7707 /*-----------------------------------------------------------------*/
7708 /* genInline - write the inline code out                           */
7709 /*-----------------------------------------------------------------*/
7710 static void
7711 genInline (iCode * ic)
7712 {
7713   char *buffer, *bp, *bp1;
7714   bool inComment = FALSE;
7715
7716   D (emitcode (";", "genInline"));
7717
7718   _G.inLine += (!options.asmpeep);
7719
7720   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7721
7722   /* emit each line as a code */
7723   while (*bp)
7724     {
7725       switch (*bp)
7726         {
7727         case ';':
7728           inComment = TRUE;
7729           ++bp;
7730           break;
7731
7732         case '\n':
7733           inComment = FALSE;
7734           *bp++ = '\0';
7735           emitcode (bp1, "");
7736           bp1 = bp;
7737           break;
7738
7739         default:
7740           /* Add \n for labels, not dirs such as c:\mydir */
7741           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7742             {
7743               ++bp;
7744               *bp = '\0';
7745               ++bp;
7746               emitcode (bp1, "");
7747               bp1 = bp;
7748             }
7749           else
7750             ++bp;
7751           break;
7752         }
7753     }
7754   if (bp1 != bp)
7755     emitcode (bp1, "");
7756
7757   Safe_free (buffer);
7758
7759   _G.inLine -= (!options.asmpeep);
7760 }
7761
7762 /*-----------------------------------------------------------------*/
7763 /* genRRC - rotate right with carry                                */
7764 /*-----------------------------------------------------------------*/
7765 static void
7766 genRRC (iCode * ic)
7767 {
7768   operand *left, *result;
7769   int size, offset;
7770   char *l;
7771
7772   D (emitcode (";", "genRRC"));
7773
7774   /* rotate right with carry */
7775   left = IC_LEFT (ic);
7776   result = IC_RESULT (ic);
7777   aopOp (left, ic, FALSE);
7778   aopOp (result, ic, FALSE);
7779
7780   /* move it to the result */
7781   size = AOP_SIZE (result);
7782   offset = size - 1;
7783   if (size == 1) { /* special case for 1 byte */
7784       l = aopGet (left, offset, FALSE, FALSE);
7785       MOVA (l);
7786       emitcode ("rr", "a");
7787       goto release;
7788   }
7789   /* no need to clear carry, bit7 will be written later */
7790   while (size--)
7791     {
7792       l = aopGet (left, offset, FALSE, FALSE);
7793       MOVA (l);
7794       emitcode ("rrc", "a");
7795       if (AOP_SIZE (result) > 1)
7796         aopPut (result, "a", offset--);
7797     }
7798   /* now we need to put the carry into the
7799      highest order byte of the result */
7800   if (AOP_SIZE (result) > 1)
7801     {
7802       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7803       MOVA (l);
7804     }
7805   emitcode ("mov", "acc.7,c");
7806  release:
7807   aopPut (result, "a", AOP_SIZE (result) - 1);
7808   freeAsmop (result, NULL, ic, TRUE);
7809   freeAsmop (left, NULL, ic, TRUE);
7810 }
7811
7812 /*-----------------------------------------------------------------*/
7813 /* genRLC - generate code for rotate left with carry               */
7814 /*-----------------------------------------------------------------*/
7815 static void
7816 genRLC (iCode * ic)
7817 {
7818   operand *left, *result;
7819   int size, offset;
7820   char *l;
7821
7822   D (emitcode (";", "genRLC"));
7823
7824   /* rotate right with carry */
7825   left = IC_LEFT (ic);
7826   result = IC_RESULT (ic);
7827   aopOp (left, ic, FALSE);
7828   aopOp (result, ic, FALSE);
7829
7830   /* move it to the result */
7831   size = AOP_SIZE (result);
7832   offset = 0;
7833   if (size--)
7834     {
7835       l = aopGet (left, offset, FALSE, FALSE);
7836       MOVA (l);
7837       if (size == 0) { /* special case for 1 byte */
7838               emitcode("rl","a");
7839               goto release;
7840       }
7841       emitcode("rlc","a"); /* bit0 will be written later */
7842       if (AOP_SIZE (result) > 1)
7843         {
7844           aopPut (result, "a", offset++);
7845         }
7846
7847       while (size--)
7848         {
7849           l = aopGet (left, offset, FALSE, FALSE);
7850           MOVA (l);
7851           emitcode ("rlc", "a");
7852           if (AOP_SIZE (result) > 1)
7853             aopPut (result, "a", offset++);
7854         }
7855     }
7856   /* now we need to put the carry into the
7857      highest order byte of the result */
7858   if (AOP_SIZE (result) > 1)
7859     {
7860       l = aopGet (result, 0, FALSE, FALSE);
7861       MOVA (l);
7862     }
7863   emitcode ("mov", "acc.0,c");
7864  release:
7865   aopPut (result, "a", 0);
7866   freeAsmop (result, NULL, ic, TRUE);
7867   freeAsmop (left, NULL, ic, TRUE);
7868 }
7869
7870 /*-----------------------------------------------------------------*/
7871 /* genGetHbit - generates code get highest order bit               */
7872 /*-----------------------------------------------------------------*/
7873 static void
7874 genGetHbit (iCode * ic)
7875 {
7876   operand *left, *result;
7877
7878   D (emitcode (";", "genGetHbit"));
7879
7880   left = IC_LEFT (ic);
7881   result = IC_RESULT (ic);
7882   aopOp (left, ic, FALSE);
7883   aopOp (result, ic, FALSE);
7884
7885   /* get the highest order byte into a */
7886   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7887   if (AOP_TYPE (result) == AOP_CRY)
7888     {
7889       emitcode ("rlc", "a");
7890       outBitC (result);
7891     }
7892   else
7893     {
7894       emitcode ("rl", "a");
7895       emitcode ("anl", "a,#0x01");
7896       outAcc (result);
7897     }
7898
7899   freeAsmop (result, NULL, ic, TRUE);
7900   freeAsmop (left, NULL, ic, TRUE);
7901 }
7902
7903 /*-----------------------------------------------------------------*/
7904 /* genGetAbit - generates code get a single bit                    */
7905 /*-----------------------------------------------------------------*/
7906 static void
7907 genGetAbit (iCode * ic)
7908 {
7909   operand *left, *right, *result;
7910   int shCount;
7911
7912   D (emitcode (";", "genGetAbit"));
7913
7914   left = IC_LEFT (ic);
7915   right = IC_RIGHT (ic);
7916   result = IC_RESULT (ic);
7917   aopOp (left, ic, FALSE);
7918   aopOp (right, ic, FALSE);
7919   aopOp (result, ic, FALSE);
7920
7921   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7922
7923   /* get the needed byte into a */
7924   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7925   shCount %= 8;
7926   if (AOP_TYPE (result) == AOP_CRY)
7927     {
7928       if ((shCount) == 7)
7929           emitcode ("rlc", "a");
7930       else if ((shCount) == 0)
7931           emitcode ("rrc", "a");
7932       else
7933           emitcode ("mov", "c,acc[%d]", shCount);
7934       outBitC (result);
7935     }
7936   else
7937     {
7938       switch (shCount)
7939         {
7940         case 2:
7941           emitcode ("rr", "a");
7942           //fallthrough
7943         case 1:
7944           emitcode ("rr", "a");
7945           //fallthrough
7946         case 0:
7947           emitcode ("anl", "a,#0x01");
7948           break;
7949         case 3:
7950         case 5:
7951           emitcode ("mov", "c,acc[%d]", shCount);
7952           emitcode ("clr", "a");
7953           emitcode ("rlc", "a");
7954           break;
7955         case 4:
7956           emitcode ("swap", "a");
7957           emitcode ("anl", "a,#0x01");
7958           break;
7959         case 6:
7960           emitcode ("rl", "a");
7961           //fallthrough
7962         case 7:
7963           emitcode ("rl", "a");
7964           emitcode ("anl", "a,#0x01");
7965           break;
7966         }
7967       outAcc (result);
7968     }
7969
7970   freeAsmop (result, NULL, ic, TRUE);
7971   freeAsmop (right, NULL, ic, TRUE);
7972   freeAsmop (left, NULL, ic, TRUE);
7973 }
7974
7975 /*-----------------------------------------------------------------*/
7976 /* genGetByte - generates code get a single byte                   */
7977 /*-----------------------------------------------------------------*/
7978 static void
7979 genGetByte (iCode * ic)
7980 {
7981   operand *left, *right, *result;
7982   int offset;
7983
7984   D (emitcode (";", "genGetByte"));
7985
7986   left = IC_LEFT (ic);
7987   right = IC_RIGHT (ic);
7988   result = IC_RESULT (ic);
7989   aopOp (left, ic, FALSE);
7990   aopOp (right, ic, FALSE);
7991   aopOp (result, ic, FALSE);
7992
7993   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
7994   aopPut (result,
7995           aopGet (left, offset, FALSE, FALSE),
7996           0);
7997
7998   freeAsmop (result, NULL, ic, TRUE);
7999   freeAsmop (right, NULL, ic, TRUE);
8000   freeAsmop (left, NULL, ic, TRUE);
8001 }
8002
8003 /*-----------------------------------------------------------------*/
8004 /* genGetWord - generates code get two bytes                       */
8005 /*-----------------------------------------------------------------*/
8006 static void
8007 genGetWord (iCode * ic)
8008 {
8009   operand *left, *right, *result;
8010   int offset;
8011
8012   D (emitcode (";", "genGetWord"));
8013
8014   left = IC_LEFT (ic);
8015   right = IC_RIGHT (ic);
8016   result = IC_RESULT (ic);
8017   aopOp (left, ic, FALSE);
8018   aopOp (right, ic, FALSE);
8019   aopOp (result, ic, FALSE);
8020
8021   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8022   aopPut (result,
8023           aopGet (left, offset, FALSE, FALSE),
8024           0);
8025   aopPut (result,
8026           aopGet (left, offset+1, FALSE, FALSE),
8027           1);
8028
8029   freeAsmop (result, NULL, ic, TRUE);
8030   freeAsmop (right, NULL, ic, TRUE);
8031   freeAsmop (left, NULL, ic, TRUE);
8032 }
8033
8034 /*-----------------------------------------------------------------*/
8035 /* genSwap - generates code to swap nibbles or bytes               */
8036 /*-----------------------------------------------------------------*/
8037 static void
8038 genSwap (iCode * ic)
8039 {
8040   operand *left, *result;
8041
8042   D(emitcode (";", "genSwap"));
8043
8044   left = IC_LEFT (ic);
8045   result = IC_RESULT (ic);
8046   aopOp (left, ic, FALSE);
8047   aopOp (result, ic, FALSE);
8048
8049   switch (AOP_SIZE (left))
8050     {
8051     case 1: /* swap nibbles in byte */
8052       MOVA (aopGet (left, 0, FALSE, FALSE));
8053       emitcode ("swap", "a");
8054       aopPut (result, "a", 0);
8055       break;
8056     case 2: /* swap bytes in word */
8057       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8058         {
8059           MOVA (aopGet (left, 0, FALSE, FALSE));
8060           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8061           aopPut (result, "a", 1);
8062         }
8063       else if (operandsEqu (left, result))
8064         {
8065           char * reg = "a";
8066           bool pushedB = FALSE, leftInB = FALSE;
8067
8068           MOVA (aopGet (left, 0, FALSE, FALSE));
8069           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8070             {
8071               pushedB = pushB ();
8072               emitcode ("mov", "b,a");
8073               reg = "b";
8074               leftInB = TRUE;
8075             }
8076           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8077           aopPut (result, reg, 1);
8078
8079           if (leftInB)
8080             popB (pushedB);
8081         }
8082       else
8083         {
8084           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8085           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8086         }
8087       break;
8088     default:
8089       wassertl(FALSE, "unsupported SWAP operand size");
8090     }
8091
8092   freeAsmop (result, NULL, ic, TRUE);
8093   freeAsmop (left, NULL, ic, TRUE);
8094 }
8095
8096 /*-----------------------------------------------------------------*/
8097 /* AccRol - rotate left accumulator by known count                 */
8098 /*-----------------------------------------------------------------*/
8099 static void
8100 AccRol (int shCount)
8101 {
8102   shCount &= 0x0007;            // shCount : 0..7
8103
8104   switch (shCount)
8105     {
8106     case 0:
8107       break;
8108     case 1:
8109       emitcode ("rl", "a");
8110       break;
8111     case 2:
8112       emitcode ("rl", "a");
8113       emitcode ("rl", "a");
8114       break;
8115     case 3:
8116       emitcode ("swap", "a");
8117       emitcode ("rr", "a");
8118       break;
8119     case 4:
8120       emitcode ("swap", "a");
8121       break;
8122     case 5:
8123       emitcode ("swap", "a");
8124       emitcode ("rl", "a");
8125       break;
8126     case 6:
8127       emitcode ("rr", "a");
8128       emitcode ("rr", "a");
8129       break;
8130     case 7:
8131       emitcode ("rr", "a");
8132       break;
8133     }
8134 }
8135
8136 /*-----------------------------------------------------------------*/
8137 /* AccLsh - left shift accumulator by known count                  */
8138 /*-----------------------------------------------------------------*/
8139 static void
8140 AccLsh (int shCount)
8141 {
8142   if (shCount != 0)
8143     {
8144       if (shCount == 1)
8145         emitcode ("add", "a,acc");
8146       else if (shCount == 2)
8147         {
8148           emitcode ("add", "a,acc");
8149           emitcode ("add", "a,acc");
8150         }
8151       else
8152         {
8153           /* rotate left accumulator */
8154           AccRol (shCount);
8155           /* and kill the lower order bits */
8156           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8157         }
8158     }
8159 }
8160
8161 /*-----------------------------------------------------------------*/
8162 /* AccRsh - right shift accumulator by known count                 */
8163 /*-----------------------------------------------------------------*/
8164 static void
8165 AccRsh (int shCount)
8166 {
8167   if (shCount != 0)
8168     {
8169       if (shCount == 1)
8170         {
8171           CLRC;
8172           emitcode ("rrc", "a");
8173         }
8174       else
8175         {
8176           /* rotate right accumulator */
8177           AccRol (8 - shCount);
8178           /* and kill the higher order bits */
8179           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8180         }
8181     }
8182 }
8183
8184 /*-----------------------------------------------------------------*/
8185 /* AccSRsh - signed right shift accumulator by known count                 */
8186 /*-----------------------------------------------------------------*/
8187 static void
8188 AccSRsh (int shCount)
8189 {
8190   symbol *tlbl;
8191   if (shCount != 0)
8192     {
8193       if (shCount == 1)
8194         {
8195           emitcode ("mov", "c,acc.7");
8196           emitcode ("rrc", "a");
8197         }
8198       else if (shCount == 2)
8199         {
8200           emitcode ("mov", "c,acc.7");
8201           emitcode ("rrc", "a");
8202           emitcode ("mov", "c,acc.7");
8203           emitcode ("rrc", "a");
8204         }
8205       else
8206         {
8207           tlbl = newiTempLabel (NULL);
8208           /* rotate right accumulator */
8209           AccRol (8 - shCount);
8210           /* and kill the higher order bits */
8211           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8212           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8213           emitcode ("orl", "a,#0x%02x",
8214                     (unsigned char) ~SRMask[shCount]);
8215           emitLabel (tlbl);
8216         }
8217     }
8218 }
8219
8220 /*-----------------------------------------------------------------*/
8221 /* shiftR1Left2Result - shift right one byte from left to result   */
8222 /*-----------------------------------------------------------------*/
8223 static void
8224 shiftR1Left2Result (operand * left, int offl,
8225                     operand * result, int offr,
8226                     int shCount, int sign)
8227 {
8228   MOVA (aopGet (left, offl, FALSE, FALSE));
8229   /* shift right accumulator */
8230   if (sign)
8231     AccSRsh (shCount);
8232   else
8233     AccRsh (shCount);
8234   aopPut (result, "a", offr);
8235 }
8236
8237 /*-----------------------------------------------------------------*/
8238 /* shiftL1Left2Result - shift left one byte from left to result    */
8239 /*-----------------------------------------------------------------*/
8240 static void
8241 shiftL1Left2Result (operand * left, int offl,
8242                     operand * result, int offr, int shCount)
8243 {
8244   char *l;
8245   l = aopGet (left, offl, FALSE, FALSE);
8246   MOVA (l);
8247   /* shift left accumulator */
8248   AccLsh (shCount);
8249   aopPut (result, "a", offr);
8250 }
8251
8252 /*-----------------------------------------------------------------*/
8253 /* movLeft2Result - move byte from left to result                  */
8254 /*-----------------------------------------------------------------*/
8255 static void
8256 movLeft2Result (operand * left, int offl,
8257                 operand * result, int offr, int sign)
8258 {
8259   char *l;
8260   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8261     {
8262       l = aopGet (left, offl, FALSE, FALSE);
8263
8264       if (*l == '@' && (IS_AOP_PREG (result)))
8265         {
8266           emitcode ("mov", "a,%s", l);
8267           aopPut (result, "a", offr);
8268         }
8269       else
8270         {
8271           if (!sign)
8272             {
8273               aopPut (result, l, offr);
8274             }
8275           else
8276             {
8277               /* MSB sign in acc.7 ! */
8278               if (getDataSize (left) == offl + 1)
8279                 {
8280                   MOVA (l);
8281                   aopPut (result, "a", offr);
8282                 }
8283             }
8284         }
8285     }
8286 }
8287
8288 /*-----------------------------------------------------------------*/
8289 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8290 /*-----------------------------------------------------------------*/
8291 static void
8292 AccAXRrl1 (char *x)
8293 {
8294   emitcode ("rrc", "a");
8295   emitcode ("xch", "a,%s", x);
8296   emitcode ("rrc", "a");
8297   emitcode ("xch", "a,%s", x);
8298 }
8299
8300 /*-----------------------------------------------------------------*/
8301 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8302 /*-----------------------------------------------------------------*/
8303 static void
8304 AccAXLrl1 (char *x)
8305 {
8306   emitcode ("xch", "a,%s", x);
8307   emitcode ("rlc", "a");
8308   emitcode ("xch", "a,%s", x);
8309   emitcode ("rlc", "a");
8310 }
8311
8312 /*-----------------------------------------------------------------*/
8313 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8314 /*-----------------------------------------------------------------*/
8315 static void
8316 AccAXLsh1 (char *x)
8317 {
8318   emitcode ("xch", "a,%s", x);
8319   emitcode ("add", "a,acc");
8320   emitcode ("xch", "a,%s", x);
8321   emitcode ("rlc", "a");
8322 }
8323
8324 /*-----------------------------------------------------------------*/
8325 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8326 /*-----------------------------------------------------------------*/
8327 static void
8328 AccAXLsh (char *x, int shCount)
8329 {
8330   switch (shCount)
8331     {
8332     case 0:
8333       break;
8334     case 1:
8335       AccAXLsh1 (x);
8336       break;
8337     case 2:
8338       AccAXLsh1 (x);
8339       AccAXLsh1 (x);
8340       break;
8341     case 3:
8342     case 4:
8343     case 5:                     // AAAAABBB:CCCCCDDD
8344
8345       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8346
8347       emitcode ("anl", "a,#0x%02x",
8348                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8349
8350       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8351
8352       AccRol (shCount);         // DDDCCCCC:BBB00000
8353
8354       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8355
8356       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8357
8358       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8359
8360       emitcode ("anl", "a,#0x%02x",
8361                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8362
8363       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8364
8365       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8366
8367       break;
8368     case 6:                     // AAAAAABB:CCCCCCDD
8369       emitcode ("anl", "a,#0x%02x",
8370                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8371       emitcode ("mov", "c,acc.0");      // c = B
8372       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8373 #if 0 // REMOVE ME
8374       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8375       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8376 #else
8377       emitcode("rrc","a");
8378       emitcode("xch","a,%s", x);
8379       emitcode("rrc","a");
8380       emitcode("mov","c,acc.0"); //<< get correct bit
8381       emitcode("xch","a,%s", x);
8382
8383       emitcode("rrc","a");
8384       emitcode("xch","a,%s", x);
8385       emitcode("rrc","a");
8386       emitcode("xch","a,%s", x);
8387 #endif
8388       break;
8389     case 7:                     // a:x <<= 7
8390
8391       emitcode ("anl", "a,#0x%02x",
8392                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8393
8394       emitcode ("mov", "c,acc.0");      // c = B
8395
8396       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8397
8398       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8399
8400       break;
8401     default:
8402       break;
8403     }
8404 }
8405
8406 /*-----------------------------------------------------------------*/
8407 /* AccAXRsh - right shift a:x known count (0..7)                   */
8408 /*-----------------------------------------------------------------*/
8409 static void
8410 AccAXRsh (char *x, int shCount)
8411 {
8412   switch (shCount)
8413     {
8414     case 0:
8415       break;
8416     case 1:
8417       CLRC;
8418       AccAXRrl1 (x);            // 0->a:x
8419
8420       break;
8421     case 2:
8422       CLRC;
8423       AccAXRrl1 (x);            // 0->a:x
8424
8425       CLRC;
8426       AccAXRrl1 (x);            // 0->a:x
8427
8428       break;
8429     case 3:
8430     case 4:
8431     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8432
8433       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8434
8435       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8436
8437       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8438
8439       emitcode ("anl", "a,#0x%02x",
8440                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8441
8442       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8443
8444       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8445
8446       emitcode ("anl", "a,#0x%02x",
8447                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8448
8449       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8450
8451       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8452
8453       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8454
8455       break;
8456     case 6:                     // AABBBBBB:CCDDDDDD
8457
8458       emitcode ("mov", "c,acc.7");
8459       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8460
8461       emitcode ("mov", "c,acc.7");
8462       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8463
8464       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8465
8466       emitcode ("anl", "a,#0x%02x",
8467                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8468
8469       break;
8470     case 7:                     // ABBBBBBB:CDDDDDDD
8471
8472       emitcode ("mov", "c,acc.7");      // c = A
8473
8474       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8475
8476       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8477
8478       emitcode ("anl", "a,#0x%02x",
8479                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8480
8481       break;
8482     default:
8483       break;
8484     }
8485 }
8486
8487 /*-----------------------------------------------------------------*/
8488 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8489 /*-----------------------------------------------------------------*/
8490 static void
8491 AccAXRshS (char *x, int shCount)
8492 {
8493   symbol *tlbl;
8494   switch (shCount)
8495     {
8496     case 0:
8497       break;
8498     case 1:
8499       emitcode ("mov", "c,acc.7");
8500       AccAXRrl1 (x);            // s->a:x
8501
8502       break;
8503     case 2:
8504       emitcode ("mov", "c,acc.7");
8505       AccAXRrl1 (x);            // s->a:x
8506
8507       emitcode ("mov", "c,acc.7");
8508       AccAXRrl1 (x);            // s->a:x
8509
8510       break;
8511     case 3:
8512     case 4:
8513     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8514
8515       tlbl = newiTempLabel (NULL);
8516       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8517
8518       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8519
8520       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8521
8522       emitcode ("anl", "a,#0x%02x",
8523                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8524
8525       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8526
8527       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8528
8529       emitcode ("anl", "a,#0x%02x",
8530                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8531
8532       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8533
8534       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8535
8536       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8537
8538       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8539       emitcode ("orl", "a,#0x%02x",
8540                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8541
8542       emitLabel (tlbl);
8543       break;                    // SSSSAAAA:BBBCCCCC
8544
8545     case 6:                     // AABBBBBB:CCDDDDDD
8546
8547       tlbl = newiTempLabel (NULL);
8548       emitcode ("mov", "c,acc.7");
8549       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8550
8551       emitcode ("mov", "c,acc.7");
8552       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8553
8554       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8555
8556       emitcode ("anl", "a,#0x%02x",
8557                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8558
8559       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8560       emitcode ("orl", "a,#0x%02x",
8561                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8562
8563       emitLabel (tlbl);
8564       break;
8565     case 7:                     // ABBBBBBB:CDDDDDDD
8566
8567       tlbl = newiTempLabel (NULL);
8568       emitcode ("mov", "c,acc.7");      // c = A
8569
8570       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8571
8572       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8573
8574       emitcode ("anl", "a,#0x%02x",
8575                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8576
8577       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8578       emitcode ("orl", "a,#0x%02x",
8579                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8580
8581       emitLabel (tlbl);
8582       break;
8583     default:
8584       break;
8585     }
8586 }
8587
8588 /*-----------------------------------------------------------------*/
8589 /* shiftL2Left2Result - shift left two bytes from left to result   */
8590 /*-----------------------------------------------------------------*/
8591 static void
8592 shiftL2Left2Result (operand * left, int offl,
8593                     operand * result, int offr, int shCount)
8594 {
8595   char * x;
8596   bool pushedB = FALSE;
8597   bool usedB = FALSE;
8598
8599   if (sameRegs (AOP (result), AOP (left)) &&
8600       ((offl + MSB16) == offr))
8601     {
8602       /* don't crash result[offr] */
8603       MOVA (aopGet (left, offl, FALSE, FALSE));
8604       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8605       usedB = !strncmp(x, "b", 1);
8606     }
8607   else if (aopGetUsesAcc (result, offr))
8608     {
8609       movLeft2Result (left, offl, result, offr, 0);
8610       pushedB = pushB ();
8611       usedB = TRUE;
8612       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8613       MOVA (aopGet (result, offr, FALSE, FALSE));
8614       emitcode ("xch", "a,b");
8615       x = "b";
8616     }
8617   else
8618     {
8619       movLeft2Result (left, offl, result, offr, 0);
8620       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8621       x = aopGet (result, offr, FALSE, FALSE);
8622     }
8623   /* ax << shCount (x = lsb(result)) */
8624   AccAXLsh (x, shCount);
8625   if (usedB)
8626     {
8627       emitcode ("xch", "a,b");
8628       aopPut (result, "a", offr);
8629       aopPut (result, "b", offr + MSB16);
8630       popB (pushedB);
8631     }
8632   else
8633     {
8634       aopPut (result, "a", offr + MSB16);
8635     }
8636 }
8637
8638
8639 /*-----------------------------------------------------------------*/
8640 /* shiftR2Left2Result - shift right two bytes from left to result  */
8641 /*-----------------------------------------------------------------*/
8642 static void
8643 shiftR2Left2Result (operand * left, int offl,
8644                     operand * result, int offr,
8645                     int shCount, int sign)
8646 {
8647   char * x;
8648   bool pushedB = FALSE;
8649   bool usedB = FALSE;
8650
8651   if (sameRegs (AOP (result), AOP (left)) &&
8652       ((offl + MSB16) == offr))
8653     {
8654       /* don't crash result[offr] */
8655       MOVA (aopGet (left, offl, FALSE, FALSE));
8656       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8657       usedB = !strncmp(x, "b", 1);
8658     }
8659   else if (aopGetUsesAcc (result, offr))
8660     {
8661       movLeft2Result (left, offl, result, offr, 0);
8662       pushedB = pushB ();
8663       usedB = TRUE;
8664       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8665       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8666       x = "b";
8667     }
8668   else
8669     {
8670       movLeft2Result (left, offl, result, offr, 0);
8671       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8672       x = aopGet (result, offr, FALSE, FALSE);
8673     }
8674   /* a:x >> shCount (x = lsb(result)) */
8675   if (sign)
8676     AccAXRshS (x, shCount);
8677   else
8678     AccAXRsh (x, shCount);
8679   if (usedB)
8680     {
8681       emitcode ("xch", "a,b");
8682       aopPut (result, "a", offr);
8683       emitcode ("xch", "a,b");
8684       popB (pushedB);
8685     }
8686   if (getDataSize (result) > 1)
8687     aopPut (result, "a", offr + MSB16);
8688 }
8689
8690 /*-----------------------------------------------------------------*/
8691 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8692 /*-----------------------------------------------------------------*/
8693 static void
8694 shiftLLeftOrResult (operand * left, int offl,
8695                     operand * result, int offr, int shCount)
8696 {
8697   MOVA (aopGet (left, offl, FALSE, FALSE));
8698   /* shift left accumulator */
8699   AccLsh (shCount);
8700   /* or with result */
8701   if (aopGetUsesAcc (result, offr))
8702     {
8703       emitcode ("xch", "a,b");
8704       MOVA (aopGet (result, offr, FALSE, FALSE));
8705       emitcode ("orl", "a,b");
8706     }
8707   else
8708     {
8709       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8710     }
8711   /* back to result */
8712   aopPut (result, "a", offr);
8713 }
8714
8715 /*-----------------------------------------------------------------*/
8716 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8717 /*-----------------------------------------------------------------*/
8718 static void
8719 shiftRLeftOrResult (operand * left, int offl,
8720                     operand * result, int offr, int shCount)
8721 {
8722   MOVA (aopGet (left, offl, FALSE, FALSE));
8723   /* shift right accumulator */
8724   AccRsh (shCount);
8725   /* or with result */
8726   if (aopGetUsesAcc(result, offr))
8727     {
8728       emitcode ("xch", "a,b");
8729       MOVA (aopGet (result, offr, FALSE, FALSE));
8730       emitcode ("orl", "a,b");
8731     }
8732   else
8733     {
8734       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8735     }
8736   /* back to result */
8737   aopPut (result, "a", offr);
8738 }
8739
8740 /*-----------------------------------------------------------------*/
8741 /* genlshOne - left shift a one byte quantity by known count       */
8742 /*-----------------------------------------------------------------*/
8743 static void
8744 genlshOne (operand * result, operand * left, int shCount)
8745 {
8746   D (emitcode (";", "genlshOne"));
8747
8748   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8749 }
8750
8751 /*-----------------------------------------------------------------*/
8752 /* genlshTwo - left shift two bytes by known amount != 0           */
8753 /*-----------------------------------------------------------------*/
8754 static void
8755 genlshTwo (operand * result, operand * left, int shCount)
8756 {
8757   int size;
8758
8759   D (emitcode (";", "genlshTwo"));
8760
8761   size = getDataSize (result);
8762
8763   /* if shCount >= 8 */
8764   if (shCount >= 8)
8765     {
8766       shCount -= 8;
8767
8768       if (size > 1)
8769         {
8770           if (shCount)
8771             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8772           else
8773             movLeft2Result (left, LSB, result, MSB16, 0);
8774         }
8775       aopPut (result, zero, LSB);
8776     }
8777
8778   /*  1 <= shCount <= 7 */
8779   else
8780     {
8781       if (size == 1)
8782         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8783       else
8784         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8785     }
8786 }
8787
8788 /*-----------------------------------------------------------------*/
8789 /* shiftLLong - shift left one long from left to result            */
8790 /* offl = LSB or MSB16                                             */
8791 /*-----------------------------------------------------------------*/
8792 static void
8793 shiftLLong (operand * left, operand * result, int offr)
8794 {
8795   char *l;
8796   int size = AOP_SIZE (result);
8797
8798   if (size >= LSB + offr)
8799     {
8800       l = aopGet (left, LSB, FALSE, FALSE);
8801       MOVA (l);
8802       emitcode ("add", "a,acc");
8803       if (sameRegs (AOP (left), AOP (result)) &&
8804           size >= MSB16 + offr && offr != LSB)
8805         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8806       else
8807         aopPut (result, "a", LSB + offr);
8808     }
8809
8810   if (size >= MSB16 + offr)
8811     {
8812       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8813         {
8814           l = aopGet (left, MSB16, FALSE, FALSE);
8815           MOVA (l);
8816         }
8817       emitcode ("rlc", "a");
8818       if (sameRegs (AOP (left), AOP (result)) &&
8819           size >= MSB24 + offr && offr != LSB)
8820         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8821       else
8822         aopPut (result, "a", MSB16 + offr);
8823     }
8824
8825   if (size >= MSB24 + offr)
8826     {
8827       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8828         {
8829           l = aopGet (left, MSB24, FALSE, FALSE);
8830           MOVA (l);
8831         }
8832       emitcode ("rlc", "a");
8833       if (sameRegs (AOP (left), AOP (result)) &&
8834           size >= MSB32 + offr && offr != LSB)
8835         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8836       else
8837         aopPut (result, "a", MSB24 + offr);
8838     }
8839
8840   if (size > MSB32 + offr)
8841     {
8842       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8843         {
8844           l = aopGet (left, MSB32, FALSE, FALSE);
8845           MOVA (l);
8846         }
8847       emitcode ("rlc", "a");
8848       aopPut (result, "a", MSB32 + offr);
8849     }
8850   if (offr != LSB)
8851     aopPut (result, zero, LSB);
8852 }
8853
8854 /*-----------------------------------------------------------------*/
8855 /* genlshFour - shift four byte by a known amount != 0             */
8856 /*-----------------------------------------------------------------*/
8857 static void
8858 genlshFour (operand * result, operand * left, int shCount)
8859 {
8860   int size;
8861
8862   D (emitcode (";", "genlshFour"));
8863
8864   size = AOP_SIZE (result);
8865
8866   /* if shifting more that 3 bytes */
8867   if (shCount >= 24)
8868     {
8869       shCount -= 24;
8870       if (shCount)
8871         /* lowest order of left goes to the highest
8872            order of the destination */
8873         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8874       else
8875         movLeft2Result (left, LSB, result, MSB32, 0);
8876       aopPut (result, zero, LSB);
8877       aopPut (result, zero, MSB16);
8878       aopPut (result, zero, MSB24);
8879       return;
8880     }
8881
8882   /* more than two bytes */
8883   else if (shCount >= 16)
8884     {
8885       /* lower order two bytes goes to higher order two bytes */
8886       shCount -= 16;
8887       /* if some more remaining */
8888       if (shCount)
8889         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8890       else
8891         {
8892           movLeft2Result (left, MSB16, result, MSB32, 0);
8893           movLeft2Result (left, LSB, result, MSB24, 0);
8894         }
8895       aopPut (result, zero, MSB16);
8896       aopPut (result, zero, LSB);
8897       return;
8898     }
8899
8900   /* if more than 1 byte */
8901   else if (shCount >= 8)
8902     {
8903       /* lower order three bytes goes to higher order  three bytes */
8904       shCount -= 8;
8905       if (size == 2)
8906         {
8907           if (shCount)
8908             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8909           else
8910             movLeft2Result (left, LSB, result, MSB16, 0);
8911         }
8912       else
8913         {                       /* size = 4 */
8914           if (shCount == 0)
8915             {
8916               movLeft2Result (left, MSB24, result, MSB32, 0);
8917               movLeft2Result (left, MSB16, result, MSB24, 0);
8918               movLeft2Result (left, LSB, result, MSB16, 0);
8919               aopPut (result, zero, LSB);
8920             }
8921           else if (shCount == 1)
8922             shiftLLong (left, result, MSB16);
8923           else
8924             {
8925               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8926               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8927               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8928               aopPut (result, zero, LSB);
8929             }
8930         }
8931     }
8932
8933   /* 1 <= shCount <= 7 */
8934   else if (shCount <= 2)
8935     {
8936       shiftLLong (left, result, LSB);
8937       if (shCount == 2)
8938         shiftLLong (result, result, LSB);
8939     }
8940   /* 3 <= shCount <= 7, optimize */
8941   else
8942     {
8943       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8944       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8945       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8946     }
8947 }
8948
8949 /*-----------------------------------------------------------------*/
8950 /* genLeftShiftLiteral - left shifting by known count              */
8951 /*-----------------------------------------------------------------*/
8952 static void
8953 genLeftShiftLiteral (operand * left,
8954                      operand * right,
8955                      operand * result,
8956                      iCode * ic)
8957 {
8958   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
8959   int size;
8960
8961   D (emitcode (";", "genLeftShiftLiteral"));
8962
8963   freeAsmop (right, NULL, ic, TRUE);
8964
8965   aopOp (left, ic, FALSE);
8966   aopOp (result, ic, FALSE);
8967
8968   size = getSize (operandType (result));
8969
8970 #if VIEW_SIZE
8971   emitcode ("; shift left ", "result %d, left %d", size,
8972             AOP_SIZE (left));
8973 #endif
8974
8975   /* I suppose that the left size >= result size */
8976   if (shCount == 0)
8977     {
8978       while (size--)
8979         {
8980           movLeft2Result (left, size, result, size, 0);
8981         }
8982     }
8983   else if (shCount >= (size * 8))
8984     {
8985       while (size--)
8986         {
8987           aopPut (result, zero, size);
8988         }
8989     }
8990   else
8991     {
8992       switch (size)
8993         {
8994         case 1:
8995           genlshOne (result, left, shCount);
8996           break;
8997
8998         case 2:
8999           genlshTwo (result, left, shCount);
9000           break;
9001
9002         case 4:
9003           genlshFour (result, left, shCount);
9004           break;
9005         default:
9006           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9007                   "*** ack! mystery literal shift!\n");
9008           break;
9009         }
9010     }
9011   freeAsmop (result, NULL, ic, TRUE);
9012   freeAsmop (left, NULL, ic, TRUE);
9013 }
9014
9015 /*-----------------------------------------------------------------*/
9016 /* genLeftShift - generates code for left shifting                 */
9017 /*-----------------------------------------------------------------*/
9018 static void
9019 genLeftShift (iCode * ic)
9020 {
9021   operand *left, *right, *result;
9022   int size, offset;
9023   char *l;
9024   symbol *tlbl, *tlbl1;
9025   bool pushedB;
9026
9027   D (emitcode (";", "genLeftShift"));
9028
9029   right = IC_RIGHT (ic);
9030   left = IC_LEFT (ic);
9031   result = IC_RESULT (ic);
9032
9033   aopOp (right, ic, FALSE);
9034
9035   /* if the shift count is known then do it
9036      as efficiently as possible */
9037   if (AOP_TYPE (right) == AOP_LIT)
9038     {
9039       genLeftShiftLiteral (left, right, result, ic);
9040       return;
9041     }
9042
9043   /* shift count is unknown then we have to form
9044      a loop get the loop count in B : Note: we take
9045      only the lower order byte since shifting
9046      more that 32 bits make no sense anyway, ( the
9047      largest size of an object can be only 32 bits ) */
9048
9049   pushedB = pushB ();
9050   MOVB (aopGet (right, 0, FALSE, FALSE));
9051   emitcode ("inc", "b");
9052   freeAsmop (right, NULL, ic, TRUE);
9053   aopOp (left, ic, FALSE);
9054   aopOp (result, ic, FALSE);
9055
9056   /* now move the left to the result if they are not the same */
9057   if (!sameRegs (AOP (left), AOP (result)) &&
9058       AOP_SIZE (result) > 1)
9059     {
9060
9061       size = AOP_SIZE (result);
9062       offset = 0;
9063       while (size--)
9064         {
9065           l = aopGet (left, offset, FALSE, TRUE);
9066           if (*l == '@' && (IS_AOP_PREG (result)))
9067             {
9068
9069               emitcode ("mov", "a,%s", l);
9070               aopPut (result, "a", offset);
9071             }
9072           else
9073             aopPut (result, l, offset);
9074           offset++;
9075         }
9076     }
9077
9078   tlbl = newiTempLabel (NULL);
9079   size = AOP_SIZE (result);
9080   offset = 0;
9081   tlbl1 = newiTempLabel (NULL);
9082
9083   /* if it is only one byte then */
9084   if (size == 1)
9085     {
9086       symbol *tlbl1 = newiTempLabel (NULL);
9087
9088       l = aopGet (left, 0, FALSE, FALSE);
9089       MOVA (l);
9090       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9091       emitLabel (tlbl);
9092       emitcode ("add", "a,acc");
9093       emitLabel (tlbl1);
9094       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9095       popB (pushedB);
9096       aopPut (result, "a", 0);
9097       goto release;
9098     }
9099
9100   reAdjustPreg (AOP (result));
9101
9102   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9103   emitLabel (tlbl);
9104   l = aopGet (result, offset, FALSE, FALSE);
9105   MOVA (l);
9106   emitcode ("add", "a,acc");
9107   aopPut (result, "a", offset++);
9108   while (--size)
9109     {
9110       l = aopGet (result, offset, FALSE, FALSE);
9111       MOVA (l);
9112       emitcode ("rlc", "a");
9113       aopPut (result, "a", offset++);
9114     }
9115   reAdjustPreg (AOP (result));
9116
9117   emitLabel (tlbl1);
9118   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9119   popB (pushedB);
9120 release:
9121   freeAsmop (result, NULL, ic, TRUE);
9122   freeAsmop (left, NULL, ic, TRUE);
9123 }
9124
9125 /*-----------------------------------------------------------------*/
9126 /* genrshOne - right shift a one byte quantity by known count      */
9127 /*-----------------------------------------------------------------*/
9128 static void
9129 genrshOne (operand * result, operand * left,
9130            int shCount, int sign)
9131 {
9132   D (emitcode (";", "genrshOne"));
9133
9134   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9135 }
9136
9137 /*-----------------------------------------------------------------*/
9138 /* genrshTwo - right shift two bytes by known amount != 0          */
9139 /*-----------------------------------------------------------------*/
9140 static void
9141 genrshTwo (operand * result, operand * left,
9142            int shCount, int sign)
9143 {
9144   D (emitcode (";", "genrshTwo"));
9145
9146   /* if shCount >= 8 */
9147   if (shCount >= 8)
9148     {
9149       shCount -= 8;
9150       if (shCount)
9151         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9152       else
9153         movLeft2Result (left, MSB16, result, LSB, sign);
9154       addSign (result, MSB16, sign);
9155     }
9156
9157   /*  1 <= shCount <= 7 */
9158   else
9159     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9160 }
9161
9162 /*-----------------------------------------------------------------*/
9163 /* shiftRLong - shift right one long from left to result           */
9164 /* offl = LSB or MSB16                                             */
9165 /*-----------------------------------------------------------------*/
9166 static void
9167 shiftRLong (operand * left, int offl,
9168             operand * result, int sign)
9169 {
9170   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9171
9172   if (overlapping && offl>1)
9173     {
9174       // we are in big trouble, but this shouldn't happen
9175       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9176     }
9177
9178   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9179
9180   if (offl==MSB16)
9181     {
9182       // shift is > 8
9183       if (sign)
9184         {
9185           emitcode ("rlc", "a");
9186           emitcode ("subb", "a,acc");
9187           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9188             {
9189               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9190             }
9191           else
9192             {
9193               aopPut (result, "a", MSB32);
9194               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9195             }
9196         }
9197       else
9198         {
9199           if (aopPutUsesAcc (result, zero, MSB32))
9200             {
9201               emitcode("xch", "a,b");
9202               aopPut (result, zero, MSB32);
9203               emitcode("xch", "a,b");
9204             }
9205           else
9206             {
9207               aopPut (result, zero, MSB32);
9208             }
9209         }
9210     }
9211
9212   if (!sign)
9213     {
9214       emitcode ("clr", "c");
9215     }
9216   else
9217     {
9218       emitcode ("mov", "c,acc.7");
9219     }
9220
9221   emitcode ("rrc", "a");
9222
9223   if (overlapping && offl==MSB16 &&
9224       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9225     {
9226       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9227     }
9228   else
9229     {
9230       aopPut (result, "a", MSB32 - offl);
9231       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9232     }
9233
9234   emitcode ("rrc", "a");
9235   if (overlapping && offl==MSB16 &&
9236       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9237     {
9238       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9239     }
9240   else
9241     {
9242       aopPut (result, "a", MSB24 - offl);
9243       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9244     }
9245
9246   emitcode ("rrc", "a");
9247   if (offl != LSB)
9248     {
9249       aopPut (result, "a", MSB16 - offl);
9250     }
9251   else
9252     {
9253       if (overlapping &&
9254           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9255         {
9256           xch_a_aopGet (left, LSB, FALSE, FALSE);
9257         }
9258       else
9259         {
9260           aopPut (result, "a", MSB16 - offl);
9261           MOVA (aopGet (left, LSB, FALSE, FALSE));
9262         }
9263       emitcode ("rrc", "a");
9264       aopPut (result, "a", LSB);
9265     }
9266 }
9267
9268 /*-----------------------------------------------------------------*/
9269 /* genrshFour - shift four byte by a known amount != 0             */
9270 /*-----------------------------------------------------------------*/
9271 static void
9272 genrshFour (operand * result, operand * left,
9273             int shCount, int sign)
9274 {
9275   D (emitcode (";", "genrshFour"));
9276
9277   /* if shifting more that 3 bytes */
9278   if (shCount >= 24)
9279     {
9280       shCount -= 24;
9281       if (shCount)
9282         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9283       else
9284         movLeft2Result (left, MSB32, result, LSB, sign);
9285       addSign (result, MSB16, sign);
9286     }
9287   else if (shCount >= 16)
9288     {
9289       shCount -= 16;
9290       if (shCount)
9291         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9292       else
9293         {
9294           movLeft2Result (left, MSB24, result, LSB, 0);
9295           movLeft2Result (left, MSB32, result, MSB16, sign);
9296         }
9297       addSign (result, MSB24, sign);
9298     }
9299   else if (shCount >= 8)
9300     {
9301       shCount -= 8;
9302       if (shCount == 1)
9303         {
9304           shiftRLong (left, MSB16, result, sign);
9305         }
9306       else if (shCount == 0)
9307         {
9308           movLeft2Result (left, MSB16, result, LSB, 0);
9309           movLeft2Result (left, MSB24, result, MSB16, 0);
9310           movLeft2Result (left, MSB32, result, MSB24, sign);
9311           addSign (result, MSB32, sign);
9312         }
9313       else
9314         {
9315           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9316           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9317           /* the last shift is signed */
9318           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9319           addSign (result, MSB32, sign);
9320         }
9321     }
9322   else
9323     {
9324       /* 1 <= shCount <= 7 */
9325       if (shCount <= 2)
9326         {
9327           shiftRLong (left, LSB, result, sign);
9328           if (shCount == 2)
9329             shiftRLong (result, LSB, result, sign);
9330         }
9331       else
9332         {
9333           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9334           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9335           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9336         }
9337     }
9338 }
9339
9340 /*-----------------------------------------------------------------*/
9341 /* genRightShiftLiteral - right shifting by known count            */
9342 /*-----------------------------------------------------------------*/
9343 static void
9344 genRightShiftLiteral (operand * left,
9345                       operand * right,
9346                       operand * result,
9347                       iCode * ic,
9348                       int sign)
9349 {
9350   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9351   int size;
9352
9353   D (emitcode (";", "genRightShiftLiteral"));
9354
9355   freeAsmop (right, NULL, ic, TRUE);
9356
9357   aopOp (left, ic, FALSE);
9358   aopOp (result, ic, FALSE);
9359
9360 #if VIEW_SIZE
9361   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9362             AOP_SIZE (left));
9363 #endif
9364
9365   size = getDataSize (left);
9366   /* test the LEFT size !!! */
9367
9368   /* I suppose that the left size >= result size */
9369   if (shCount == 0)
9370     {
9371       size = getDataSize (result);
9372       while (size--)
9373         movLeft2Result (left, size, result, size, 0);
9374     }
9375
9376   else if (shCount >= (size * 8))
9377     {
9378       if (sign)
9379         {
9380           /* get sign in acc.7 */
9381           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9382         }
9383       addSign (result, LSB, sign);
9384     }
9385   else
9386     {
9387       switch (size)
9388         {
9389         case 1:
9390           genrshOne (result, left, shCount, sign);
9391           break;
9392
9393         case 2:
9394           genrshTwo (result, left, shCount, sign);
9395           break;
9396
9397         case 4:
9398           genrshFour (result, left, shCount, sign);
9399           break;
9400         default:
9401           break;
9402         }
9403     }
9404   freeAsmop (result, NULL, ic, TRUE);
9405   freeAsmop (left, NULL, ic, TRUE);
9406 }
9407
9408 /*-----------------------------------------------------------------*/
9409 /* genSignedRightShift - right shift of signed number              */
9410 /*-----------------------------------------------------------------*/
9411 static void
9412 genSignedRightShift (iCode * ic)
9413 {
9414   operand *right, *left, *result;
9415   int size, offset;
9416   char *l;
9417   symbol *tlbl, *tlbl1;
9418   bool pushedB;
9419
9420   D (emitcode (";", "genSignedRightShift"));
9421
9422   /* we do it the hard way put the shift count in b
9423      and loop thru preserving the sign */
9424
9425   right = IC_RIGHT (ic);
9426   left = IC_LEFT (ic);
9427   result = IC_RESULT (ic);
9428
9429   aopOp (right, ic, FALSE);
9430
9431
9432   if (AOP_TYPE (right) == AOP_LIT)
9433     {
9434       genRightShiftLiteral (left, right, result, ic, 1);
9435       return;
9436     }
9437   /* shift count is unknown then we have to form
9438      a loop get the loop count in B : Note: we take
9439      only the lower order byte since shifting
9440      more that 32 bits make no sense anyway, ( the
9441      largest size of an object can be only 32 bits ) */
9442
9443   pushedB = pushB ();
9444   MOVB (aopGet (right, 0, FALSE, FALSE));
9445   emitcode ("inc", "b");
9446   freeAsmop (right, NULL, ic, TRUE);
9447   aopOp (left, ic, FALSE);
9448   aopOp (result, ic, FALSE);
9449
9450   /* now move the left to the result if they are not the
9451      same */
9452   if (!sameRegs (AOP (left), AOP (result)) &&
9453       AOP_SIZE (result) > 1)
9454     {
9455
9456       size = AOP_SIZE (result);
9457       offset = 0;
9458       while (size--)
9459         {
9460           l = aopGet (left, offset, FALSE, TRUE);
9461           if (*l == '@' && IS_AOP_PREG (result))
9462             {
9463
9464               emitcode ("mov", "a,%s", l);
9465               aopPut (result, "a", offset);
9466             }
9467           else
9468             aopPut (result, l, offset);
9469           offset++;
9470         }
9471     }
9472
9473   /* mov the highest order bit to OVR */
9474   tlbl = newiTempLabel (NULL);
9475   tlbl1 = newiTempLabel (NULL);
9476
9477   size = AOP_SIZE (result);
9478   offset = size - 1;
9479   MOVA (aopGet (left, offset, FALSE, FALSE));
9480   emitcode ("rlc", "a");
9481   emitcode ("mov", "ov,c");
9482   /* if it is only one byte then */
9483   if (size == 1)
9484     {
9485       l = aopGet (left, 0, FALSE, FALSE);
9486       MOVA (l);
9487       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9488       emitLabel (tlbl);
9489       emitcode ("mov", "c,ov");
9490       emitcode ("rrc", "a");
9491       emitLabel (tlbl1);
9492       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9493       popB (pushedB);
9494       aopPut (result, "a", 0);
9495       goto release;
9496     }
9497
9498   reAdjustPreg (AOP (result));
9499   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9500   emitLabel (tlbl);
9501   emitcode ("mov", "c,ov");
9502   while (size--)
9503     {
9504       l = aopGet (result, offset, FALSE, FALSE);
9505       MOVA (l);
9506       emitcode ("rrc", "a");
9507       aopPut (result, "a", offset--);
9508     }
9509   reAdjustPreg (AOP (result));
9510   emitLabel (tlbl1);
9511   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9512   popB (pushedB);
9513
9514 release:
9515   freeAsmop (result, NULL, ic, TRUE);
9516   freeAsmop (left, NULL, ic, TRUE);
9517 }
9518
9519 /*-----------------------------------------------------------------*/
9520 /* genRightShift - generate code for right shifting                */
9521 /*-----------------------------------------------------------------*/
9522 static void
9523 genRightShift (iCode * ic)
9524 {
9525   operand *right, *left, *result;
9526   sym_link *letype;
9527   int size, offset;
9528   char *l;
9529   symbol *tlbl, *tlbl1;
9530   bool pushedB;
9531
9532   D (emitcode (";", "genRightShift"));
9533
9534   /* if signed then we do it the hard way preserve the
9535      sign bit moving it inwards */
9536   letype = getSpec (operandType (IC_LEFT (ic)));
9537
9538   if (!SPEC_USIGN (letype))
9539     {
9540       genSignedRightShift (ic);
9541       return;
9542     }
9543
9544   /* signed & unsigned types are treated the same : i.e. the
9545      signed is NOT propagated inwards : quoting from the
9546      ANSI - standard : "for E1 >> E2, is equivalent to division
9547      by 2**E2 if unsigned or if it has a non-negative value,
9548      otherwise the result is implementation defined ", MY definition
9549      is that the sign does not get propagated */
9550
9551   right = IC_RIGHT (ic);
9552   left = IC_LEFT (ic);
9553   result = IC_RESULT (ic);
9554
9555   aopOp (right, ic, FALSE);
9556
9557   /* if the shift count is known then do it
9558      as efficiently as possible */
9559   if (AOP_TYPE (right) == AOP_LIT)
9560     {
9561       genRightShiftLiteral (left, right, result, ic, 0);
9562       return;
9563     }
9564
9565   /* shift count is unknown then we have to form
9566      a loop get the loop count in B : Note: we take
9567      only the lower order byte since shifting
9568      more that 32 bits make no sense anyway, ( the
9569      largest size of an object can be only 32 bits ) */
9570
9571   pushedB = pushB ();
9572   MOVB (aopGet (right, 0, FALSE, FALSE));
9573   emitcode ("inc", "b");
9574   freeAsmop (right, NULL, ic, TRUE);
9575   aopOp (left, ic, FALSE);
9576   aopOp (result, ic, FALSE);
9577
9578   /* now move the left to the result if they are not the
9579      same */
9580   if (!sameRegs (AOP (left), AOP (result)) &&
9581       AOP_SIZE (result) > 1)
9582     {
9583       size = AOP_SIZE (result);
9584       offset = 0;
9585       while (size--)
9586         {
9587           l = aopGet (left, offset, FALSE, TRUE);
9588           if (*l == '@' && IS_AOP_PREG (result))
9589             {
9590
9591               emitcode ("mov", "a,%s", l);
9592               aopPut (result, "a", offset);
9593             }
9594           else
9595             aopPut (result, l, offset);
9596           offset++;
9597         }
9598     }
9599
9600   tlbl = newiTempLabel (NULL);
9601   tlbl1 = newiTempLabel (NULL);
9602   size = AOP_SIZE (result);
9603   offset = size - 1;
9604
9605   /* if it is only one byte then */
9606   if (size == 1)
9607     {
9608       l = aopGet (left, 0, FALSE, FALSE);
9609       MOVA (l);
9610       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9611       emitLabel (tlbl);
9612       CLRC;
9613       emitcode ("rrc", "a");
9614       emitLabel (tlbl1);
9615       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9616       popB (pushedB);
9617       aopPut (result, "a", 0);
9618       goto release;
9619     }
9620
9621   reAdjustPreg (AOP (result));
9622   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9623   emitLabel (tlbl);
9624   CLRC;
9625   while (size--)
9626     {
9627       l = aopGet (result, offset, FALSE, FALSE);
9628       MOVA (l);
9629       emitcode ("rrc", "a");
9630       aopPut (result, "a", offset--);
9631     }
9632   reAdjustPreg (AOP (result));
9633
9634   emitLabel (tlbl1);
9635   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9636   popB (pushedB);
9637
9638 release:
9639   freeAsmop (result, NULL, ic, TRUE);
9640   freeAsmop (left, NULL, ic, TRUE);
9641 }
9642
9643 /*-----------------------------------------------------------------*/
9644 /* emitPtrByteGet - emits code to get a byte into A through a      */
9645 /*                  pointer register (R0, R1, or DPTR). The        */
9646 /*                  original value of A can be preserved in B.     */
9647 /*-----------------------------------------------------------------*/
9648 static void
9649 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9650 {
9651   switch (p_type)
9652     {
9653     case IPOINTER:
9654     case POINTER:
9655       if (preserveAinB)
9656         emitcode ("mov", "b,a");
9657       emitcode ("mov", "a,@%s", rname);
9658       break;
9659
9660     case PPOINTER:
9661       if (preserveAinB)
9662         emitcode ("mov", "b,a");
9663       emitcode ("movx", "a,@%s", rname);
9664       break;
9665
9666     case FPOINTER:
9667       if (preserveAinB)
9668         emitcode ("mov", "b,a");
9669       emitcode ("movx", "a,@dptr");
9670       break;
9671
9672     case CPOINTER:
9673       if (preserveAinB)
9674         emitcode ("mov", "b,a");
9675       emitcode ("clr", "a");
9676       emitcode ("movc", "a,@a+dptr");
9677       break;
9678
9679     case GPOINTER:
9680       if (preserveAinB)
9681         {
9682           emitcode ("push", "b");
9683           emitcode ("push", "acc");
9684         }
9685       emitcode ("lcall", "__gptrget");
9686       if (preserveAinB)
9687         emitcode ("pop", "b");
9688       break;
9689     }
9690 }
9691
9692 /*-----------------------------------------------------------------*/
9693 /* emitPtrByteSet - emits code to set a byte from src through a    */
9694 /*                  pointer register (R0, R1, or DPTR).            */
9695 /*-----------------------------------------------------------------*/
9696 static void
9697 emitPtrByteSet (char *rname, int p_type, char *src)
9698 {
9699   switch (p_type)
9700     {
9701     case IPOINTER:
9702     case POINTER:
9703       if (*src=='@')
9704         {
9705           MOVA (src);
9706           emitcode ("mov", "@%s,a", rname);
9707         }
9708       else
9709         emitcode ("mov", "@%s,%s", rname, src);
9710       break;
9711
9712     case PPOINTER:
9713       MOVA (src);
9714       emitcode ("movx", "@%s,a", rname);
9715       break;
9716
9717     case FPOINTER:
9718       MOVA (src);
9719       emitcode ("movx", "@dptr,a");
9720       break;
9721
9722     case GPOINTER:
9723       MOVA (src);
9724       emitcode ("lcall", "__gptrput");
9725       break;
9726     }
9727 }
9728
9729 /*-----------------------------------------------------------------*/
9730 /* genUnpackBits - generates code for unpacking bits               */
9731 /*-----------------------------------------------------------------*/
9732 static char*
9733 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9734 {
9735   int offset = 0;       /* result byte offset */
9736   int rsize;            /* result size */
9737   int rlen = 0;         /* remaining bitfield length */
9738   sym_link *etype;      /* bitfield type information */
9739   int blen;             /* bitfield length */
9740   int bstr;             /* bitfield starting bit within byte */
9741   static char* const accBits[] = {"acc.0", "acc.1", "acc.2", "acc.3",
9742                                   "acc.4", "acc.5", "acc.6", "acc.7"};
9743
9744   D(emitcode (";", "genUnpackBits"));
9745
9746   etype = getSpec (operandType (result));
9747   rsize = getSize (operandType (result));
9748   blen = SPEC_BLEN (etype);
9749   bstr = SPEC_BSTR (etype);
9750
9751   if (ifx && blen <= 8)
9752     {
9753       emitPtrByteGet (rname, ptype, FALSE);
9754       if (blen == 1)
9755         {
9756           return accBits[bstr];;
9757         }
9758       else
9759         {
9760           if (blen < 8)
9761             emitcode ("anl", "a,#0x%02x",
9762                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9763           return "a";
9764         }
9765     }
9766   wassert (!ifx);
9767
9768   /* If the bitfield length is less than a byte */
9769   if (blen < 8)
9770     {
9771       emitPtrByteGet (rname, ptype, FALSE);
9772       AccRol (8 - bstr);
9773       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9774       if (!SPEC_USIGN (etype))
9775         {
9776           /* signed bitfield */
9777           symbol *tlbl = newiTempLabel (NULL);
9778
9779           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9780           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9781           emitLabel (tlbl);
9782         }
9783       aopPut (result, "a", offset++);
9784       goto finish;
9785     }
9786
9787   /* Bit field did not fit in a byte. Copy all
9788      but the partial byte at the end.  */
9789   for (rlen=blen;rlen>=8;rlen-=8)
9790     {
9791       emitPtrByteGet (rname, ptype, FALSE);
9792       aopPut (result, "a", offset++);
9793       if (rlen>8)
9794         emitcode ("inc", "%s", rname);
9795     }
9796
9797   /* Handle the partial byte at the end */
9798   if (rlen)
9799     {
9800       emitPtrByteGet (rname, ptype, FALSE);
9801       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9802       if (!SPEC_USIGN (etype))
9803         {
9804           /* signed bitfield */
9805           symbol *tlbl = newiTempLabel (NULL);
9806
9807           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9808           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9809           emitLabel (tlbl);
9810         }
9811       aopPut (result, "a", offset++);
9812     }
9813
9814 finish:
9815   if (offset < rsize)
9816     {
9817       char *source;
9818
9819       if (SPEC_USIGN (etype))
9820         source = zero;
9821       else
9822         {
9823           /* signed bitfield: sign extension with 0x00 or 0xff */
9824           emitcode ("rlc", "a");
9825           emitcode ("subb", "a,acc");
9826
9827           source = "a";
9828         }
9829       rsize -= offset;
9830       while (rsize--)
9831         aopPut (result, source, offset++);
9832     }
9833   return NULL;
9834 }
9835
9836
9837 /*-----------------------------------------------------------------*/
9838 /* genDataPointerGet - generates code when ptr offset is known     */
9839 /*-----------------------------------------------------------------*/
9840 static void
9841 genDataPointerGet (operand * left,
9842                    operand * result,
9843                    iCode * ic)
9844 {
9845   char *l;
9846   char buffer[256];
9847   int size, offset = 0;
9848
9849   D (emitcode (";", "genDataPointerGet"));
9850
9851   aopOp (result, ic, TRUE);
9852
9853   /* get the string representation of the name */
9854   l = aopGet (left, 0, FALSE, TRUE);
9855   l++; // remove #
9856   size = AOP_SIZE (result);
9857   while (size--)
9858     {
9859       if (offset)
9860         {
9861           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9862         }
9863       else
9864         {
9865           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9866         }
9867       aopPut (result, buffer, offset++);
9868     }
9869
9870   freeAsmop (result, NULL, ic, TRUE);
9871   freeAsmop (left, NULL, ic, TRUE);
9872 }
9873
9874 /*-----------------------------------------------------------------*/
9875 /* genNearPointerGet - emitcode for near pointer fetch             */
9876 /*-----------------------------------------------------------------*/
9877 static void
9878 genNearPointerGet (operand * left,
9879                    operand * result,
9880                    iCode * ic,
9881                    iCode * pi,
9882                    iCode * ifx)
9883 {
9884   asmop *aop = NULL;
9885   regs *preg = NULL;
9886   char *rname;
9887   char *ifxCond = "a";
9888   sym_link *rtype, *retype;
9889   sym_link *ltype = operandType (left);
9890
9891   D (emitcode (";", "genNearPointerGet"));
9892
9893   rtype = operandType (result);
9894   retype = getSpec (rtype);
9895
9896   aopOp (left, ic, FALSE);
9897
9898   /* if left is rematerialisable and
9899      result is not bitfield variable type and
9900      the left is pointer to data space i.e
9901      lower 128 bytes of space */
9902   if (AOP_TYPE (left) == AOP_IMMD &&
9903       !IS_BITFIELD (retype) &&
9904       DCL_TYPE (ltype) == POINTER)
9905     {
9906       genDataPointerGet (left, result, ic);
9907       return;
9908     }
9909
9910   //aopOp (result, ic, FALSE);
9911   aopOp (result, ic, result?TRUE:FALSE);
9912
9913  /* if the value is already in a pointer register
9914      then don't need anything more */
9915   if (!AOP_INPREG (AOP (left)))
9916     {
9917       if (IS_AOP_PREG (left))
9918         {
9919           // Aha, it is a pointer, just in disguise.
9920           rname = aopGet (left, 0, FALSE, FALSE);
9921           if (*rname != '@')
9922             {
9923               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9924                       __FILE__, __LINE__);
9925             }
9926           else
9927             {
9928               // Expected case.
9929               emitcode ("mov", "a%s,%s", rname + 1, rname);
9930               rname++;  // skip the '@'.
9931             }
9932         }
9933       else
9934         {
9935           /* otherwise get a free pointer register */
9936           aop = newAsmop (0);
9937           preg = getFreePtr (ic, &aop, FALSE);
9938           emitcode ("mov", "%s,%s",
9939                     preg->name,
9940                     aopGet (left, 0, FALSE, TRUE));
9941           rname = preg->name;
9942         }
9943     }
9944   else
9945     rname = aopGet (left, 0, FALSE, FALSE);
9946
9947   /* if bitfield then unpack the bits */
9948   if (IS_BITFIELD (retype))
9949     ifxCond = genUnpackBits (result, rname, POINTER, ifx);
9950   else
9951     {
9952       /* we have can just get the values */
9953       int size = AOP_SIZE (result);
9954       int offset = 0;
9955
9956       while (size--)
9957         {
9958           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9959             {
9960
9961               emitcode ("mov", "a,@%s", rname);
9962               if (!ifx)
9963                 aopPut (result, "a", offset);
9964             }
9965           else
9966             {
9967               char buffer[80];
9968
9969               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9970               aopPut (result, buffer, offset);
9971             }
9972           offset++;
9973           if (size || pi)
9974             emitcode ("inc", "%s", rname);
9975         }
9976     }
9977
9978   /* now some housekeeping stuff */
9979   if (aop)       /* we had to allocate for this iCode */
9980     {
9981       if (pi) { /* post increment present */
9982         aopPut (left, rname, 0);
9983       }
9984       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9985     }
9986   else
9987     {
9988       /* we did not allocate which means left
9989          already in a pointer register, then
9990          if size > 0 && this could be used again
9991          we have to point it back to where it
9992          belongs */
9993       if ((AOP_SIZE (result) > 1 &&
9994            !OP_SYMBOL (left)->remat &&
9995            (OP_SYMBOL (left)->liveTo > ic->seq ||
9996             ic->depth)) &&
9997           !pi)
9998         {
9999           int size = AOP_SIZE (result) - 1;
10000           while (size--)
10001             emitcode ("dec", "%s", rname);
10002         }
10003     }
10004
10005   if (ifx && !ifx->generated)
10006     {
10007       genIfxJump (ifx, ifxCond, left, NULL, result);
10008     }
10009
10010   /* done */
10011   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10012   freeAsmop (left, NULL, ic, TRUE);
10013   if (pi) pi->generated = 1;
10014 }
10015
10016 /*-----------------------------------------------------------------*/
10017 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10018 /*-----------------------------------------------------------------*/
10019 static void
10020 genPagedPointerGet (operand * left,
10021                     operand * result,
10022                     iCode * ic,
10023                     iCode *pi,
10024                     iCode *ifx)
10025 {
10026   asmop *aop = NULL;
10027   regs *preg = NULL;
10028   char *rname;
10029   char *ifxCond = "a";
10030   sym_link *rtype, *retype;
10031
10032   D (emitcode (";", "genPagedPointerGet"));
10033
10034   rtype = operandType (result);
10035   retype = getSpec (rtype);
10036
10037   aopOp (left, ic, FALSE);
10038
10039   aopOp (result, ic, FALSE);
10040
10041   /* if the value is already in a pointer register
10042      then don't need anything more */
10043   if (!AOP_INPREG (AOP (left)))
10044     {
10045       /* otherwise get a free pointer register */
10046       aop = newAsmop (0);
10047       preg = getFreePtr (ic, &aop, FALSE);
10048       emitcode ("mov", "%s,%s",
10049                 preg->name,
10050                 aopGet (left, 0, FALSE, TRUE));
10051       rname = preg->name;
10052     }
10053   else
10054     rname = aopGet (left, 0, FALSE, FALSE);
10055
10056   /* if bitfield then unpack the bits */
10057   if (IS_BITFIELD (retype))
10058     ifxCond = genUnpackBits (result, rname, PPOINTER, ifx);
10059   else
10060     {
10061       /* we have can just get the values */
10062       int size = AOP_SIZE (result);
10063       int offset = 0;
10064
10065       while (size--)
10066         {
10067
10068           emitcode ("movx", "a,@%s", rname);
10069           if (!ifx)
10070             aopPut (result, "a", offset);
10071
10072           offset++;
10073
10074           if (size || pi)
10075             emitcode ("inc", "%s", rname);
10076         }
10077     }
10078
10079   /* now some housekeeping stuff */
10080   if (aop) /* we had to allocate for this iCode */
10081     {
10082       if (pi)
10083         aopPut (left, rname, 0);
10084       freeAsmop (NULL, aop, ic, TRUE);
10085     }
10086   else
10087     {
10088       /* we did not allocate which means left
10089          already in a pointer register, then
10090          if size > 0 && this could be used again
10091          we have to point it back to where it
10092          belongs */
10093       if ((AOP_SIZE (result) > 1 &&
10094            !OP_SYMBOL (left)->remat &&
10095            (OP_SYMBOL (left)->liveTo > ic->seq ||
10096             ic->depth)) &&
10097           !pi)
10098         {
10099           int size = AOP_SIZE (result) - 1;
10100           while (size--)
10101             emitcode ("dec", "%s", rname);
10102         }
10103     }
10104
10105   if (ifx && !ifx->generated)
10106     {
10107       genIfxJump (ifx, ifxCond, left, NULL, result);
10108     }
10109
10110   /* done */
10111   freeAsmop (result, NULL, ic, TRUE);
10112   freeAsmop (left, NULL, ic, TRUE);
10113   if (pi) pi->generated = 1;
10114 }
10115
10116 /*--------------------------------------------------------------------*/
10117 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10118 /*--------------------------------------------------------------------*/
10119 static void
10120 loadDptrFromOperand (operand *op, bool loadBToo)
10121 {
10122   if (AOP_TYPE (op) != AOP_STR)
10123     {
10124       /* if this is rematerializable */
10125       if (AOP_TYPE (op) == AOP_IMMD)
10126         {
10127           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10128           if (loadBToo)
10129             {
10130               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10131                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10132               else
10133                 {
10134                   wassertl(FALSE, "need pointerCode");
10135                   emitcode (";", "mov b,???");
10136                   /* genPointerGet and genPointerSet originally did different
10137                   ** things for this case. Both seem wrong.
10138                   ** from genPointerGet:
10139                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10140                   ** from genPointerSet:
10141                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10142                   */
10143                 }
10144             }
10145         }
10146       else if (AOP_TYPE (op) == AOP_DPTR)
10147         {
10148           if (loadBToo)
10149             {
10150               MOVA (aopGet (op, 0, FALSE, FALSE));
10151               emitcode ("push", "acc");
10152               MOVA (aopGet (op, 1, FALSE, FALSE));
10153               emitcode ("push", "acc");
10154               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10155               emitcode ("pop", "dph");
10156               emitcode ("pop", "dpl");
10157             }
10158           else
10159             {
10160               MOVA (aopGet (op, 0, FALSE, FALSE));
10161               emitcode ("push", "acc");
10162               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10163               emitcode ("pop", "dpl");
10164             }
10165         }
10166       else
10167         {                       /* we need to get it byte by byte */
10168           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10169           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10170           if (loadBToo)
10171             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10172         }
10173     }
10174 }
10175
10176 /*-----------------------------------------------------------------*/
10177 /* genFarPointerGet - get value from far space                     */
10178 /*-----------------------------------------------------------------*/
10179 static void
10180 genFarPointerGet (operand * left,
10181                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10182 {
10183   int size, offset;
10184   char *ifxCond = "a";
10185   sym_link *retype = getSpec (operandType (result));
10186
10187   D (emitcode (";", "genFarPointerGet"));
10188
10189   aopOp (left, ic, FALSE);
10190   loadDptrFromOperand (left, FALSE);
10191
10192   /* so dptr now contains the address */
10193   aopOp (result, ic, FALSE);
10194
10195   /* if bit then unpack */
10196   if (IS_BITFIELD (retype))
10197     ifxCond = genUnpackBits (result, "dptr", FPOINTER, ifx);
10198   else
10199     {
10200       size = AOP_SIZE (result);
10201       offset = 0;
10202
10203       while (size--)
10204         {
10205           emitcode ("movx", "a,@dptr");
10206           if (!ifx)
10207             aopPut (result, "a", offset++);
10208           if (size || pi)
10209             emitcode ("inc", "dptr");
10210         }
10211     }
10212
10213   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10214     {
10215       aopPut (left, "dpl", 0);
10216       aopPut (left, "dph", 1);
10217       pi->generated = 1;
10218     }
10219
10220   if (ifx && !ifx->generated)
10221     {
10222       genIfxJump (ifx, ifxCond, left, NULL, result);
10223     }
10224
10225   freeAsmop (result, NULL, ic, TRUE);
10226   freeAsmop (left, NULL, ic, TRUE);
10227 }
10228
10229 /*-----------------------------------------------------------------*/
10230 /* genCodePointerGet - get value from code space                   */
10231 /*-----------------------------------------------------------------*/
10232 static void
10233 genCodePointerGet (operand * left,
10234                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10235 {
10236   int size, offset;
10237   char *ifxCond = "a";
10238   sym_link *retype = getSpec (operandType (result));
10239
10240   D (emitcode (";", "genCodePointerGet"));
10241
10242   aopOp (left, ic, FALSE);
10243   loadDptrFromOperand (left, FALSE);
10244
10245   /* so dptr now contains the address */
10246   aopOp (result, ic, FALSE);
10247
10248   /* if bit then unpack */
10249   if (IS_BITFIELD (retype))
10250     ifxCond = genUnpackBits (result, "dptr", CPOINTER, ifx);
10251   else
10252     {
10253       size = AOP_SIZE (result);
10254       offset = 0;
10255
10256       while (size--)
10257         {
10258           emitcode ("clr", "a");
10259           emitcode ("movc", "a,@a+dptr");
10260           if (!ifx)
10261             aopPut (result, "a", offset++);
10262           if (size || pi)
10263             emitcode ("inc", "dptr");
10264         }
10265     }
10266
10267   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10268     {
10269       aopPut (left, "dpl", 0);
10270       aopPut (left, "dph", 1);
10271       pi->generated = 1;
10272     }
10273
10274   if (ifx && !ifx->generated)
10275     {
10276       genIfxJump (ifx, ifxCond, left, NULL, result);
10277     }
10278
10279   freeAsmop (result, NULL, ic, TRUE);
10280   freeAsmop (left, NULL, ic, TRUE);
10281 }
10282
10283 /*-----------------------------------------------------------------*/
10284 /* genGenPointerGet - get value from generic pointer space         */
10285 /*-----------------------------------------------------------------*/
10286 static void
10287 genGenPointerGet (operand * left,
10288                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10289 {
10290   int size, offset;
10291   char *ifxCond = "a";
10292   sym_link *retype = getSpec (operandType (result));
10293
10294   D (emitcode (";", "genGenPointerGet"));
10295
10296   aopOp (left, ic, FALSE);
10297   loadDptrFromOperand (left, TRUE);
10298
10299   /* so dptr now contains the address */
10300   aopOp (result, ic, FALSE);
10301
10302   /* if bit then unpack */
10303   if (IS_BITFIELD (retype))
10304     {
10305       ifxCond = genUnpackBits (result, "dptr", GPOINTER, ifx);
10306     }
10307   else
10308     {
10309       size = AOP_SIZE (result);
10310       offset = 0;
10311
10312       while (size--)
10313         {
10314           emitcode ("lcall", "__gptrget");
10315           if (!ifx)
10316             aopPut (result, "a", offset++);
10317           if (size || pi)
10318             emitcode ("inc", "dptr");
10319         }
10320     }
10321
10322   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10323     {
10324       aopPut (left, "dpl", 0);
10325       aopPut (left, "dph", 1);
10326       pi->generated = 1;
10327     }
10328
10329   if (ifx && !ifx->generated)
10330     {
10331       genIfxJump (ifx, ifxCond, left, NULL, result);
10332     }
10333
10334   freeAsmop (result, NULL, ic, TRUE);
10335   freeAsmop (left, NULL, ic, TRUE);
10336 }
10337
10338 /*-----------------------------------------------------------------*/
10339 /* genPointerGet - generate code for pointer get                   */
10340 /*-----------------------------------------------------------------*/
10341 static void
10342 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10343 {
10344   operand *left, *result;
10345   sym_link *type, *etype;
10346   int p_type;
10347
10348   D (emitcode (";", "genPointerGet"));
10349
10350   left = IC_LEFT (ic);
10351   result = IC_RESULT (ic);
10352
10353   if (getSize (operandType (result))>1)
10354     ifx = NULL;
10355
10356   /* depending on the type of pointer we need to
10357      move it to the correct pointer register */
10358   type = operandType (left);
10359   etype = getSpec (type);
10360   /* if left is of type of pointer then it is simple */
10361   if (IS_PTR (type) && !IS_FUNC (type->next))
10362     {
10363       p_type = DCL_TYPE (type);
10364     }
10365   else
10366     {
10367       /* we have to go by the storage class */
10368       p_type = PTR_TYPE (SPEC_OCLS (etype));
10369     }
10370
10371   /* special case when cast remat */
10372   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10373       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10374     {
10375       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10376       type = operandType (left);
10377       p_type = DCL_TYPE (type);
10378     }
10379   /* now that we have the pointer type we assign
10380      the pointer values */
10381   switch (p_type)
10382     {
10383
10384     case POINTER:
10385     case IPOINTER:
10386       genNearPointerGet (left, result, ic, pi, ifx);
10387       break;
10388
10389     case PPOINTER:
10390       genPagedPointerGet (left, result, ic, pi, ifx);
10391       break;
10392
10393     case FPOINTER:
10394       genFarPointerGet (left, result, ic, pi, ifx);
10395       break;
10396
10397     case CPOINTER:
10398       genCodePointerGet (left, result, ic, pi, ifx);
10399       break;
10400
10401     case GPOINTER:
10402       genGenPointerGet (left, result, ic, pi, ifx);
10403       break;
10404     }
10405 }
10406
10407
10408 /*-----------------------------------------------------------------*/
10409 /* genPackBits - generates code for packed bit storage             */
10410 /*-----------------------------------------------------------------*/
10411 static void
10412 genPackBits (sym_link * etype,
10413              operand * right,
10414              char *rname, int p_type)
10415 {
10416   int offset = 0;       /* source byte offset */
10417   int rlen = 0;         /* remaining bitfield length */
10418   int blen;             /* bitfield length */
10419   int bstr;             /* bitfield starting bit within byte */
10420   int litval;           /* source literal value (if AOP_LIT) */
10421   unsigned char mask;   /* bitmask within current byte */
10422
10423   D(emitcode (";", "genPackBits"));
10424
10425   blen = SPEC_BLEN (etype);
10426   bstr = SPEC_BSTR (etype);
10427
10428   /* If the bitfield length is less than a byte */
10429   if (blen < 8)
10430     {
10431       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10432               (unsigned char) (0xFF >> (8 - bstr)));
10433
10434       if (AOP_TYPE (right) == AOP_LIT)
10435         {
10436           /* Case with a bitfield length <8 and literal source
10437           */
10438           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10439           litval <<= bstr;
10440           litval &= (~mask) & 0xff;
10441           emitPtrByteGet (rname, p_type, FALSE);
10442           if ((mask|litval)!=0xff)
10443             emitcode ("anl","a,#0x%02x", mask);
10444           if (litval)
10445             emitcode ("orl","a,#0x%02x", litval);
10446         }
10447       else
10448         {
10449           if ((blen==1) && (p_type!=GPOINTER))
10450             {
10451               /* Case with a bitfield length == 1 and no generic pointer
10452               */
10453               if (AOP_TYPE (right) == AOP_CRY)
10454                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10455               else
10456                 {
10457                   MOVA (aopGet (right, 0, FALSE, FALSE));
10458                   emitcode ("rrc","a");
10459                 }
10460               emitPtrByteGet (rname, p_type, FALSE);
10461               emitcode ("mov","acc.%d,c",bstr);
10462             }
10463           else
10464             {
10465               bool pushedB;
10466               /* Case with a bitfield length < 8 and arbitrary source
10467               */
10468               MOVA (aopGet (right, 0, FALSE, FALSE));
10469               /* shift and mask source value */
10470               AccLsh (bstr);
10471               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10472
10473               pushedB = pushB ();
10474               /* transfer A to B and get next byte */
10475               emitPtrByteGet (rname, p_type, TRUE);
10476
10477               emitcode ("anl", "a,#0x%02x", mask);
10478               emitcode ("orl", "a,b");
10479               if (p_type == GPOINTER)
10480                 emitcode ("pop", "b");
10481
10482               popB (pushedB);
10483            }
10484         }
10485
10486       emitPtrByteSet (rname, p_type, "a");
10487       return;
10488     }
10489
10490   /* Bit length is greater than 7 bits. In this case, copy  */
10491   /* all except the partial byte at the end                 */
10492   for (rlen=blen;rlen>=8;rlen-=8)
10493     {
10494       emitPtrByteSet (rname, p_type,
10495                       aopGet (right, offset++, FALSE, TRUE) );
10496       if (rlen>8)
10497         emitcode ("inc", "%s", rname);
10498     }
10499
10500   /* If there was a partial byte at the end */
10501   if (rlen)
10502     {
10503       mask = (((unsigned char) -1 << rlen) & 0xff);
10504
10505       if (AOP_TYPE (right) == AOP_LIT)
10506         {
10507           /* Case with partial byte and literal source
10508           */
10509           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10510           litval >>= (blen-rlen);
10511           litval &= (~mask) & 0xff;
10512           emitPtrByteGet (rname, p_type, FALSE);
10513           if ((mask|litval)!=0xff)
10514             emitcode ("anl","a,#0x%02x", mask);
10515           if (litval)
10516             emitcode ("orl","a,#0x%02x", litval);
10517         }
10518       else
10519         {
10520           bool pushedB;
10521           /* Case with partial byte and arbitrary source
10522           */
10523           MOVA (aopGet (right, offset++, FALSE, FALSE));
10524           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10525
10526           pushedB = pushB ();
10527           /* transfer A to B and get next byte */
10528           emitPtrByteGet (rname, p_type, TRUE);
10529
10530           emitcode ("anl", "a,#0x%02x", mask);
10531           emitcode ("orl", "a,b");
10532           if (p_type == GPOINTER)
10533             emitcode ("pop", "b");
10534
10535           popB (pushedB);
10536         }
10537       emitPtrByteSet (rname, p_type, "a");
10538     }
10539 }
10540
10541
10542 /*-----------------------------------------------------------------*/
10543 /* genDataPointerSet - remat pointer to data space                 */
10544 /*-----------------------------------------------------------------*/
10545 static void
10546 genDataPointerSet (operand * right,
10547                    operand * result,
10548                    iCode * ic)
10549 {
10550   int size, offset = 0;
10551   char *l, buffer[256];
10552
10553   D (emitcode (";", "genDataPointerSet"));
10554
10555   aopOp (right, ic, FALSE);
10556
10557   l = aopGet (result, 0, FALSE, TRUE);
10558   l++; //remove #
10559   size = max (AOP_SIZE (right), AOP_SIZE (result));
10560   while (size--)
10561     {
10562       if (offset)
10563         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10564       else
10565         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10566       emitcode ("mov", "%s,%s", buffer,
10567                 aopGet (right, offset++, FALSE, FALSE));
10568     }
10569
10570   freeAsmop (right, NULL, ic, TRUE);
10571   freeAsmop (result, NULL, ic, TRUE);
10572 }
10573
10574 /*-----------------------------------------------------------------*/
10575 /* genNearPointerSet - emitcode for near pointer put               */
10576 /*-----------------------------------------------------------------*/
10577 static void
10578 genNearPointerSet (operand * right,
10579                    operand * result,
10580                    iCode * ic,
10581                    iCode * pi)
10582 {
10583   asmop *aop = NULL;
10584   regs *preg = NULL;
10585   char *rname, *l;
10586   sym_link *retype, *letype;
10587   sym_link *ptype = operandType (result);
10588
10589   D (emitcode (";", "genNearPointerSet"));
10590
10591   retype = getSpec (operandType (right));
10592   letype = getSpec (ptype);
10593
10594   aopOp (result, ic, FALSE);
10595
10596   /* if the result is rematerializable &
10597      in data space & not a bit variable */
10598   if (AOP_TYPE (result) == AOP_IMMD &&
10599       DCL_TYPE (ptype) == POINTER &&
10600       !IS_BITVAR (retype) &&
10601       !IS_BITVAR (letype))
10602     {
10603       genDataPointerSet (right, result, ic);
10604       return;
10605     }
10606
10607   /* if the value is already in a pointer register
10608      then don't need anything more */
10609   if (!AOP_INPREG (AOP (result)))
10610     {
10611       if (IS_AOP_PREG (result))
10612         {
10613           // Aha, it is a pointer, just in disguise.
10614           rname = aopGet (result, 0, FALSE, FALSE);
10615           if (*rname != '@')
10616             {
10617               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10618                       __FILE__, __LINE__);
10619             }
10620           else
10621             {
10622               // Expected case.
10623               emitcode ("mov", "a%s,%s", rname + 1, rname);
10624               rname++;  // skip the '@'.
10625             }
10626         }
10627       else
10628         {
10629           /* otherwise get a free pointer register */
10630           aop = newAsmop (0);
10631           preg = getFreePtr (ic, &aop, FALSE);
10632           emitcode ("mov", "%s,%s",
10633                     preg->name,
10634                     aopGet (result, 0, FALSE, TRUE));
10635           rname = preg->name;
10636         }
10637     }
10638   else
10639     {
10640       rname = aopGet (result, 0, FALSE, FALSE);
10641     }
10642
10643   aopOp (right, ic, FALSE);
10644
10645   /* if bitfield then unpack the bits */
10646   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10647     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10648   else
10649     {
10650       /* we can just get the values */
10651       int size = AOP_SIZE (right);
10652       int offset = 0;
10653
10654       while (size--)
10655         {
10656           l = aopGet (right, offset, FALSE, TRUE);
10657           if ((*l == '@') || (strcmp (l, "acc") == 0))
10658             {
10659               MOVA (l);
10660               emitcode ("mov", "@%s,a", rname);
10661             }
10662           else
10663             emitcode ("mov", "@%s,%s", rname, l);
10664           if (size || pi)
10665             emitcode ("inc", "%s", rname);
10666           offset++;
10667         }
10668     }
10669
10670   /* now some housekeeping stuff */
10671   if (aop) /* we had to allocate for this iCode */
10672     {
10673       if (pi)
10674         aopPut (result, rname, 0);
10675       freeAsmop (NULL, aop, ic, TRUE);
10676     }
10677   else
10678     {
10679       /* we did not allocate which means left
10680          already in a pointer register, then
10681          if size > 0 && this could be used again
10682          we have to point it back to where it
10683          belongs */
10684       if ((AOP_SIZE (right) > 1 &&
10685            !OP_SYMBOL (result)->remat &&
10686            (OP_SYMBOL (result)->liveTo > ic->seq ||
10687             ic->depth)) &&
10688           !pi)
10689         {
10690           int size = AOP_SIZE (right) - 1;
10691           while (size--)
10692             emitcode ("dec", "%s", rname);
10693         }
10694     }
10695
10696   /* done */
10697   if (pi)
10698     pi->generated = 1;
10699   freeAsmop (right, NULL, ic, TRUE);
10700   freeAsmop (result, NULL, ic, TRUE);
10701 }
10702
10703 /*-----------------------------------------------------------------*/
10704 /* genPagedPointerSet - emitcode for Paged pointer put             */
10705 /*-----------------------------------------------------------------*/
10706 static void
10707 genPagedPointerSet (operand * right,
10708                     operand * result,
10709                     iCode * ic,
10710                     iCode * pi)
10711 {
10712   asmop *aop = NULL;
10713   regs *preg = NULL;
10714   char *rname, *l;
10715   sym_link *retype, *letype;
10716
10717   D (emitcode (";", "genPagedPointerSet"));
10718
10719   retype = getSpec (operandType (right));
10720   letype = getSpec (operandType (result));
10721
10722   aopOp (result, ic, FALSE);
10723
10724   /* if the value is already in a pointer register
10725      then don't need anything more */
10726   if (!AOP_INPREG (AOP (result)))
10727     {
10728       if (IS_AOP_PREG (result))
10729         {
10730           // Aha, it is a pointer, just in disguise.
10731           rname = aopGet (result, 0, FALSE, FALSE);
10732           if (*rname != '@')
10733             {
10734               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10735                       __FILE__, __LINE__);
10736             }
10737           else
10738             {
10739               // Expected case.
10740               emitcode ("mov", "a%s,%s", rname + 1, rname);
10741               rname++;  // skip the '@'.
10742             }
10743         }
10744       else
10745         {
10746           /* otherwise get a free pointer register */
10747           aop = newAsmop (0);
10748           preg = getFreePtr (ic, &aop, FALSE);
10749           emitcode ("mov", "%s,%s",
10750                     preg->name,
10751                     aopGet (result, 0, FALSE, TRUE));
10752           rname = preg->name;
10753         }
10754     }
10755   else
10756     {
10757       rname = aopGet (result, 0, FALSE, FALSE);
10758     }
10759
10760   aopOp (right, ic, FALSE);
10761
10762   /* if bitfield then unpack the bits */
10763   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10764     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10765   else
10766     {
10767       /* we can just get the values */
10768       int size = AOP_SIZE (right);
10769       int offset = 0;
10770
10771       while (size--)
10772         {
10773           l = aopGet (right, offset, FALSE, TRUE);
10774           MOVA (l);
10775           emitcode ("movx", "@%s,a", rname);
10776           if (size || pi)
10777             emitcode ("inc", "%s", rname);
10778           offset++;
10779         }
10780     }
10781
10782   /* now some housekeeping stuff */
10783   if (aop) /* we had to allocate for this iCode */
10784     {
10785       if (pi)
10786         aopPut (result, rname, 0);
10787       freeAsmop (NULL, aop, ic, TRUE);
10788     }
10789   else
10790     {
10791       /* we did not allocate which means left
10792          already in a pointer register, then
10793          if size > 0 && this could be used again
10794          we have to point it back to where it
10795          belongs */
10796       if (AOP_SIZE (right) > 1 &&
10797           !OP_SYMBOL (result)->remat &&
10798           (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) &&
10799           !pi)
10800         {
10801           int size = AOP_SIZE (right) - 1;
10802           while (size--)
10803             emitcode ("dec", "%s", rname);
10804         }
10805     }
10806
10807   /* done */
10808   if (pi)
10809     pi->generated = 1;
10810   freeAsmop (right, NULL, ic, TRUE);
10811   freeAsmop (result, NULL, ic, TRUE);
10812 }
10813
10814 /*-----------------------------------------------------------------*/
10815 /* genFarPointerSet - set value from far space                     */
10816 /*-----------------------------------------------------------------*/
10817 static void
10818 genFarPointerSet (operand * right,
10819                   operand * result, iCode * ic, iCode * pi)
10820 {
10821   int size, offset;
10822   sym_link *retype = getSpec (operandType (right));
10823   sym_link *letype = getSpec (operandType (result));
10824
10825   D(emitcode (";", "genFarPointerSet"));
10826
10827   aopOp (result, ic, FALSE);
10828   loadDptrFromOperand (result, FALSE);
10829
10830   /* so dptr now contains the address */
10831   aopOp (right, ic, FALSE);
10832
10833   /* if bit then unpack */
10834   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10835     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10836   else
10837     {
10838       size = AOP_SIZE (right);
10839       offset = 0;
10840
10841       while (size--)
10842         {
10843           char *l = aopGet (right, offset++, FALSE, FALSE);
10844           MOVA (l);
10845           emitcode ("movx", "@dptr,a");
10846           if (size || pi)
10847             emitcode ("inc", "dptr");
10848         }
10849     }
10850   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10851     aopPut (result, "dpl", 0);
10852     aopPut (result, "dph", 1);
10853     pi->generated=1;
10854   }
10855   freeAsmop (result, NULL, ic, TRUE);
10856   freeAsmop (right, NULL, ic, TRUE);
10857 }
10858
10859 /*-----------------------------------------------------------------*/
10860 /* genGenPointerSet - set value from generic pointer space         */
10861 /*-----------------------------------------------------------------*/
10862 static void
10863 genGenPointerSet (operand * right,
10864                   operand * result, iCode * ic, iCode * pi)
10865 {
10866   int size, offset;
10867   sym_link *retype = getSpec (operandType (right));
10868   sym_link *letype = getSpec (operandType (result));
10869
10870   D (emitcode (";", "genGenPointerSet"));
10871
10872   aopOp (result, ic, FALSE);
10873   loadDptrFromOperand (result, TRUE);
10874
10875   /* so dptr now contains the address */
10876   aopOp (right, ic, FALSE);
10877
10878   /* if bit then unpack */
10879   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10880     {
10881       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10882     }
10883   else
10884     {
10885       size = AOP_SIZE (right);
10886       offset = 0;
10887
10888       while (size--)
10889         {
10890           char *l = aopGet (right, offset++, FALSE, FALSE);
10891           MOVA (l);
10892           emitcode ("lcall", "__gptrput");
10893           if (size || pi)
10894             emitcode ("inc", "dptr");
10895         }
10896     }
10897
10898   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10899     aopPut (result, "dpl", 0);
10900     aopPut (result, "dph", 1);
10901     pi->generated=1;
10902   }
10903   freeAsmop (result, NULL, ic, TRUE);
10904   freeAsmop (right, NULL, ic, TRUE);
10905 }
10906
10907 /*-----------------------------------------------------------------*/
10908 /* genPointerSet - stores the value into a pointer location        */
10909 /*-----------------------------------------------------------------*/
10910 static void
10911 genPointerSet (iCode * ic, iCode *pi)
10912 {
10913   operand *right, *result;
10914   sym_link *type, *etype;
10915   int p_type;
10916
10917   D (emitcode (";", "genPointerSet"));
10918
10919   right = IC_RIGHT (ic);
10920   result = IC_RESULT (ic);
10921
10922   /* depending on the type of pointer we need to
10923      move it to the correct pointer register */
10924   type = operandType (result);
10925   etype = getSpec (type);
10926   /* if left is of type of pointer then it is simple */
10927   if (IS_PTR (type) && !IS_FUNC (type->next))
10928     {
10929       p_type = DCL_TYPE (type);
10930     }
10931   else
10932     {
10933       /* we have to go by the storage class */
10934       p_type = PTR_TYPE (SPEC_OCLS (etype));
10935     }
10936
10937   /* special case when cast remat */
10938   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10939       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10940           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10941           type = operandType (result);
10942           p_type = DCL_TYPE (type);
10943   }
10944
10945   /* now that we have the pointer type we assign
10946      the pointer values */
10947   switch (p_type)
10948     {
10949
10950     case POINTER:
10951     case IPOINTER:
10952       genNearPointerSet (right, result, ic, pi);
10953       break;
10954
10955     case PPOINTER:
10956       genPagedPointerSet (right, result, ic, pi);
10957       break;
10958
10959     case FPOINTER:
10960       genFarPointerSet (right, result, ic, pi);
10961       break;
10962
10963     case GPOINTER:
10964       genGenPointerSet (right, result, ic, pi);
10965       break;
10966
10967     default:
10968       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10969               "genPointerSet: illegal pointer type");
10970     }
10971 }
10972
10973 /*-----------------------------------------------------------------*/
10974 /* genIfx - generate code for Ifx statement                        */
10975 /*-----------------------------------------------------------------*/
10976 static void
10977 genIfx (iCode * ic, iCode * popIc)
10978 {
10979   operand *cond = IC_COND (ic);
10980   int isbit = 0;
10981   char *dup = NULL;
10982
10983   D (emitcode (";", "genIfx"));
10984
10985   aopOp (cond, ic, FALSE);
10986
10987   /* get the value into acc */
10988   if (AOP_TYPE (cond) != AOP_CRY)
10989     {
10990       toBoolean (cond);
10991     }
10992   else
10993     {
10994       isbit = 1;
10995       if (AOP(cond)->aopu.aop_dir)
10996         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10997     }
10998
10999   /* the result is now in the accumulator or a directly addressable bit */
11000   freeAsmop (cond, NULL, ic, TRUE);
11001
11002   /* if there was something to be popped then do it */
11003   if (popIc)
11004     genIpop (popIc);
11005
11006   /* if the condition is a bit variable */
11007   if (isbit && dup)
11008     genIfxJump(ic, dup, NULL, NULL, NULL);
11009   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11010     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
11011   else if (isbit && !IS_ITEMP (cond))
11012     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
11013   else
11014     genIfxJump (ic, "a", NULL, NULL, NULL);
11015
11016   ic->generated = 1;
11017 }
11018
11019 /*-----------------------------------------------------------------*/
11020 /* genAddrOf - generates code for address of                       */
11021 /*-----------------------------------------------------------------*/
11022 static void
11023 genAddrOf (iCode * ic)
11024 {
11025   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11026   int size, offset;
11027
11028   D (emitcode (";", "genAddrOf"));
11029
11030   aopOp (IC_RESULT (ic), ic, FALSE);
11031
11032   /* if the operand is on the stack then we
11033      need to get the stack offset of this
11034      variable */
11035   if (sym->onStack)
11036     {
11037       /* if it has an offset then we need to compute it */
11038       if (sym->stack)
11039         {
11040           int stack_offset = ((sym->stack < 0) ?
11041                               ((char) (sym->stack - _G.nRegsSaved)) :
11042                               ((char) sym->stack)) & 0xff;
11043           if ((abs(stack_offset) == 1) &&
11044               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11045               !isOperandVolatile (IC_RESULT (ic), FALSE))
11046             {
11047               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11048               if (stack_offset > 0)
11049                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11050               else
11051                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11052             }
11053           else
11054             {
11055               emitcode ("mov", "a,%s", SYM_BP (sym));
11056               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11057               aopPut (IC_RESULT (ic), "a", 0);
11058             }
11059         }
11060       else
11061         {
11062           /* we can just move _bp */
11063           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11064         }
11065       /* fill the result with zero */
11066       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11067
11068       offset = 1;
11069       while (size--)
11070         {
11071           aopPut (IC_RESULT (ic), zero, offset++);
11072         }
11073       goto release;
11074     }
11075
11076   /* object not on stack then we need the name */
11077   size = AOP_SIZE (IC_RESULT (ic));
11078   offset = 0;
11079
11080   while (size--)
11081     {
11082       char s[SDCC_NAME_MAX];
11083       if (offset)
11084         sprintf (s, "#(%s >> %d)",
11085                  sym->rname,
11086                  offset * 8);
11087       else
11088         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11089       aopPut (IC_RESULT (ic), s, offset++);
11090     }
11091
11092 release:
11093   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11094
11095 }
11096
11097 /*-----------------------------------------------------------------*/
11098 /* genFarFarAssign - assignment when both are in far space         */
11099 /*-----------------------------------------------------------------*/
11100 static void
11101 genFarFarAssign (operand * result, operand * right, iCode * ic)
11102 {
11103   int size = AOP_SIZE (right);
11104   int offset = 0;
11105   char *l;
11106
11107   D (emitcode (";", "genFarFarAssign"));
11108
11109   /* first push the right side on to the stack */
11110   while (size--)
11111     {
11112       l = aopGet (right, offset++, FALSE, FALSE);
11113       MOVA (l);
11114       emitcode ("push", "acc");
11115     }
11116
11117   freeAsmop (right, NULL, ic, FALSE);
11118   /* now assign DPTR to result */
11119   aopOp (result, ic, FALSE);
11120   size = AOP_SIZE (result);
11121   while (size--)
11122     {
11123       emitcode ("pop", "acc");
11124       aopPut (result, "a", --offset);
11125     }
11126   freeAsmop (result, NULL, ic, FALSE);
11127 }
11128
11129 /*-----------------------------------------------------------------*/
11130 /* genAssign - generate code for assignment                        */
11131 /*-----------------------------------------------------------------*/
11132 static void
11133 genAssign (iCode * ic)
11134 {
11135   operand *result, *right;
11136   int size, offset;
11137   unsigned long lit = 0L;
11138
11139   D (emitcode (";", "genAssign"));
11140
11141   result = IC_RESULT (ic);
11142   right = IC_RIGHT (ic);
11143
11144   /* if they are the same */
11145   if (operandsEqu (result, right) &&
11146       !isOperandVolatile (result, FALSE) &&
11147       !isOperandVolatile (right, FALSE))
11148     return;
11149
11150   aopOp (right, ic, FALSE);
11151
11152   /* special case both in far space */
11153   if (AOP_TYPE (right) == AOP_DPTR &&
11154       IS_TRUE_SYMOP (result) &&
11155       isOperandInFarSpace (result))
11156     {
11157       genFarFarAssign (result, right, ic);
11158       return;
11159     }
11160
11161   aopOp (result, ic, TRUE);
11162
11163   /* if they are the same registers */
11164   if (sameRegs (AOP (right), AOP (result)) &&
11165       !isOperandVolatile (result, FALSE) &&
11166       !isOperandVolatile (right, FALSE))
11167     goto release;
11168
11169   /* if the result is a bit */
11170   if (AOP_TYPE (result) == AOP_CRY)
11171     {
11172       assignBit (result, right);
11173       goto release;
11174     }
11175
11176   /* bit variables done */
11177   /* general case */
11178   size = AOP_SIZE (result);
11179   offset = 0;
11180   if (AOP_TYPE (right) == AOP_LIT)
11181     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11182
11183   if ((size > 1) &&
11184       (AOP_TYPE (result) != AOP_REG) &&
11185       (AOP_TYPE (right) == AOP_LIT) &&
11186       !IS_FLOAT (operandType (right)) &&
11187       (lit < 256L))
11188     {
11189       while ((size) && (lit))
11190         {
11191           aopPut (result,
11192                   aopGet (right, offset, FALSE, FALSE),
11193                   offset);
11194           lit >>= 8;
11195           offset++;
11196           size--;
11197         }
11198       /* And now fill the rest with zeros. */
11199       if (size)
11200         {
11201           emitcode ("clr", "a");
11202         }
11203       while (size--)
11204         {
11205           aopPut (result, "a", offset);
11206           offset++;
11207         }
11208     }
11209   else
11210     {
11211       while (size--)
11212         {
11213           aopPut (result,
11214                   aopGet (right, offset, FALSE, FALSE),
11215                   offset);
11216           offset++;
11217         }
11218     }
11219
11220 release:
11221   freeAsmop (result, NULL, ic, TRUE);
11222   freeAsmop (right, NULL, ic, TRUE);
11223 }
11224
11225 /*-----------------------------------------------------------------*/
11226 /* genJumpTab - generates code for jump table                      */
11227 /*-----------------------------------------------------------------*/
11228 static void
11229 genJumpTab (iCode * ic)
11230 {
11231   symbol *jtab,*jtablo,*jtabhi;
11232   char *l;
11233   unsigned int count;
11234
11235   D (emitcode (";", "genJumpTab"));
11236
11237   count = elementsInSet( IC_JTLABELS (ic) );
11238
11239   if( count <= 16 )
11240     {
11241       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11242          if the switch argument is in a register.
11243          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11244       /* Peephole may not convert ljmp to sjmp or ret
11245          labelIsReturnOnly & labelInRange must check
11246          currPl->ic->op != JUMPTABLE */
11247       aopOp (IC_JTCOND (ic), ic, FALSE);
11248       /* get the condition into accumulator */
11249       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11250       MOVA (l);
11251       /* multiply by three */
11252       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11253         {
11254           emitcode ("mov", "b,#3");
11255           emitcode ("mul", "ab");
11256         }
11257       else
11258         {
11259           emitcode ("add", "a,acc");
11260           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11261         }
11262       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11263
11264       jtab = newiTempLabel (NULL);
11265       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11266       emitcode ("jmp", "@a+dptr");
11267       emitLabel (jtab);
11268       /* now generate the jump labels */
11269       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11270            jtab = setNextItem (IC_JTLABELS (ic)))
11271         emitcode ("ljmp", "%05d$", jtab->key + 100);
11272     }
11273   else
11274     {
11275       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11276          if the switch argument is in a register.
11277          For n>6 this algorithm may be more compact */
11278       jtablo = newiTempLabel (NULL);
11279       jtabhi = newiTempLabel (NULL);
11280
11281       /* get the condition into accumulator.
11282          Using b as temporary storage, if register push/pop is needed */
11283       aopOp (IC_JTCOND (ic), ic, FALSE);
11284       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11285       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11286           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11287         {
11288           // (MB) what if B is in use???
11289           wassertl(!BINUSE, "B was in use");
11290           emitcode ("mov", "b,%s", l);
11291           l = "b";
11292         }
11293       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11294       MOVA (l);
11295       if( count <= 112 )
11296         {
11297           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11298           emitcode ("movc", "a,@a+pc");
11299           emitcode ("push", "acc");
11300
11301           MOVA (l);
11302           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11303           emitcode ("movc", "a,@a+pc");
11304           emitcode ("push", "acc");
11305         }
11306       else
11307         {
11308           /* this scales up to n<=255, but needs two more bytes
11309              and changes dptr */
11310           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11311           emitcode ("movc", "a,@a+dptr");
11312           emitcode ("push", "acc");
11313
11314           MOVA (l);
11315           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11316           emitcode ("movc", "a,@a+dptr");
11317           emitcode ("push", "acc");
11318         }
11319
11320       emitcode ("ret", "");
11321
11322       /* now generate jump table, LSB */
11323       emitLabel (jtablo);
11324       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11325            jtab = setNextItem (IC_JTLABELS (ic)))
11326         emitcode (".db", "%05d$", jtab->key + 100);
11327
11328       /* now generate jump table, MSB */
11329       emitLabel (jtabhi);
11330       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11331            jtab = setNextItem (IC_JTLABELS (ic)))
11332          emitcode (".db", "%05d$>>8", jtab->key + 100);
11333     }
11334 }
11335
11336 /*-----------------------------------------------------------------*/
11337 /* genCast - gen code for casting                                  */
11338 /*-----------------------------------------------------------------*/
11339 static void
11340 genCast (iCode * ic)
11341 {
11342   operand *result = IC_RESULT (ic);
11343   sym_link *ctype = operandType (IC_LEFT (ic));
11344   sym_link *rtype = operandType (IC_RIGHT (ic));
11345   operand *right = IC_RIGHT (ic);
11346   int size, offset;
11347
11348   D (emitcode (";", "genCast"));
11349
11350   /* if they are equivalent then do nothing */
11351   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11352     return;
11353
11354   aopOp (right, ic, FALSE);
11355   aopOp (result, ic, FALSE);
11356
11357   /* if the result is a bit (and not a bitfield) */
11358   if (IS_BIT (OP_SYMBOL (result)->type))
11359     {
11360       assignBit (result, right);
11361       goto release;
11362     }
11363
11364   /* if they are the same size : or less */
11365   if (AOP_SIZE (result) <= AOP_SIZE (right))
11366     {
11367
11368       /* if they are in the same place */
11369       if (sameRegs (AOP (right), AOP (result)))
11370         goto release;
11371
11372       /* if they in different places then copy */
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   /* if the result is of type pointer */
11386   if (IS_PTR (ctype))
11387     {
11388
11389       int p_type;
11390       sym_link *type = operandType (right);
11391       sym_link *etype = getSpec (type);
11392
11393       /* pointer to generic pointer */
11394       if (IS_GENPTR (ctype))
11395         {
11396           if (IS_PTR (type))
11397             {
11398               p_type = DCL_TYPE (type);
11399             }
11400           else
11401             {
11402               if (SPEC_SCLS(etype)==S_REGISTER) {
11403                 // let's assume it is a generic pointer
11404                 p_type=GPOINTER;
11405               } else {
11406                 /* we have to go by the storage class */
11407                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11408               }
11409             }
11410
11411           /* the first two bytes are known */
11412           size = GPTRSIZE - 1;
11413           offset = 0;
11414           while (size--)
11415             {
11416               aopPut (result,
11417                       aopGet (right, offset, FALSE, FALSE),
11418                       offset);
11419               offset++;
11420             }
11421           /* the last byte depending on type */
11422             {
11423                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11424                 char gpValStr[10];
11425
11426                 if (gpVal == -1)
11427                 {
11428                     // pointerTypeToGPByte will have bitched.
11429                     exit(1);
11430                 }
11431
11432                 sprintf(gpValStr, "#0x%x", gpVal);
11433                 aopPut (result, gpValStr, GPTRSIZE - 1);
11434             }
11435           goto release;
11436         }
11437
11438       /* just copy the pointers */
11439       size = AOP_SIZE (result);
11440       offset = 0;
11441       while (size--)
11442         {
11443           aopPut (result,
11444                   aopGet (right, offset, FALSE, FALSE),
11445                   offset);
11446           offset++;
11447         }
11448       goto release;
11449     }
11450
11451   /* so we now know that the size of destination is greater
11452      than the size of the source */
11453   /* we move to result for the size of source */
11454   size = AOP_SIZE (right);
11455   offset = 0;
11456   while (size--)
11457     {
11458       aopPut (result,
11459               aopGet (right, offset, FALSE, FALSE),
11460               offset);
11461       offset++;
11462     }
11463
11464   /* now depending on the sign of the source && destination */
11465   size = AOP_SIZE (result) - AOP_SIZE (right);
11466   /* if unsigned or not an integral type */
11467   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11468     {
11469       while (size--)
11470         aopPut (result, zero, offset++);
11471     }
11472   else
11473     {
11474       /* we need to extend the sign :{ */
11475       char *l = aopGet (right, AOP_SIZE (right) - 1,
11476                         FALSE, FALSE);
11477       MOVA (l);
11478       emitcode ("rlc", "a");
11479       emitcode ("subb", "a,acc");
11480       while (size--)
11481         aopPut (result, "a", offset++);
11482     }
11483
11484   /* we are done hurray !!!! */
11485
11486 release:
11487   freeAsmop (result, NULL, ic, TRUE);
11488   freeAsmop (right, NULL, ic, TRUE);
11489 }
11490
11491 /*-----------------------------------------------------------------*/
11492 /* genDjnz - generate decrement & jump if not zero instrucion      */
11493 /*-----------------------------------------------------------------*/
11494 static int
11495 genDjnz (iCode * ic, iCode * ifx)
11496 {
11497   symbol *lbl, *lbl1;
11498   if (!ifx)
11499     return 0;
11500
11501   /* if the if condition has a false label
11502      then we cannot save */
11503   if (IC_FALSE (ifx))
11504     return 0;
11505
11506   /* if the minus is not of the form a = a - 1 */
11507   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11508       !IS_OP_LITERAL (IC_RIGHT (ic)))
11509     return 0;
11510
11511   if (operandLitValue (IC_RIGHT (ic)) != 1)
11512     return 0;
11513
11514   /* if the size of this greater than one then no
11515      saving */
11516   if (getSize (operandType (IC_RESULT (ic))) > 1)
11517     return 0;
11518
11519   /* otherwise we can save BIG */
11520
11521   D (emitcode (";", "genDjnz"));
11522
11523   lbl = newiTempLabel (NULL);
11524   lbl1 = newiTempLabel (NULL);
11525
11526   aopOp (IC_RESULT (ic), ic, FALSE);
11527
11528   if (AOP_NEEDSACC(IC_RESULT(ic)))
11529   {
11530       /* If the result is accessed indirectly via
11531        * the accumulator, we must explicitly write
11532        * it back after the decrement.
11533        */
11534       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11535
11536       if (strcmp(rByte, "a"))
11537       {
11538            /* Something is hopelessly wrong */
11539            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11540                    __FILE__, __LINE__);
11541            /* We can just give up; the generated code will be inefficient,
11542             * but what the hey.
11543             */
11544            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11545            return 0;
11546       }
11547       emitcode ("dec", "%s", rByte);
11548       aopPut (IC_RESULT (ic), rByte, 0);
11549       emitcode ("jnz", "%05d$", lbl->key + 100);
11550   }
11551   else if (IS_AOP_PREG (IC_RESULT (ic)))
11552     {
11553       emitcode ("dec", "%s",
11554                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11555       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11556       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11557       ifx->generated = 1;
11558       emitcode ("jnz", "%05d$", lbl->key + 100);
11559     }
11560   else
11561     {
11562       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11563                 lbl->key + 100);
11564     }
11565   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11566   emitLabel (lbl);
11567   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11568   emitLabel (lbl1);
11569
11570   if (!ifx->generated)
11571       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11572   ifx->generated = 1;
11573   return 1;
11574 }
11575
11576 /*-----------------------------------------------------------------*/
11577 /* genReceive - generate code for a receive iCode                  */
11578 /*-----------------------------------------------------------------*/
11579 static void
11580 genReceive (iCode * ic)
11581 {
11582   int size = getSize (operandType (IC_RESULT (ic)));
11583   int offset = 0;
11584
11585   D (emitcode (";", "genReceive"));
11586
11587   if (ic->argreg == 1)
11588     { /* first parameter */
11589       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11590            isOperandInPagedSpace (IC_RESULT (ic))) &&
11591           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11592            IS_TRUE_SYMOP (IC_RESULT (ic))))
11593         {
11594           regs *tempRegs[4];
11595           int receivingA = 0;
11596           int roffset = 0;
11597
11598           for (offset = 0; offset<size; offset++)
11599             if (!strcmp (fReturn[offset], "a"))
11600               receivingA = 1;
11601
11602           if (!receivingA)
11603             {
11604               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11605                 {
11606                   for (offset = size-1; offset>0; offset--)
11607                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11608                   emitcode("mov","a,%s", fReturn[0]);
11609                   _G.accInUse++;
11610                   aopOp (IC_RESULT (ic), ic, FALSE);
11611                   _G.accInUse--;
11612                   aopPut (IC_RESULT (ic), "a", offset);
11613                   for (offset = 1; offset<size; offset++)
11614                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11615                   goto release;
11616                 }
11617             }
11618           else
11619             {
11620               if (getTempRegs(tempRegs, size, ic))
11621                 {
11622                   for (offset = 0; offset<size; offset++)
11623                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11624                   aopOp (IC_RESULT (ic), ic, FALSE);
11625                   for (offset = 0; offset<size; offset++)
11626                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11627                   goto release;
11628                 }
11629             }
11630
11631           offset = fReturnSizeMCS51 - size;
11632           while (size--)
11633             {
11634               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11635                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11636               offset++;
11637             }
11638           aopOp (IC_RESULT (ic), ic, FALSE);
11639           size = AOP_SIZE (IC_RESULT (ic));
11640           offset = 0;
11641           while (size--)
11642             {
11643               emitcode ("pop", "acc");
11644               aopPut (IC_RESULT (ic), "a", offset++);
11645             }
11646         }
11647       else
11648         {
11649           _G.accInUse++;
11650           aopOp (IC_RESULT (ic), ic, FALSE);
11651           _G.accInUse--;
11652           assignResultValue (IC_RESULT (ic), NULL);
11653         }
11654     }
11655   else if (ic->argreg > 12)
11656     { /* bit parameters */
11657       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11658
11659       BitBankUsed = 1;
11660       if (!reg || reg->rIdx != ic->argreg-5)
11661         {
11662           aopOp (IC_RESULT (ic), ic, FALSE);
11663           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11664           outBitC(IC_RESULT (ic));
11665         }
11666     }
11667   else
11668     { /* other parameters */
11669       int rb1off ;
11670       aopOp (IC_RESULT (ic), ic, FALSE);
11671       rb1off = ic->argreg;
11672       while (size--)
11673         {
11674           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11675         }
11676     }
11677
11678 release:
11679   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11680 }
11681
11682 /*-----------------------------------------------------------------*/
11683 /* genDummyRead - generate code for dummy read of volatiles        */
11684 /*-----------------------------------------------------------------*/
11685 static void
11686 genDummyRead (iCode * ic)
11687 {
11688   operand *op;
11689   int size, offset;
11690
11691   D (emitcode(";", "genDummyRead"));
11692
11693   op = IC_RIGHT (ic);
11694   if (op && IS_SYMOP (op))
11695     {
11696       aopOp (op, ic, FALSE);
11697
11698       /* if the result is a bit */
11699       if (AOP_TYPE (op) == AOP_CRY)
11700         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11701       else
11702         {
11703           /* bit variables done */
11704           /* general case */
11705           size = AOP_SIZE (op);
11706           offset = 0;
11707           while (size--)
11708           {
11709             MOVA (aopGet (op, offset, FALSE, FALSE));
11710             offset++;
11711           }
11712         }
11713
11714       freeAsmop (op, NULL, ic, TRUE);
11715     }
11716
11717   op = IC_LEFT (ic);
11718   if (op && IS_SYMOP (op))
11719     {
11720       aopOp (op, ic, FALSE);
11721
11722       /* if the result is a bit */
11723       if (AOP_TYPE (op) == AOP_CRY)
11724         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11725       else
11726         {
11727           /* bit variables done */
11728           /* general case */
11729           size = AOP_SIZE (op);
11730           offset = 0;
11731           while (size--)
11732           {
11733             MOVA (aopGet (op, offset, FALSE, FALSE));
11734             offset++;
11735           }
11736         }
11737
11738       freeAsmop (op, NULL, ic, TRUE);
11739     }
11740 }
11741
11742 /*-----------------------------------------------------------------*/
11743 /* genCritical - generate code for start of a critical sequence    */
11744 /*-----------------------------------------------------------------*/
11745 static void
11746 genCritical (iCode *ic)
11747 {
11748   symbol *tlbl = newiTempLabel (NULL);
11749
11750   D (emitcode(";", "genCritical"));
11751
11752   if (IC_RESULT (ic))
11753     {
11754       aopOp (IC_RESULT (ic), ic, TRUE);
11755       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11756       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11757       aopPut (IC_RESULT (ic), zero, 0);
11758       emitLabel (tlbl);
11759       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11760     }
11761   else
11762     {
11763       emitcode ("setb", "c");
11764       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11765       emitcode ("clr", "c");
11766       emitLabel (tlbl);
11767       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11768     }
11769 }
11770
11771 /*-----------------------------------------------------------------*/
11772 /* genEndCritical - generate code for end of a critical sequence   */
11773 /*-----------------------------------------------------------------*/
11774 static void
11775 genEndCritical (iCode *ic)
11776 {
11777   D(emitcode(";", "genEndCritical"));
11778
11779   if (IC_RIGHT (ic))
11780     {
11781       aopOp (IC_RIGHT (ic), ic, FALSE);
11782       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11783         {
11784           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11785           emitcode ("mov", "ea,c");
11786         }
11787       else
11788         {
11789           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11790             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11791           emitcode ("rrc", "a");
11792           emitcode ("mov", "ea,c");
11793         }
11794       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11795     }
11796   else
11797     {
11798       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11799       emitcode ("mov", "ea,c");
11800     }
11801 }
11802
11803 /*-----------------------------------------------------------------*/
11804 /* gen51Code - generate code for 8051 based controllers            */
11805 /*-----------------------------------------------------------------*/
11806 void
11807 gen51Code (iCode * lic)
11808 {
11809   iCode *ic;
11810   int cln = 0;
11811   /* int cseq = 0; */
11812
11813   _G.currentFunc = NULL;
11814   lineHead = lineCurr = NULL;
11815
11816   /* print the allocation information */
11817   if (allocInfo && currFunc)
11818     printAllocInfo (currFunc, codeOutBuf);
11819   /* if debug information required */
11820   if (options.debug && currFunc)
11821     {
11822       debugFile->writeFunction (currFunc, lic);
11823     }
11824   /* stack pointer name */
11825   if (options.useXstack)
11826     spname = "_spx";
11827   else
11828     spname = "sp";
11829
11830
11831   for (ic = lic; ic; ic = ic->next)
11832     {
11833       _G.current_iCode = ic;
11834
11835       if (ic->lineno && cln != ic->lineno)
11836         {
11837           if (options.debug)
11838             {
11839               debugFile->writeCLine (ic);
11840             }
11841           if (!options.noCcodeInAsm) {
11842             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11843                       printCLine(ic->filename, ic->lineno));
11844           }
11845           cln = ic->lineno;
11846         }
11847       #if 0
11848       if (ic->seqPoint && ic->seqPoint != cseq)
11849         {
11850           emitcode (";", "sequence point %d", ic->seqPoint);
11851           cseq = ic->seqPoint;
11852         }
11853       #endif
11854       if (options.iCodeInAsm) {
11855         char regsInUse[80];
11856         int i;
11857         const char *iLine;
11858
11859         #if 0
11860         for (i=0; i<8; i++) {
11861           sprintf (&regsInUse[i],
11862                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11863         regsInUse[i]=0;
11864         #else
11865         strcpy (regsInUse, "--------");
11866         for (i=0; i < 8; i++) {
11867           if (bitVectBitValue (ic->rMask, i))
11868             {
11869               int offset = regs8051[i].offset;
11870               regsInUse[offset] = offset + '0'; /* show rMask */
11871             }
11872         #endif
11873         }
11874         iLine = printILine(ic);
11875         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11876         dbuf_free(iLine);
11877       }
11878       /* if the result is marked as
11879          spilt and rematerializable or code for
11880          this has already been generated then
11881          do nothing */
11882       if (resultRemat (ic) || ic->generated)
11883         continue;
11884
11885       /* depending on the operation */
11886       switch (ic->op)
11887         {
11888         case '!':
11889           genNot (ic);
11890           break;
11891
11892         case '~':
11893           genCpl (ic);
11894           break;
11895
11896         case UNARYMINUS:
11897           genUminus (ic);
11898           break;
11899
11900         case IPUSH:
11901           genIpush (ic);
11902           break;
11903
11904         case IPOP:
11905           /* IPOP happens only when trying to restore a
11906              spilt live range, if there is an ifx statement
11907              following this pop then the if statement might
11908              be using some of the registers being popped which
11909              would destory the contents of the register so
11910              we need to check for this condition and handle it */
11911           if (ic->next &&
11912               ic->next->op == IFX &&
11913               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11914             genIfx (ic->next, ic);
11915           else
11916             genIpop (ic);
11917           break;
11918
11919         case CALL:
11920           genCall (ic);
11921           break;
11922
11923         case PCALL:
11924           genPcall (ic);
11925           break;
11926
11927         case FUNCTION:
11928           genFunction (ic);
11929           break;
11930
11931         case ENDFUNCTION:
11932           genEndFunction (ic);
11933           break;
11934
11935         case RETURN:
11936           genRet (ic);
11937           break;
11938
11939         case LABEL:
11940           genLabel (ic);
11941           break;
11942
11943         case GOTO:
11944           genGoto (ic);
11945           break;
11946
11947         case '+':
11948           genPlus (ic);
11949           break;
11950
11951         case '-':
11952           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11953             genMinus (ic);
11954           break;
11955
11956         case '*':
11957           genMult (ic);
11958           break;
11959
11960         case '/':
11961           genDiv (ic);
11962           break;
11963
11964         case '%':
11965           genMod (ic);
11966           break;
11967
11968         case '>':
11969           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11970           break;
11971
11972         case '<':
11973           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11974           break;
11975
11976         case LE_OP:
11977         case GE_OP:
11978         case NE_OP:
11979
11980           /* note these two are xlated by algebraic equivalence
11981              in decorateType() in SDCCast.c */
11982           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11983                   "got '>=' or '<=' shouldn't have come here");
11984           break;
11985
11986         case EQ_OP:
11987           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11988           break;
11989
11990         case AND_OP:
11991           genAndOp (ic);
11992           break;
11993
11994         case OR_OP:
11995           genOrOp (ic);
11996           break;
11997
11998         case '^':
11999           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
12000           break;
12001
12002         case '|':
12003           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
12004           break;
12005
12006         case BITWISEAND:
12007           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
12008           break;
12009
12010         case INLINEASM:
12011           genInline (ic);
12012           break;
12013
12014         case RRC:
12015           genRRC (ic);
12016           break;
12017
12018         case RLC:
12019           genRLC (ic);
12020           break;
12021
12022         case GETHBIT:
12023           genGetHbit (ic);
12024           break;
12025
12026         case GETABIT:
12027           genGetAbit (ic);
12028           break;
12029
12030         case GETBYTE:
12031           genGetByte (ic);
12032           break;
12033
12034         case GETWORD:
12035           genGetWord (ic);
12036           break;
12037
12038         case LEFT_OP:
12039           genLeftShift (ic);
12040           break;
12041
12042         case RIGHT_OP:
12043           genRightShift (ic);
12044           break;
12045
12046         case GET_VALUE_AT_ADDRESS:
12047           genPointerGet (ic,
12048                          hasInc (IC_LEFT (ic), ic,
12049                                  getSize (operandType (IC_RESULT (ic)))),
12050                          ifxForOp (IC_RESULT (ic), ic) );
12051           break;
12052
12053         case '=':
12054           if (POINTER_SET (ic))
12055             genPointerSet (ic,
12056                            hasInc (IC_RESULT (ic), ic,
12057                                    getSize (operandType (IC_RIGHT (ic)))));
12058           else
12059             genAssign (ic);
12060           break;
12061
12062         case IFX:
12063           genIfx (ic, NULL);
12064           break;
12065
12066         case ADDRESS_OF:
12067           genAddrOf (ic);
12068           break;
12069
12070         case JUMPTABLE:
12071           genJumpTab (ic);
12072           break;
12073
12074         case CAST:
12075           genCast (ic);
12076           break;
12077
12078         case RECEIVE:
12079           genReceive (ic);
12080           break;
12081
12082         case SEND:
12083           addSet (&_G.sendSet, ic);
12084           break;
12085
12086         case DUMMY_READ_VOLATILE:
12087           genDummyRead (ic);
12088           break;
12089
12090         case CRITICAL:
12091           genCritical (ic);
12092           break;
12093
12094         case ENDCRITICAL:
12095           genEndCritical (ic);
12096           break;
12097
12098         case SWAP:
12099           genSwap (ic);
12100           break;
12101
12102         default:
12103           ic = ic;
12104         }
12105     }
12106
12107   _G.current_iCode = NULL;
12108
12109   /* now we are ready to call the
12110      peep hole optimizer */
12111   if (!options.nopeep)
12112     peepHole (&lineHead);
12113
12114   /* now do the actual printing */
12115   printLine (lineHead, codeOutBuf);
12116   return;
12117 }