* src/ds390/gen.c (pushSide, genPcall),
[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 = aopForSym (ic, sym->usl.spillLoc, result);
1010           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1011             {
1012               /* Don't reuse the new aop, go with the last one */
1013               sym->usl.spillLoc->aop = oldAsmOp;
1014             }
1015           aop->size = getSize (sym->type);
1016           return;
1017         }
1018
1019       /* else must be a dummy iTemp */
1020       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1021       aop->size = getSize (sym->type);
1022       return;
1023     }
1024
1025   /* if the type is a bit register */
1026   if (sym->regType == REG_BIT)
1027     {
1028       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1029       aop->size = sym->nRegs;//1???
1030       aop->aopu.aop_reg[0] = sym->regs[0];
1031       aop->aopu.aop_dir = sym->regs[0]->name;
1032       return;
1033     }
1034
1035   /* must be in a register */
1036   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1037   aop->size = sym->nRegs;
1038   for (i = 0; i < sym->nRegs; i++)
1039     aop->aopu.aop_reg[i] = sym->regs[i];
1040 }
1041
1042 /*-----------------------------------------------------------------*/
1043 /* freeAsmop - free up the asmop given to an operand               */
1044 /*-----------------------------------------------------------------*/
1045 static void
1046 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1047 {
1048   asmop *aop;
1049
1050   if (!op)
1051     aop = aaop;
1052   else
1053     aop = op->aop;
1054
1055   if (!aop)
1056     return;
1057
1058   aop->allocated--;
1059
1060   if (aop->allocated)
1061     goto dealloc;
1062
1063   /* depending on the asmop type only three cases need work
1064      AOP_R0, AOP_R1 & AOP_STK */
1065   switch (aop->type)
1066     {
1067     case AOP_R0:
1068       if (R0INB)
1069         {
1070           emitcode ("mov", "r0,b");
1071           R0INB--;
1072         }
1073       else if (_G.r0Pushed)
1074         {
1075           if (pop)
1076             {
1077               emitcode ("pop", "ar0");
1078               _G.r0Pushed--;
1079             }
1080         }
1081       bitVectUnSetBit (ic->rUsed, R0_IDX);
1082       break;
1083
1084     case AOP_R1:
1085       if (R1INB)
1086         {
1087           emitcode ("mov", "r1,b");
1088           R1INB--;
1089         }
1090       else if (_G.r1Pushed)
1091         {
1092           if (pop)
1093             {
1094               emitcode ("pop", "ar1");
1095               _G.r1Pushed--;
1096             }
1097         }
1098       bitVectUnSetBit (ic->rUsed, R1_IDX);
1099       break;
1100
1101     case AOP_STK:
1102       {
1103         int sz = aop->size;
1104         int stk = aop->aopu.aop_stk + aop->size - 1;
1105         bitVectUnSetBit (ic->rUsed, R0_IDX);
1106         bitVectUnSetBit (ic->rUsed, R1_IDX);
1107
1108         getFreePtr (ic, &aop, FALSE);
1109
1110         if (stk)
1111           {
1112             emitcode ("mov", "a,_bp");
1113             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1114             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1115           }
1116         else
1117           {
1118             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1119           }
1120
1121         while (sz--)
1122           {
1123             emitcode ("pop", "acc");
1124             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1125             if (!sz)
1126               break;
1127             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1128           }
1129         op->aop = aop;
1130         freeAsmop (op, NULL, ic, TRUE);
1131         if (_G.r1Pushed)
1132           {
1133             emitcode ("pop", "ar1");
1134             _G.r1Pushed--;
1135           }
1136         if (_G.r0Pushed)
1137           {
1138             emitcode ("pop", "ar0");
1139             _G.r0Pushed--;
1140           }
1141       }
1142       break;
1143     }
1144
1145 dealloc:
1146   /* all other cases just dealloc */
1147   if (op)
1148     {
1149       op->aop = NULL;
1150       if (IS_SYMOP (op))
1151         {
1152           OP_SYMBOL (op)->aop = NULL;
1153           /* if the symbol has a spill */
1154           if (SPIL_LOC (op))
1155             SPIL_LOC (op)->aop = NULL;
1156         }
1157     }
1158 }
1159
1160 /*------------------------------------------------------------------*/
1161 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1162 /*                      pop r0 or r1 off stack if pushed            */
1163 /*------------------------------------------------------------------*/
1164 static void
1165 freeForBranchAsmop (operand * op)
1166 {
1167   asmop *aop;
1168
1169   if (!op)
1170     return;
1171
1172   aop = op->aop;
1173
1174   if (!aop)
1175     return;
1176
1177   if (!aop->allocated)
1178     return;
1179
1180   switch (aop->type)
1181     {
1182     case AOP_R0:
1183       if (R0INB)
1184         {
1185           emitcode ("mov", "r0,b");
1186         }
1187       else if (_G.r0Pushed)
1188         {
1189           emitcode ("pop", "ar0");
1190         }
1191       break;
1192
1193     case AOP_R1:
1194       if (R1INB)
1195         {
1196           emitcode ("mov", "r1,b");
1197         }
1198       else if (_G.r1Pushed)
1199         {
1200           emitcode ("pop", "ar1");
1201         }
1202       break;
1203
1204     case AOP_STK:
1205       {
1206         int sz = aop->size;
1207         int stk = aop->aopu.aop_stk + aop->size - 1;
1208
1209         emitcode ("mov", "b,r0");
1210         if (stk)
1211           {
1212             emitcode ("mov", "a,_bp");
1213             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1214             emitcode ("mov", "r0,a");
1215           }
1216         else
1217           {
1218             emitcode ("mov", "r0,_bp");
1219           }
1220
1221         while (sz--)
1222           {
1223             emitcode ("pop", "acc");
1224             emitcode ("mov", "@r0,a");
1225             if (!sz)
1226               break;
1227             emitcode ("dec", "r0");
1228           }
1229         emitcode ("mov", "r0,b");
1230       }
1231     }
1232
1233 }
1234
1235 /*-----------------------------------------------------------------*/
1236 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1237 /*                 clobber the accumulator                         */
1238 /*-----------------------------------------------------------------*/
1239 static bool
1240 aopGetUsesAcc (operand * oper, int offset)
1241 {
1242   asmop * aop = AOP (oper);
1243
1244   if (offset > (aop->size - 1))
1245     return FALSE;
1246
1247   switch (aop->type)
1248     {
1249
1250     case AOP_R0:
1251     case AOP_R1:
1252       if (aop->paged)
1253         return TRUE;
1254       return FALSE;
1255     case AOP_DPTR:
1256       return TRUE;
1257     case AOP_IMMD:
1258       return FALSE;
1259     case AOP_DIR:
1260       return FALSE;
1261     case AOP_REG:
1262       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1263       return FALSE;
1264     case AOP_CRY:
1265       return TRUE;
1266     case AOP_ACC:
1267       if (offset)
1268         return FALSE;
1269       return TRUE;
1270     case AOP_LIT:
1271       return FALSE;
1272     case AOP_STR:
1273       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1274         return TRUE;
1275       return FALSE;
1276     case AOP_DUMMY:
1277       return FALSE;
1278     default:
1279       /* Error case --- will have been caught already */
1280       wassert(0);
1281       return FALSE;
1282     }
1283 }
1284
1285 /*-------------------------------------------------------------------*/
1286 /* aopGet - for fetching value of the aop                            */
1287 /*-------------------------------------------------------------------*/
1288 static char *
1289 aopGet (operand * oper, int offset, bool bit16, bool dname)
1290 {
1291   asmop * aop = AOP (oper);
1292
1293   /* offset is greater than
1294      size then zero */
1295   if (offset > (aop->size - 1) &&
1296       aop->type != AOP_LIT)
1297     return zero;
1298
1299   /* depending on type */
1300   switch (aop->type)
1301     {
1302     case AOP_DUMMY:
1303       return zero;
1304
1305     case AOP_R0:
1306     case AOP_R1:
1307       /* if we need to increment it */
1308       while (offset > aop->coff)
1309         {
1310           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1311           aop->coff++;
1312         }
1313
1314       while (offset < aop->coff)
1315         {
1316           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1317           aop->coff--;
1318         }
1319
1320       aop->coff = offset;
1321       if (aop->paged)
1322         {
1323           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1324           return (dname ? "acc" : "a");
1325         }
1326       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1327       return Safe_strdup(buffer);
1328
1329     case AOP_DPTR:
1330       if (aop->code && aop->coff==0 && offset>=1) {
1331         emitcode ("mov", "a,#0x%02x", offset);
1332         emitcode ("movc", "a,@a+dptr");
1333         return (dname ? "acc" : "a");
1334       }
1335
1336       while (offset > aop->coff)
1337         {
1338           emitcode ("inc", "dptr");
1339           aop->coff++;
1340         }
1341
1342       while (offset < aop->coff)
1343         {
1344           emitcode ("lcall", "__decdptr");
1345           aop->coff--;
1346         }
1347
1348       aop->coff = offset;
1349       if (aop->code)
1350         {
1351           emitcode ("clr", "a");
1352           emitcode ("movc", "a,@a+dptr");
1353         }
1354       else
1355         {
1356           emitcode ("movx", "a,@dptr");
1357         }
1358       return (dname ? "acc" : "a");
1359
1360     case AOP_IMMD:
1361       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1362         {
1363           SNPRINTF(buffer, sizeof(buffer),
1364                    "%s",aop->aopu.aop_immd.aop_immd2);
1365         }
1366       else if (bit16)
1367         {
1368           SNPRINTF(buffer, sizeof(buffer),
1369                    "#%s", aop->aopu.aop_immd.aop_immd1);
1370         }
1371       else if (offset)
1372         {
1373           SNPRINTF (buffer, sizeof(buffer),
1374                     "#(%s >> %d)",
1375                     aop->aopu.aop_immd.aop_immd1,
1376                     offset * 8);
1377         }
1378       else
1379         {
1380           SNPRINTF (buffer, sizeof(buffer),
1381                     "#%s",
1382                     aop->aopu.aop_immd.aop_immd1);
1383         }
1384       return Safe_strdup(buffer);
1385
1386     case AOP_DIR:
1387       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1388         {
1389           SNPRINTF (buffer, sizeof(buffer),
1390                     "(%s >> %d)",
1391                     aop->aopu.aop_dir, offset * 8);
1392         }
1393       else if (offset)
1394         {
1395           SNPRINTF (buffer, sizeof(buffer),
1396                     "(%s + %d)",
1397                     aop->aopu.aop_dir,
1398                     offset);
1399         }
1400       else
1401         {
1402           SNPRINTF (buffer, sizeof(buffer),
1403                     "%s",
1404                     aop->aopu.aop_dir);
1405         }
1406
1407       return Safe_strdup(buffer);
1408
1409     case AOP_REG:
1410       if (dname)
1411         return aop->aopu.aop_reg[offset]->dname;
1412       else
1413         return aop->aopu.aop_reg[offset]->name;
1414
1415     case AOP_CRY:
1416       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1417       emitcode ("clr", "a");
1418       emitcode ("rlc", "a");
1419       return (dname ? "acc" : "a");
1420
1421     case AOP_ACC:
1422       if (!offset && dname)
1423         return "acc";
1424       return aop->aopu.aop_str[offset];
1425
1426     case AOP_LIT:
1427       return aopLiteral (aop->aopu.aop_lit, offset);
1428
1429     case AOP_STR:
1430       aop->coff = offset;
1431       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1432           dname)
1433         return "acc";
1434
1435       return aop->aopu.aop_str[offset];
1436
1437     }
1438
1439   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1440           "aopget got unsupported aop->type");
1441   exit (1);
1442 }
1443
1444 /*-----------------------------------------------------------------*/
1445 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1446 /*                 clobber the accumulator                         */
1447 /*-----------------------------------------------------------------*/
1448 static bool
1449 aopPutUsesAcc (operand * oper, const char *s, int offset)
1450 {
1451   asmop * aop = AOP (oper);
1452
1453   if (offset > (aop->size - 1))
1454     return FALSE;
1455
1456   switch (aop->type)
1457     {
1458     case AOP_DUMMY:
1459       return TRUE;
1460     case AOP_DIR:
1461       return FALSE;
1462     case AOP_REG:
1463       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1464       return FALSE;
1465     case AOP_DPTR:
1466       return TRUE;
1467     case AOP_R0:
1468     case AOP_R1:
1469       return ((aop->paged) || (*s == '@'));
1470     case AOP_STK:
1471       return (*s == '@');
1472     case AOP_CRY:
1473       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1474     case AOP_STR:
1475       return FALSE;
1476     case AOP_IMMD:
1477       return FALSE;
1478     case AOP_ACC:
1479       return FALSE;
1480     default:
1481       /* Error case --- will have been caught already */
1482       wassert(0);
1483       return FALSE;
1484     }
1485 }
1486
1487 /*-----------------------------------------------------------------*/
1488 /* aopPut - puts a string for a aop and indicates if acc is in use */
1489 /*-----------------------------------------------------------------*/
1490 static bool
1491 aopPut (operand * result, const char *s, int offset)
1492 {
1493   bool bvolatile = isOperandVolatile (result, FALSE);
1494   bool accuse = FALSE;
1495   asmop * aop = AOP (result);
1496   const char *d = NULL;
1497
1498   if (aop->size && offset > (aop->size - 1))
1499     {
1500       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1501               "aopPut got offset > aop->size");
1502       exit (1);
1503     }
1504
1505   /* will assign value to value */
1506   /* depending on where it is ofcourse */
1507   switch (aop->type)
1508     {
1509     case AOP_DUMMY:
1510       MOVA (s);         /* read s in case it was volatile */
1511       accuse = TRUE;
1512       break;
1513
1514     case AOP_DIR:
1515       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1516         {
1517           SNPRINTF (buffer, sizeof(buffer),
1518                     "(%s >> %d)",
1519                     aop->aopu.aop_dir, offset * 8);
1520         }
1521       else if (offset)
1522         {
1523           SNPRINTF (buffer, sizeof(buffer),
1524                     "(%s + %d)",
1525                     aop->aopu.aop_dir, offset);
1526         }
1527       else
1528         {
1529           SNPRINTF (buffer, sizeof(buffer),
1530                     "%s",
1531                     aop->aopu.aop_dir);
1532         }
1533
1534       if (strcmp (buffer, s) || bvolatile)
1535         {
1536           emitcode ("mov", "%s,%s", buffer, s);
1537         }
1538       if (!strcmp (buffer, "acc"))
1539         {
1540           accuse = TRUE;
1541         }
1542       break;
1543
1544     case AOP_REG:
1545       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1546           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1547         {
1548           if (*s == '@' ||
1549               strcmp (s, "r0") == 0 ||
1550               strcmp (s, "r1") == 0 ||
1551               strcmp (s, "r2") == 0 ||
1552               strcmp (s, "r3") == 0 ||
1553               strcmp (s, "r4") == 0 ||
1554               strcmp (s, "r5") == 0 ||
1555               strcmp (s, "r6") == 0 ||
1556               strcmp (s, "r7") == 0)
1557             {
1558               emitcode ("mov", "%s,%s",
1559                         aop->aopu.aop_reg[offset]->dname, s);
1560             }
1561           else
1562             {
1563               emitcode ("mov", "%s,%s",
1564                         aop->aopu.aop_reg[offset]->name, s);
1565             }
1566         }
1567       break;
1568
1569     case AOP_DPTR:
1570       if (aop->code)
1571         {
1572           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1573                   "aopPut writing to code space");
1574           exit (1);
1575         }
1576
1577       while (offset > aop->coff)
1578         {
1579           aop->coff++;
1580           emitcode ("inc", "dptr");
1581         }
1582
1583       while (offset < aop->coff)
1584         {
1585           aop->coff--;
1586           emitcode ("lcall", "__decdptr");
1587         }
1588
1589       aop->coff = offset;
1590
1591       /* if not in accumulator */
1592       MOVA (s);
1593
1594       emitcode ("movx", "@dptr,a");
1595       break;
1596
1597     case AOP_R0:
1598     case AOP_R1:
1599       while (offset > aop->coff)
1600         {
1601           aop->coff++;
1602           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1603         }
1604       while (offset < aop->coff)
1605         {
1606           aop->coff--;
1607           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1608         }
1609       aop->coff = offset;
1610
1611       if (aop->paged)
1612         {
1613           MOVA (s);
1614           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1615         }
1616       else if (*s == '@')
1617         {
1618           MOVA (s);
1619           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1620         }
1621       else if (strcmp (s, "r0") == 0 ||
1622                strcmp (s, "r1") == 0 ||
1623                strcmp (s, "r2") == 0 ||
1624                strcmp (s, "r3") == 0 ||
1625                strcmp (s, "r4") == 0 ||
1626                strcmp (s, "r5") == 0 ||
1627                strcmp (s, "r6") == 0 ||
1628                strcmp (s, "r7") == 0)
1629         {
1630           char buffer[10];
1631           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1632           emitcode ("mov", "@%s,%s",
1633                     aop->aopu.aop_ptr->name, buffer);
1634         }
1635       else
1636         {
1637           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1638         }
1639       break;
1640
1641     case AOP_STK:
1642       if (strcmp (s, "a") == 0)
1643         {
1644           emitcode ("push", "acc");
1645         }
1646       else if (*s=='@')
1647         {
1648           MOVA(s);
1649           emitcode ("push", "acc");
1650         }
1651       else if (strcmp (s, "r0") == 0 ||
1652                strcmp (s, "r1") == 0 ||
1653                strcmp (s, "r2") == 0 ||
1654                strcmp (s, "r3") == 0 ||
1655                strcmp (s, "r4") == 0 ||
1656                strcmp (s, "r5") == 0 ||
1657                strcmp (s, "r6") == 0 ||
1658                strcmp (s, "r7") == 0)
1659         {
1660           char buffer[10];
1661           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1662           emitcode ("push", buffer);
1663         }
1664       else
1665         {
1666           emitcode ("push", s);
1667         }
1668
1669       break;
1670
1671     case AOP_CRY:
1672       // destination is carry for return-use-only
1673       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1674       // source is no literal and not in carry
1675       if ((s != zero) && (s != one) && strcmp (s, "c"))
1676         {
1677           MOVA (s);
1678           /* set C, if a >= 1 */
1679           emitcode ("add", "a,#0xff");
1680           s = "c";
1681         }
1682       // now source is zero, one or carry
1683
1684       /* if result no bit variable */
1685       if (!d)
1686         {
1687           if (!strcmp (s, "c"))
1688             {
1689               /* inefficient: move carry into A and use jz/jnz */
1690               emitcode ("clr", "a");
1691               emitcode ("rlc", "a");
1692               accuse = TRUE;
1693             }
1694           else
1695             {
1696               MOVA (s);
1697               accuse = TRUE;
1698             }
1699         }
1700       else if (s == zero)
1701           emitcode ("clr", "%s", d);
1702       else if (s == one)
1703           emitcode ("setb", "%s", d);
1704       else if (strcmp (s, d))
1705           emitcode ("mov", "%s,c", d);
1706       break;
1707
1708     case AOP_STR:
1709       aop->coff = offset;
1710       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1711         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1712       break;
1713
1714     case AOP_ACC:
1715       accuse = TRUE;
1716       aop->coff = offset;
1717       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1718         break;
1719
1720       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1721         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1722       break;
1723
1724     default:
1725       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1726               "aopPut got unsupported aop->type");
1727       exit (1);
1728     }
1729
1730     return accuse;
1731 }
1732
1733
1734 #if 0
1735 /*-----------------------------------------------------------------*/
1736 /* pointToEnd :- points to the last byte of the operand            */
1737 /*-----------------------------------------------------------------*/
1738 static void
1739 pointToEnd (asmop * aop)
1740 {
1741   int count;
1742   if (!aop)
1743     return;
1744
1745   aop->coff = count = (aop->size - 1);
1746   switch (aop->type)
1747     {
1748     case AOP_R0:
1749     case AOP_R1:
1750       while (count--)
1751         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1752       break;
1753     case AOP_DPTR:
1754       while (count--)
1755         emitcode ("inc", "dptr");
1756       break;
1757     }
1758
1759 }
1760 #endif
1761
1762 /*-----------------------------------------------------------------*/
1763 /* reAdjustPreg - points a register back to where it should        */
1764 /*-----------------------------------------------------------------*/
1765 static void
1766 reAdjustPreg (asmop * aop)
1767 {
1768   if ((aop->coff==0) || (aop->size <= 1))
1769     return;
1770
1771   switch (aop->type)
1772     {
1773     case AOP_R0:
1774     case AOP_R1:
1775       while (aop->coff--)
1776         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1777       break;
1778     case AOP_DPTR:
1779       while (aop->coff--)
1780         {
1781           emitcode ("lcall", "__decdptr");
1782         }
1783       break;
1784     }
1785   aop->coff = 0;
1786 }
1787
1788 /*-----------------------------------------------------------------*/
1789 /* opIsGptr: returns non-zero if the passed operand is       */
1790 /* a generic pointer type.             */
1791 /*-----------------------------------------------------------------*/
1792 static int
1793 opIsGptr (operand * op)
1794 {
1795   sym_link *type = operandType (op);
1796
1797   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1798     {
1799       return 1;
1800     }
1801   return 0;
1802 }
1803
1804 /*-----------------------------------------------------------------*/
1805 /* getDataSize - get the operand data size                         */
1806 /*-----------------------------------------------------------------*/
1807 static int
1808 getDataSize (operand * op)
1809 {
1810   int size;
1811   size = AOP_SIZE (op);
1812   if (size == GPTRSIZE)
1813     {
1814       sym_link *type = operandType (op);
1815       if (IS_GENPTR (type))
1816         {
1817           /* generic pointer; arithmetic operations
1818            * should ignore the high byte (pointer type).
1819            */
1820           size--;
1821         }
1822     }
1823   return size;
1824 }
1825
1826 /*-----------------------------------------------------------------*/
1827 /* outAcc - output Acc                                             */
1828 /*-----------------------------------------------------------------*/
1829 static void
1830 outAcc (operand * result)
1831 {
1832   int size, offset;
1833   size = getDataSize (result);
1834   if (size)
1835     {
1836       aopPut (result, "a", 0);
1837       size--;
1838       offset = 1;
1839       /* unsigned or positive */
1840       while (size--)
1841         {
1842           aopPut (result, zero, offset++);
1843         }
1844     }
1845 }
1846
1847 /*-----------------------------------------------------------------*/
1848 /* outBitC - output a bit C                                        */
1849 /*-----------------------------------------------------------------*/
1850 static void
1851 outBitC (operand * result)
1852 {
1853   /* if the result is bit */
1854   if (AOP_TYPE (result) == AOP_CRY)
1855     {
1856       if (!IS_OP_RUONLY (result))
1857         aopPut (result, "c", 0);
1858     }
1859   else if (AOP_TYPE (result) != AOP_DUMMY)
1860     {
1861       emitcode ("clr", "a");
1862       emitcode ("rlc", "a");
1863       outAcc (result);
1864     }
1865 }
1866
1867 /*-----------------------------------------------------------------*/
1868 /* toBoolean - emit code for orl a,operator(sizeop)                */
1869 /*-----------------------------------------------------------------*/
1870 static void
1871 toBoolean (operand * oper)
1872 {
1873   int size = AOP_SIZE (oper) - 1;
1874   int offset = 1;
1875   bool AccUsed = FALSE;
1876   bool pushedB;
1877
1878   while (!AccUsed && size--)
1879     {
1880       AccUsed |= aopGetUsesAcc(oper, offset++);
1881     }
1882
1883   size = AOP_SIZE (oper) - 1;
1884   offset = 1;
1885   MOVA (aopGet (oper, 0, FALSE, FALSE));
1886   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1887     {
1888       pushedB = pushB ();
1889       emitcode("mov", "b,a");
1890       while (--size)
1891         {
1892           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1893           emitcode ("orl", "b,a");
1894         }
1895       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1896       emitcode ("orl", "a,b");
1897       popB (pushedB);
1898     }
1899   else
1900     {
1901       while (size--)
1902         {
1903           emitcode ("orl", "a,%s",
1904                     aopGet (oper, offset++, FALSE, FALSE));
1905         }
1906     }
1907 }
1908
1909 /*-----------------------------------------------------------------*/
1910 /* toCarry - make boolean and move into carry                      */
1911 /*-----------------------------------------------------------------*/
1912 static void
1913 toCarry (operand * oper)
1914 {
1915   /* if the operand is a literal then
1916      we know what the value is */
1917   if (AOP_TYPE (oper) == AOP_LIT)
1918     {
1919       if ((int) operandLitValue (oper))
1920         SETC;
1921       else
1922         CLRC;
1923     }
1924   else if (AOP_TYPE (oper) == AOP_CRY)
1925     {
1926       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1927     }
1928   else
1929     {
1930       /* or the operand into a */
1931       toBoolean (oper);
1932       /* set C, if a >= 1 */
1933       emitcode ("add", "a,#0xff");
1934     }
1935 }
1936
1937 /*-----------------------------------------------------------------*/
1938 /* assignBit - assign operand to bit operand                       */
1939 /*-----------------------------------------------------------------*/
1940 static void
1941 assignBit (operand * result, operand * right)
1942 {
1943   /* if the right side is a literal then
1944      we know what the value is */
1945   if (AOP_TYPE (right) == AOP_LIT)
1946     {
1947       if ((int) operandLitValue (right))
1948         aopPut (result, one, 0);
1949       else
1950         aopPut (result, zero, 0);
1951     }
1952   else
1953     {
1954       toCarry (right);
1955       aopPut (result, "c", 0);
1956     }
1957 }
1958
1959
1960 /*-------------------------------------------------------------------*/
1961 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1962 /*-------------------------------------------------------------------*/
1963 static char *
1964 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1965 {
1966   char * l;
1967
1968   if (aopGetUsesAcc (oper, offset))
1969     {
1970       emitcode("mov", "b,a");
1971       MOVA (aopGet (oper, offset, bit16, dname));
1972       emitcode("xch", "a,b");
1973       aopPut (oper, "a", offset);
1974       emitcode("xch", "a,b");
1975       l = "b";
1976     }
1977   else
1978     {
1979       l = aopGet (oper, offset, bit16, dname);
1980       emitcode("xch", "a,%s", l);
1981     }
1982   return l;
1983 }
1984
1985
1986 /*-----------------------------------------------------------------*/
1987 /* genNot - generate code for ! operation                          */
1988 /*-----------------------------------------------------------------*/
1989 static void
1990 genNot (iCode * ic)
1991 {
1992   symbol *tlbl;
1993
1994   D (emitcode (";", "genNot"));
1995
1996   /* assign asmOps to operand & result */
1997   aopOp (IC_LEFT (ic), ic, FALSE);
1998   aopOp (IC_RESULT (ic), ic, TRUE);
1999
2000   /* if in bit space then a special case */
2001   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2002     {
2003       /* if left==result then cpl bit */
2004       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2005         {
2006           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2007         }
2008       else
2009         {
2010           toCarry (IC_LEFT (ic));
2011           emitcode ("cpl", "c");
2012           outBitC (IC_RESULT (ic));
2013         }
2014       goto release;
2015     }
2016
2017   toBoolean (IC_LEFT (ic));
2018
2019   /* set C, if a == 0 */
2020   tlbl = newiTempLabel (NULL);
2021   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2022   emitLabel (tlbl);
2023   outBitC (IC_RESULT (ic));
2024
2025 release:
2026   /* release the aops */
2027   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2028   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2029 }
2030
2031
2032 /*-----------------------------------------------------------------*/
2033 /* genCpl - generate code for complement                           */
2034 /*-----------------------------------------------------------------*/
2035 static void
2036 genCpl (iCode * ic)
2037 {
2038   int offset = 0;
2039   int size;
2040   symbol *tlbl;
2041   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2042
2043   D(emitcode (";", "genCpl"));
2044
2045   /* assign asmOps to operand & result */
2046   aopOp (IC_LEFT (ic), ic, FALSE);
2047   aopOp (IC_RESULT (ic), ic, TRUE);
2048
2049   /* special case if in bit space */
2050   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2051     {
2052       char *l;
2053
2054       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2055           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2056         {
2057           /* promotion rules are responsible for this strange result:
2058              bit -> int -> ~int -> bit
2059              uchar -> int -> ~int -> bit
2060           */
2061           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2062           goto release;
2063         }
2064
2065       tlbl=newiTempLabel(NULL);
2066       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2067       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2068           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2069           IS_AOP_PREG (IC_LEFT (ic)))
2070         {
2071           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2072         }
2073       else
2074         {
2075           MOVA (l);
2076           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2077         }
2078       emitLabel (tlbl);
2079       outBitC (IC_RESULT(ic));
2080       goto release;
2081     }
2082
2083   size = AOP_SIZE (IC_RESULT (ic));
2084   while (size--)
2085     {
2086       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2087       MOVA (l);
2088       emitcode ("cpl", "a");
2089       aopPut (IC_RESULT (ic), "a", offset++);
2090     }
2091
2092
2093 release:
2094   /* release the aops */
2095   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2096   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2097 }
2098
2099 /*-----------------------------------------------------------------*/
2100 /* genUminusFloat - unary minus for floating points                */
2101 /*-----------------------------------------------------------------*/
2102 static void
2103 genUminusFloat (operand * op, operand * result)
2104 {
2105   int size, offset = 0;
2106   char *l;
2107
2108   D (emitcode (";", "genUminusFloat"));
2109
2110   /* for this we just copy and then flip the bit */
2111
2112   size = AOP_SIZE (op) - 1;
2113
2114   while (size--)
2115     {
2116       aopPut (result,
2117               aopGet (op, offset, FALSE, FALSE),
2118               offset);
2119       offset++;
2120     }
2121
2122   l = aopGet (op, offset, FALSE, FALSE);
2123   MOVA (l);
2124
2125   emitcode ("cpl", "acc.7");
2126   aopPut (result, "a", offset);
2127 }
2128
2129 /*-----------------------------------------------------------------*/
2130 /* genUminus - unary minus code generation                         */
2131 /*-----------------------------------------------------------------*/
2132 static void
2133 genUminus (iCode * ic)
2134 {
2135   int offset, size;
2136   sym_link *optype;
2137
2138   D (emitcode (";", "genUminus"));
2139
2140   /* assign asmops */
2141   aopOp (IC_LEFT (ic), ic, FALSE);
2142   aopOp (IC_RESULT (ic), ic, TRUE);
2143
2144   /* if both in bit space then special
2145      case */
2146   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2147       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2148     {
2149
2150       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2151       emitcode ("cpl", "c");
2152       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2153       goto release;
2154     }
2155
2156   optype = operandType (IC_LEFT (ic));
2157
2158   /* if float then do float stuff */
2159   if (IS_FLOAT (optype))
2160     {
2161       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2162       goto release;
2163     }
2164
2165   /* otherwise subtract from zero */
2166   size = AOP_SIZE (IC_LEFT (ic));
2167   offset = 0;
2168   while (size--)
2169     {
2170       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2171       if (!strcmp (l, "a"))
2172         {
2173           if (offset == 0)
2174             SETC;
2175           emitcode ("cpl", "a");
2176           emitcode ("addc", "a,#0");
2177         }
2178       else
2179         {
2180           if (offset == 0)
2181             CLRC;
2182           emitcode ("clr", "a");
2183           emitcode ("subb", "a,%s", l);
2184         }
2185       aopPut (IC_RESULT (ic), "a", offset++);
2186     }
2187
2188   /* if any remaining bytes in the result */
2189   /* we just need to propagate the sign   */
2190   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2191     {
2192       emitcode ("rlc", "a");
2193       emitcode ("subb", "a,acc");
2194       while (size--)
2195         aopPut (IC_RESULT (ic), "a", offset++);
2196     }
2197
2198 release:
2199   /* release the aops */
2200   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2201   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2202 }
2203
2204 /*-----------------------------------------------------------------*/
2205 /* saveRegisters - will look for a call and save the registers     */
2206 /*-----------------------------------------------------------------*/
2207 static void
2208 saveRegisters (iCode * lic)
2209 {
2210   int i;
2211   iCode *ic;
2212   bitVect *rsave;
2213
2214   /* look for call */
2215   for (ic = lic; ic; ic = ic->next)
2216     if (ic->op == CALL || ic->op == PCALL)
2217       break;
2218
2219   if (!ic)
2220     {
2221       fprintf (stderr, "found parameter push with no function call\n");
2222       return;
2223     }
2224
2225   /* if the registers have been saved already or don't need to be then
2226      do nothing */
2227   if (ic->regsSaved)
2228     return;
2229   if (IS_SYMOP(IC_LEFT(ic)) &&
2230       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2231        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2232     return;
2233
2234   /* save the registers in use at this time but skip the
2235      ones for the result */
2236   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2237                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2238
2239   ic->regsSaved = 1;
2240   if (options.useXstack)
2241     {
2242       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2243       int nBits = bitVectnBitsOn (rsavebits);
2244       int count = bitVectnBitsOn (rsave);
2245
2246       if (nBits != 0)
2247         {
2248           count = count - nBits + 1;
2249           /* remove all but the first bits as they are pushed all at once */
2250           rsave = bitVectCplAnd (rsave, rsavebits);
2251           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2252         }
2253       freeBitVect (rsavebits);
2254
2255       if (count == 1)
2256         {
2257           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2258           if (reg->type == REG_BIT)
2259             {
2260               emitcode ("mov", "a,%s", reg->base);
2261             }
2262           else
2263             {
2264               emitcode ("mov", "a,%s", reg->name);
2265             }
2266           emitcode ("mov", "r0,%s", spname);
2267           emitcode ("inc", "%s", spname);// allocate before use
2268           emitcode ("movx", "@r0,a");
2269           if (bitVectBitValue (rsave, R0_IDX))
2270             emitcode ("mov", "r0,a");
2271         }
2272       else if (count != 0)
2273         {
2274           if (bitVectBitValue (rsave, R0_IDX))
2275             {
2276               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2277             }
2278           emitcode ("mov", "r0,%s", spname);
2279           MOVA ("r0");
2280           emitcode ("add", "a,#%d", count);
2281           emitcode ("mov", "%s,a", spname);
2282           for (i = 0; i < mcs51_nRegs; i++)
2283             {
2284               if (bitVectBitValue (rsave, i))
2285                 {
2286                   regs * reg = REG_WITH_INDEX (i);
2287                   if (i == R0_IDX)
2288                     {
2289                       emitcode ("pop", "acc");
2290                       emitcode ("push", "acc");
2291                     }
2292                   else if (reg->type == REG_BIT)
2293                     {
2294                       emitcode ("mov", "a,%s", reg->base);
2295                     }
2296                   else
2297                     {
2298                       emitcode ("mov", "a,%s", reg->name);
2299                     }
2300                   emitcode ("movx", "@r0,a");
2301                   if (--count)
2302                     {
2303                       emitcode ("inc", "r0");
2304                     }
2305                 }
2306             }
2307           if (bitVectBitValue (rsave, R0_IDX))
2308             {
2309               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2310             }
2311         }
2312     }
2313   else
2314     {
2315       bool bits_pushed = FALSE;
2316       for (i = 0; i < mcs51_nRegs; i++)
2317         {
2318           if (bitVectBitValue (rsave, i))
2319             {
2320               bits_pushed = pushReg (i, bits_pushed);
2321             }
2322         }
2323     }
2324   freeBitVect (rsave);
2325 }
2326
2327 /*-----------------------------------------------------------------*/
2328 /* unsaveRegisters - pop the pushed registers                      */
2329 /*-----------------------------------------------------------------*/
2330 static void
2331 unsaveRegisters (iCode * ic)
2332 {
2333   int i;
2334   bitVect *rsave;
2335
2336   /* restore the registers in use at this time but skip the
2337      ones for the result */
2338   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2339                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2340
2341   if (options.useXstack)
2342     {
2343       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2344       int nBits = bitVectnBitsOn (rsavebits);
2345       int count = bitVectnBitsOn (rsave);
2346
2347       if (nBits != 0)
2348         {
2349           count = count - nBits + 1;
2350           /* remove all but the first bits as they are popped all at once */
2351           rsave = bitVectCplAnd (rsave, rsavebits);
2352           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2353         }
2354       freeBitVect (rsavebits);
2355
2356       if (count == 1)
2357         {
2358           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2359           emitcode ("mov", "r0,%s", spname);
2360           emitcode ("dec", "r0");
2361           emitcode ("movx", "a,@r0");
2362           if (reg->type == REG_BIT)
2363             {
2364               emitcode ("mov", "%s,a", reg->base);
2365             }
2366           else
2367             {
2368               emitcode ("mov", "%s,a", reg->name);
2369             }
2370           emitcode ("dec", "%s", spname);
2371         }
2372       else if (count != 0)
2373         {
2374           emitcode ("mov", "r0,%s", spname);
2375           for (i = mcs51_nRegs; i >= 0; i--)
2376             {
2377               if (bitVectBitValue (rsave, i))
2378                 {
2379                   regs * reg = REG_WITH_INDEX (i);
2380                   emitcode ("dec", "r0");
2381                   emitcode ("movx", "a,@r0");
2382                   if (i == R0_IDX)
2383                     {
2384                       emitcode ("push", "acc");
2385                     }
2386                   else if (reg->type == REG_BIT)
2387                     {
2388                       emitcode ("mov", "%s,a", reg->base);
2389                     }
2390                   else
2391                     {
2392                       emitcode ("mov", "%s,a", reg->name);
2393                     }
2394                 }
2395             }
2396           emitcode ("mov", "%s,r0", spname);
2397           if (bitVectBitValue (rsave, R0_IDX))
2398             {
2399               emitcode ("pop", "ar0");
2400             }
2401         }
2402     }
2403   else
2404     {
2405       bool bits_popped = FALSE;
2406       for (i = mcs51_nRegs; i >= 0; i--)
2407         {
2408           if (bitVectBitValue (rsave, i))
2409             {
2410               bits_popped = popReg (i, bits_popped);
2411             }
2412         }
2413     }
2414   freeBitVect (rsave);
2415 }
2416
2417
2418 /*-----------------------------------------------------------------*/
2419 /* pushSide -                                                      */
2420 /*-----------------------------------------------------------------*/
2421 static void
2422 pushSide (operand * oper, int size, iCode * ic)
2423 {
2424   int offset = 0;
2425   int nPushed = _G.r0Pushed + _G.r1Pushed;
2426
2427   aopOp (oper, ic, FALSE);
2428
2429   if (nPushed != _G.r0Pushed + _G.r1Pushed)
2430     {
2431       while (offset < size)
2432         {
2433           char *l = aopGet (oper, offset, FALSE, TRUE);
2434           emitcode ("mov", "%s,%s", fReturn[offset++], l);
2435         }
2436       freeAsmop (oper, NULL, ic, TRUE);
2437       offset = 0;
2438       while (offset < size)
2439         {
2440           emitcode ("push", "%s", fReturn[offset++]);
2441         }
2442       return;
2443     }
2444
2445   while (size--)
2446     {
2447       char *l = aopGet (oper, offset++, FALSE, TRUE);
2448       if (AOP_TYPE (oper) != AOP_REG &&
2449           AOP_TYPE (oper) != AOP_DIR &&
2450           strcmp (l, "a"))
2451         {
2452           MOVA (l);
2453           emitcode ("push", "acc");
2454         }
2455       else
2456         {
2457           emitcode ("push", "%s", l);
2458         }
2459     }
2460
2461   freeAsmop (oper, NULL, ic, TRUE);
2462 }
2463
2464 /*-----------------------------------------------------------------*/
2465 /* assignResultValue - also indicates if acc is in use afterwards  */
2466 /*-----------------------------------------------------------------*/
2467 static bool
2468 assignResultValue (operand * oper, operand * func)
2469 {
2470   int offset = 0;
2471   int size = AOP_SIZE (oper);
2472   bool accuse = FALSE;
2473   bool pushedA = FALSE;
2474
2475   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2476     {
2477       outBitC (oper);
2478       return FALSE;
2479     }
2480
2481   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2482     {
2483       emitcode ("push", "acc");
2484       pushedA = TRUE;
2485     }
2486   while (size--)
2487     {
2488       if ((offset == 3) && pushedA)
2489         emitcode ("pop", "acc");
2490       accuse |= aopPut (oper, fReturn[offset], offset);
2491       offset++;
2492     }
2493   return accuse;
2494 }
2495
2496
2497 /*-----------------------------------------------------------------*/
2498 /* genXpush - pushes onto the external stack                       */
2499 /*-----------------------------------------------------------------*/
2500 static void
2501 genXpush (iCode * ic)
2502 {
2503   asmop *aop = newAsmop (0);
2504   regs *r;
2505   int size, offset = 0;
2506
2507   D (emitcode (";", "genXpush"));
2508
2509   aopOp (IC_LEFT (ic), ic, FALSE);
2510   r = getFreePtr (ic, &aop, FALSE);
2511
2512   size = AOP_SIZE (IC_LEFT (ic));
2513
2514   if (size == 1)
2515     {
2516       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2517       emitcode ("mov", "%s,%s", r->name, spname);
2518       emitcode ("inc", "%s", spname); // allocate space first
2519       emitcode ("movx", "@%s,a", r->name);
2520     }
2521   else
2522     {
2523       // allocate space first
2524       emitcode ("mov", "%s,%s", r->name, spname);
2525       MOVA (r->name);
2526       emitcode ("add", "a,#%d", size);
2527       emitcode ("mov", "%s,a", spname);
2528
2529       while (size--)
2530         {
2531           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2532           emitcode ("movx", "@%s,a", r->name);
2533           emitcode ("inc", "%s", r->name);
2534         }
2535     }
2536
2537   freeAsmop (NULL, aop, ic, TRUE);
2538   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2539 }
2540
2541 /*-----------------------------------------------------------------*/
2542 /* genIpush - generate code for pushing this gets a little complex */
2543 /*-----------------------------------------------------------------*/
2544 static void
2545 genIpush (iCode * ic)
2546 {
2547   int size, offset = 0;
2548   char *l;
2549   char *prev = "";
2550
2551   D (emitcode (";", "genIpush"));
2552
2553   /* if this is not a parm push : ie. it is spill push
2554      and spill push is always done on the local stack */
2555   if (!ic->parmPush)
2556     {
2557
2558       /* and the item is spilt then do nothing */
2559       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2560         return;
2561
2562       aopOp (IC_LEFT (ic), ic, FALSE);
2563       size = AOP_SIZE (IC_LEFT (ic));
2564       /* push it on the stack */
2565       while (size--)
2566         {
2567           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2568           if (*l == '#')
2569             {
2570               MOVA (l);
2571               l = "acc";
2572             }
2573           emitcode ("push", "%s", l);
2574         }
2575       return;
2576     }
2577
2578   /* this is a parameter push: in this case we call
2579      the routine to find the call and save those
2580      registers that need to be saved */
2581   saveRegisters (ic);
2582
2583   /* if use external stack then call the external
2584      stack pushing routine */
2585   if (options.useXstack)
2586     {
2587       genXpush (ic);
2588       return;
2589     }
2590
2591   /* then do the push */
2592   aopOp (IC_LEFT (ic), ic, FALSE);
2593
2594   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2595   size = AOP_SIZE (IC_LEFT (ic));
2596
2597   while (size--)
2598     {
2599       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2600       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2601           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2602         {
2603           if (strcmp (l, prev) || *l == '@')
2604             MOVA (l);
2605           emitcode ("push", "acc");
2606         }
2607       else
2608         {
2609           emitcode ("push", "%s", l);
2610         }
2611       prev = l;
2612     }
2613
2614   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2615 }
2616
2617 /*-----------------------------------------------------------------*/
2618 /* genIpop - recover the registers: can happen only for spilling   */
2619 /*-----------------------------------------------------------------*/
2620 static void
2621 genIpop (iCode * ic)
2622 {
2623   int size, offset;
2624
2625   D (emitcode (";", "genIpop"));
2626
2627   /* if the temp was not pushed then */
2628   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2629     return;
2630
2631   aopOp (IC_LEFT (ic), ic, FALSE);
2632   size = AOP_SIZE (IC_LEFT (ic));
2633   offset = (size - 1);
2634   while (size--)
2635     {
2636       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2637                                      FALSE, TRUE));
2638     }
2639
2640   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2641 }
2642
2643 /*-----------------------------------------------------------------*/
2644 /* saveRBank - saves an entire register bank on the stack          */
2645 /*-----------------------------------------------------------------*/
2646 static void
2647 saveRBank (int bank, iCode * ic, bool pushPsw)
2648 {
2649   int i;
2650   int count = 8 + (pushPsw ? 1 : 0);
2651   asmop *aop = NULL;
2652   regs *r = NULL;
2653
2654   if (options.useXstack)
2655     {
2656       if (!ic)
2657         {
2658           /* Assume r0 is available for use. */
2659           r = REG_WITH_INDEX (R0_IDX);
2660         }
2661       else
2662         {
2663           aop = newAsmop (0);
2664           r = getFreePtr (ic, &aop, FALSE);
2665         }
2666       // allocate space first
2667       emitcode ("mov", "%s,%s", r->name, spname);
2668       MOVA (r->name);
2669       emitcode ("add", "a,#%d", count);
2670       emitcode ("mov", "%s,a", spname);
2671     }
2672
2673   for (i = 0; i < 8; i++)
2674     {
2675       if (options.useXstack)
2676         {
2677           emitcode ("mov", "a,(%s+%d)",
2678                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2679           emitcode ("movx", "@%s,a", r->name);
2680           if (--count)
2681             emitcode ("inc", "%s", r->name);
2682         }
2683       else
2684         emitcode ("push", "(%s+%d)",
2685                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2686     }
2687
2688   if (pushPsw)
2689     {
2690       if (options.useXstack)
2691         {
2692           emitcode ("mov", "a,psw");
2693           emitcode ("movx", "@%s,a", r->name);
2694         }
2695       else
2696         {
2697           emitcode ("push", "psw");
2698         }
2699
2700       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2701     }
2702
2703   if (aop)
2704     {
2705       freeAsmop (NULL, aop, ic, TRUE);
2706     }
2707
2708   if (ic)
2709     {
2710       ic->bankSaved = 1;
2711     }
2712 }
2713
2714 /*-----------------------------------------------------------------*/
2715 /* unsaveRBank - restores the register bank from stack             */
2716 /*-----------------------------------------------------------------*/
2717 static void
2718 unsaveRBank (int bank, iCode * ic, bool popPsw)
2719 {
2720   int i;
2721   asmop *aop = NULL;
2722   regs *r = NULL;
2723
2724   if (options.useXstack)
2725     {
2726       if (!ic)
2727         {
2728           /* Assume r0 is available for use. */
2729           r = REG_WITH_INDEX (R0_IDX);;
2730         }
2731       else
2732         {
2733           aop = newAsmop (0);
2734           r = getFreePtr (ic, &aop, FALSE);
2735         }
2736       emitcode ("mov", "%s,%s", r->name, spname);
2737     }
2738
2739   if (popPsw)
2740     {
2741       if (options.useXstack)
2742         {
2743           emitcode ("dec", "%s", r->name);
2744           emitcode ("movx", "a,@%s", r->name);
2745           emitcode ("mov", "psw,a");
2746         }
2747       else
2748         {
2749           emitcode ("pop", "psw");
2750         }
2751     }
2752
2753   for (i = 7; i >= 0; i--)
2754     {
2755       if (options.useXstack)
2756         {
2757           emitcode ("dec", "%s", r->name);
2758           emitcode ("movx", "a,@%s", r->name);
2759           emitcode ("mov", "(%s+%d),a",
2760                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2761         }
2762       else
2763         {
2764           emitcode ("pop", "(%s+%d)",
2765                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2766         }
2767     }
2768
2769   if (options.useXstack)
2770     {
2771       emitcode ("mov", "%s,%s", spname, r->name);
2772     }
2773
2774   if (aop)
2775     {
2776       freeAsmop (NULL, aop, ic, TRUE);
2777     }
2778 }
2779
2780 /*-----------------------------------------------------------------*/
2781 /* genSend - gen code for SEND                                     */
2782 /*-----------------------------------------------------------------*/
2783 static void genSend(set *sendSet)
2784 {
2785   iCode *sic;
2786   int bit_count = 0;
2787
2788   /* first we do all bit parameters */
2789   for (sic = setFirstItem (sendSet); sic;
2790        sic = setNextItem (sendSet))
2791     {
2792       if (sic->argreg > 12)
2793         {
2794           int bit = sic->argreg-13;
2795
2796           aopOp (IC_LEFT (sic), sic, FALSE);
2797
2798           /* if left is a literal then
2799              we know what the value is */
2800           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2801             {
2802               if (((int) operandLitValue (IC_LEFT (sic))))
2803                   emitcode ("setb", "b[%d]", bit);
2804               else
2805                   emitcode ("clr", "b[%d]", bit);
2806             }
2807           else
2808             {
2809               /* we need to or */
2810               toCarry (IC_LEFT (sic));
2811               emitcode ("mov", "b[%d],c", bit);
2812             }
2813           bit_count++;
2814           BitBankUsed = 1;
2815
2816           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2817         }
2818     }
2819
2820   if (bit_count)
2821     {
2822       saveRegisters (setFirstItem (sendSet));
2823       emitcode ("mov", "bits,b");
2824     }
2825
2826   /* then we do all other parameters */
2827   for (sic = setFirstItem (sendSet); sic;
2828        sic = setNextItem (sendSet))
2829     {
2830       if (sic->argreg <= 12)
2831         {
2832           int size, offset = 0;
2833           aopOp (IC_LEFT (sic), sic, FALSE);
2834           size = AOP_SIZE (IC_LEFT (sic));
2835
2836           if (sic->argreg == 1)
2837             {
2838               while (size--)
2839                 {
2840                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2841                   if (strcmp (l, fReturn[offset]))
2842                     {
2843                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2844                     }
2845                   offset++;
2846                 }
2847             }
2848           else
2849             {
2850               while (size--)
2851                 {
2852                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2853                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2854                   offset++;
2855                 }
2856             }
2857           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2858         }
2859     }
2860 }
2861
2862 /*-----------------------------------------------------------------*/
2863 /* selectRegBank - emit code to select the register bank           */
2864 /*-----------------------------------------------------------------*/
2865 static void
2866 selectRegBank (short bank, bool keepFlags)
2867 {
2868   /* if f.e. result is in carry */
2869   if (keepFlags)
2870     {
2871       emitcode ("anl", "psw,#0xE7");
2872       if (bank)
2873         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2874     }
2875   else
2876     {
2877       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2878     }
2879 }
2880
2881 /*-----------------------------------------------------------------*/
2882 /* genCall - generates a call statement                            */
2883 /*-----------------------------------------------------------------*/
2884 static void
2885 genCall (iCode * ic)
2886 {
2887   sym_link *dtype;
2888   sym_link *etype;
2889 //  bool restoreBank = FALSE;
2890   bool swapBanks = FALSE;
2891   bool accuse = FALSE;
2892   bool accPushed = FALSE;
2893   bool resultInF0 = FALSE;
2894   bool assignResultGenerated = FALSE;
2895
2896   D (emitcode (";", "genCall"));
2897
2898   dtype = operandType (IC_LEFT (ic));
2899   etype = getSpec(dtype);
2900   /* if send set is not empty then assign */
2901   if (_G.sendSet)
2902     {
2903         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2904             genSend(reverseSet(_G.sendSet));
2905         } else {
2906             genSend(_G.sendSet);
2907         }
2908       _G.sendSet = NULL;
2909     }
2910
2911   /* if we are calling a not _naked function that is not using
2912      the same register bank then we need to save the
2913      destination registers on the stack */
2914   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2915       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2916        !IFFUNC_ISISR (dtype))
2917     {
2918       swapBanks = TRUE;
2919     }
2920
2921   /* if caller saves & we have not saved then */
2922   if (!ic->regsSaved)
2923       saveRegisters (ic);
2924
2925   if (swapBanks)
2926     {
2927         emitcode ("mov", "psw,#0x%02x",
2928            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2929     }
2930
2931   /* make the call */
2932   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2933     {
2934       if (IFFUNC_CALLEESAVES(dtype))
2935         {
2936           werror (E_BANKED_WITH_CALLEESAVES);
2937         }
2938       else
2939         {
2940           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2941                      OP_SYMBOL (IC_LEFT (ic))->rname :
2942                      OP_SYMBOL (IC_LEFT (ic))->name);
2943
2944           emitcode ("mov", "r0,#%s", l);
2945           emitcode ("mov", "r1,#(%s >> 8)", l);
2946           emitcode ("mov", "r2,#(%s >> 16)", l);
2947           emitcode ("lcall", "__sdcc_banked_call");
2948         }
2949     }
2950   else
2951     {
2952       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2953                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2954                                 OP_SYMBOL (IC_LEFT (ic))->name));
2955     }
2956
2957   if (swapBanks)
2958     {
2959       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2960     }
2961
2962   /* if we need assign a result value */
2963   if ((IS_ITEMP (IC_RESULT (ic)) &&
2964        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2965        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2966         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2967         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2968       IS_TRUE_SYMOP (IC_RESULT (ic)))
2969     {
2970
2971       _G.accInUse++;
2972       aopOp (IC_RESULT (ic), ic, FALSE);
2973       _G.accInUse--;
2974
2975       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2976       assignResultGenerated = TRUE;
2977
2978       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2979     }
2980
2981   /* adjust the stack for parameters if required */
2982   if (ic->parmBytes)
2983     {
2984       int i;
2985       if (ic->parmBytes > 3)
2986         {
2987           if (accuse)
2988             {
2989               emitcode ("push", "acc");
2990               accPushed = TRUE;
2991             }
2992           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2993               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2994               !assignResultGenerated)
2995             {
2996               emitcode ("mov", "F0,c");
2997               resultInF0 = TRUE;
2998             }
2999
3000           emitcode ("mov", "a,%s", spname);
3001           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3002           emitcode ("mov", "%s,a", spname);
3003
3004           /* unsaveRegisters from xstack needs acc, but */
3005           /* unsaveRegisters from stack needs this popped */
3006           if (accPushed && !options.useXstack)
3007             {
3008               emitcode ("pop", "acc");
3009               accPushed = FALSE;
3010             }
3011         }
3012       else
3013         for (i = 0; i < ic->parmBytes; i++)
3014           emitcode ("dec", "%s", spname);
3015     }
3016
3017   /* if we had saved some registers then unsave them */
3018   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3019     {
3020       if (accuse && !accPushed && options.useXstack)
3021         {
3022           /* xstack needs acc, but doesn't touch normal stack */
3023           emitcode ("push", "acc");
3024           accPushed = TRUE;
3025         }
3026       unsaveRegisters (ic);
3027     }
3028
3029 //  /* if register bank was saved then pop them */
3030 //  if (restoreBank)
3031 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3032
3033   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3034     {
3035       if (resultInF0)
3036           emitcode ("mov", "c,F0");
3037
3038       aopOp (IC_RESULT (ic), ic, FALSE);
3039       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3040       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3041     }
3042
3043   if (accPushed)
3044     emitcode ("pop", "acc");
3045 }
3046
3047 /*-----------------------------------------------------------------*/
3048 /* genPcall - generates a call by pointer statement                */
3049 /*-----------------------------------------------------------------*/
3050 static void
3051 genPcall (iCode * ic)
3052 {
3053   sym_link *dtype;
3054   sym_link *etype;
3055   symbol *rlbl = newiTempLabel (NULL);
3056 //  bool restoreBank=FALSE;
3057   bool swapBanks = FALSE;
3058   bool resultInF0 = FALSE;
3059
3060   D (emitcode (";", "genPcall"));
3061
3062   dtype = operandType (IC_LEFT (ic))->next;
3063   etype = getSpec(dtype);
3064   /* if caller saves & we have not saved then */
3065   if (!ic->regsSaved)
3066     saveRegisters (ic);
3067
3068   /* if we are calling a not _naked function that is not using
3069      the same register bank then we need to save the
3070      destination registers on the stack */
3071   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3072       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3073       !IFFUNC_ISISR (dtype))
3074     {
3075 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3076 //    restoreBank=TRUE;
3077       swapBanks = TRUE;
3078       // need caution message to user here
3079     }
3080
3081   if (IS_LITERAL (etype))
3082     {
3083       /* if send set is not empty then assign */
3084       if (_G.sendSet)
3085         {
3086           genSend(reverseSet(_G.sendSet));
3087           _G.sendSet = NULL;
3088         }
3089
3090       if (swapBanks)
3091         {
3092           emitcode ("mov", "psw,#0x%02x",
3093            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3094         }
3095
3096       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3097         {
3098           if (IFFUNC_CALLEESAVES (dtype))
3099             {
3100               werror (E_BANKED_WITH_CALLEESAVES);
3101             }
3102           else
3103             {
3104               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3105
3106               emitcode ("mov", "r0,#%s", l);
3107               emitcode ("mov", "r1,#(%s >> 8)", l);
3108               emitcode ("mov", "r2,#(%s >> 16)", l);
3109               emitcode ("lcall", "__sdcc_banked_call");
3110             }
3111         }
3112       else
3113         {
3114           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3115         }
3116     }
3117   else
3118     {
3119       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3120         {
3121           if (IFFUNC_CALLEESAVES (dtype))
3122             {
3123               werror (E_BANKED_WITH_CALLEESAVES);
3124             }
3125           else
3126             {
3127               aopOp (IC_LEFT (ic), ic, FALSE);
3128
3129               if (!swapBanks)
3130                 {
3131                   /* what if aopGet needs r0 or r1 ??? */
3132                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3133                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3134                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3135                 }
3136               else
3137                 {
3138                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3139                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3140                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3141                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3142                 }
3143
3144               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3145
3146               /* if send set is not empty then assign */
3147               if (_G.sendSet)
3148                 {
3149                   genSend(reverseSet(_G.sendSet));
3150                   _G.sendSet = NULL;
3151                 }
3152
3153               if (swapBanks)
3154                 {
3155                   emitcode ("mov", "psw,#0x%02x",
3156                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3157                 }
3158
3159               /* make the call */
3160               emitcode ("lcall", "__sdcc_banked_call");
3161             }
3162         }
3163       else if (_G.sendSet)
3164         {
3165           /* push the return address on to the stack */
3166           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3167           emitcode ("push", "acc");
3168           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3169           emitcode ("push", "acc");
3170
3171           /* now push the function address */
3172           pushSide (IC_LEFT (ic), FPTRSIZE, ic);
3173
3174           /* if send set is not empty then assign */
3175           if (_G.sendSet)
3176             {
3177               genSend(reverseSet(_G.sendSet));
3178               _G.sendSet = NULL;
3179             }
3180
3181           if (swapBanks)
3182             {
3183               emitcode ("mov", "psw,#0x%02x",
3184                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3185             }
3186
3187           /* make the call */
3188           emitcode ("ret", "");
3189           emitLabel (rlbl);
3190         }
3191       else /* the send set is empty */
3192         {
3193           char *l;
3194           /* now get the calling address into dptr */
3195           aopOp (IC_LEFT (ic), ic, FALSE);
3196
3197           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3198           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3199             {
3200               emitcode ("mov", "r0,%s", l);
3201               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3202               emitcode ("mov", "dph,%s", l);
3203               emitcode ("mov", "dpl,r0");
3204             }
3205           else
3206             {
3207               emitcode ("mov", "dpl,%s", l);
3208               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3209               emitcode ("mov", "dph,%s", l);
3210             }
3211
3212           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3213
3214           if (swapBanks)
3215             {
3216               emitcode ("mov", "psw,#0x%02x",
3217                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3218             }
3219
3220           /* make the call */
3221           emitcode ("lcall", "__sdcc_call_dptr");
3222         }
3223     }
3224   if (swapBanks)
3225     {
3226       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3227     }
3228
3229   /* if we need assign a result value */
3230   if ((IS_ITEMP (IC_RESULT (ic)) &&
3231        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3232        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3233         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3234       IS_TRUE_SYMOP (IC_RESULT (ic)))
3235     {
3236
3237       _G.accInUse++;
3238       aopOp (IC_RESULT (ic), ic, FALSE);
3239       _G.accInUse--;
3240
3241       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3242
3243       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3244     }
3245
3246   /* adjust the stack for parameters if required */
3247   if (ic->parmBytes)
3248     {
3249       int i;
3250       if (ic->parmBytes > 3)
3251         {
3252           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3253               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3254             {
3255               emitcode ("mov", "F0,c");
3256               resultInF0 = TRUE;
3257             }
3258
3259           emitcode ("mov", "a,%s", spname);
3260           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3261           emitcode ("mov", "%s,a", spname);
3262         }
3263       else
3264         for (i = 0; i < ic->parmBytes; i++)
3265           emitcode ("dec", "%s", spname);
3266     }
3267
3268 //  /* if register bank was saved then unsave them */
3269 //  if (restoreBank)
3270 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3271
3272   /* if we had saved some registers then unsave them */
3273   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3274     unsaveRegisters (ic);
3275
3276   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3277     {
3278       if (resultInF0)
3279           emitcode ("mov", "c,F0");
3280
3281       aopOp (IC_RESULT (ic), ic, FALSE);
3282       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3283       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3284     }
3285 }
3286
3287 /*-----------------------------------------------------------------*/
3288 /* resultRemat - result  is rematerializable                       */
3289 /*-----------------------------------------------------------------*/
3290 static int
3291 resultRemat (iCode * ic)
3292 {
3293   if (SKIP_IC (ic) || ic->op == IFX)
3294     return 0;
3295
3296   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3297     {
3298       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3299       if (sym->remat && !POINTER_SET (ic))
3300         return 1;
3301     }
3302
3303   return 0;
3304 }
3305
3306 /*-----------------------------------------------------------------*/
3307 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3308 /*-----------------------------------------------------------------*/
3309 static int
3310 regsCmp(void *p1, void *p2)
3311 {
3312   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3313 }
3314
3315 static bool
3316 inExcludeList (char *s)
3317 {
3318   const char *p = setFirstItem(options.excludeRegsSet);
3319
3320   if (p == NULL || STRCASECMP(p, "none") == 0)
3321     return FALSE;
3322
3323
3324   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3325 }
3326
3327 /*-----------------------------------------------------------------*/
3328 /* genFunction - generated code for function entry                 */
3329 /*-----------------------------------------------------------------*/
3330 static void
3331 genFunction (iCode * ic)
3332 {
3333   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3334   sym_link *ftype;
3335   bool     switchedPSW = FALSE;
3336   int      calleesaves_saved_register = -1;
3337   int      stackAdjust = sym->stack;
3338   int      accIsFree = sym->recvSize < 4;
3339   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3340   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3341
3342   _G.nRegsSaved = 0;
3343   /* create the function header */
3344   emitcode (";", "-----------------------------------------");
3345   emitcode (";", " function %s", sym->name);
3346   emitcode (";", "-----------------------------------------");
3347
3348   emitcode ("", "%s:", sym->rname);
3349   lineCurr->isLabel = 1;
3350   ftype = operandType (IC_LEFT (ic));
3351   _G.currentFunc = sym;
3352
3353   if (IFFUNC_ISNAKED(ftype))
3354   {
3355       emitcode(";", "naked function: no prologue.");
3356       return;
3357   }
3358
3359   /* here we need to generate the equates for the
3360      register bank if required */
3361   if (FUNC_REGBANK (ftype) != rbank)
3362     {
3363       int i;
3364
3365       rbank = FUNC_REGBANK (ftype);
3366       for (i = 0; i < mcs51_nRegs; i++)
3367         {
3368           if (regs8051[i].type != REG_BIT)
3369             {
3370               if (strcmp (regs8051[i].base, "0") == 0)
3371                 emitcode ("", "%s = 0x%02x",
3372                           regs8051[i].dname,
3373                           8 * rbank + regs8051[i].offset);
3374               else
3375                 emitcode ("", "%s = %s + 0x%02x",
3376                           regs8051[i].dname,
3377                           regs8051[i].base,
3378                           8 * rbank + regs8051[i].offset);
3379             }
3380         }
3381     }
3382
3383   /* if this is an interrupt service routine then
3384      save acc, b, dpl, dph  */
3385   if (IFFUNC_ISISR (sym->type))
3386     {
3387       bitVect *rsavebits;
3388
3389       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3390       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3391         {
3392           emitcode ("push", "bits");
3393           BitBankUsed = 1;
3394         }
3395       freeBitVect (rsavebits);
3396
3397       if (!inExcludeList ("acc"))
3398         emitcode ("push", "acc");
3399       if (!inExcludeList ("b"))
3400         emitcode ("push", "b");
3401       if (!inExcludeList ("dpl"))
3402         emitcode ("push", "dpl");
3403       if (!inExcludeList ("dph"))
3404         emitcode ("push", "dph");
3405       /* if this isr has no bank i.e. is going to
3406          run with bank 0 , then we need to save more
3407          registers :-) */
3408       if (!FUNC_REGBANK (sym->type))
3409         {
3410           int i;
3411
3412           /* if this function does not call any other
3413              function then we can be economical and
3414              save only those registers that are used */
3415           if (!IFFUNC_HASFCALL(sym->type))
3416             {
3417               /* if any registers used */
3418               if (sym->regsUsed)
3419                 {
3420                   /* save the registers used */
3421                   for (i = 0; i < sym->regsUsed->size; i++)
3422                     {
3423                       if (bitVectBitValue (sym->regsUsed, i))
3424                         pushReg (i, TRUE);
3425                     }
3426                 }
3427             }
3428           else
3429             {
3430               /* this function has a function call. We cannot
3431                  determine register usage so we will have to push the
3432                  entire bank */
3433                 saveRBank (0, ic, FALSE);
3434                 if (options.parms_in_bank1) {
3435                     for (i=0; i < 8 ; i++ ) {
3436                         emitcode ("push","%s",rb1regs[i]);
3437                     }
3438                 }
3439             }
3440         }
3441       else
3442         {
3443             /* This ISR uses a non-zero bank.
3444              *
3445              * We assume that the bank is available for our
3446              * exclusive use.
3447              *
3448              * However, if this ISR calls a function which uses some
3449              * other bank, we must save that bank entirely.
3450              */
3451             unsigned long banksToSave = 0;
3452
3453             if (IFFUNC_HASFCALL(sym->type))
3454             {
3455
3456 #define MAX_REGISTER_BANKS 4
3457
3458                 iCode *i;
3459                 int ix;
3460
3461                 for (i = ic; i; i = i->next)
3462                 {
3463                     if (i->op == ENDFUNCTION)
3464                     {
3465                         /* we got to the end OK. */
3466                         break;
3467                     }
3468
3469                     if (i->op == CALL)
3470                     {
3471                         sym_link *dtype;
3472
3473                         dtype = operandType (IC_LEFT(i));
3474                         if (dtype
3475                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3476                         {
3477                              /* Mark this bank for saving. */
3478                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3479                              {
3480                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3481                              }
3482                              else
3483                              {
3484                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3485                              }
3486
3487                              /* And note that we don't need to do it in
3488                               * genCall.
3489                               */
3490                              i->bankSaved = 1;
3491                         }
3492                     }
3493                     if (i->op == PCALL)
3494                     {
3495                         /* This is a mess; we have no idea what
3496                          * register bank the called function might
3497                          * use.
3498                          *
3499                          * The only thing I can think of to do is
3500                          * throw a warning and hope.
3501                          */
3502                         werror(W_FUNCPTR_IN_USING_ISR);
3503                     }
3504                 }
3505
3506                 if (banksToSave && options.useXstack)
3507                 {
3508                     /* Since we aren't passing it an ic,
3509                      * saveRBank will assume r0 is available to abuse.
3510                      *
3511                      * So switch to our (trashable) bank now, so
3512                      * the caller's R0 isn't trashed.
3513                      */
3514                     emitcode ("push", "psw");
3515                     emitcode ("mov", "psw,#0x%02x",
3516                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3517                     switchedPSW = TRUE;
3518                 }
3519
3520                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3521                 {
3522                      if (banksToSave & (1 << ix))
3523                      {
3524                          saveRBank(ix, NULL, FALSE);
3525                      }
3526                 }
3527             }
3528             // TODO: this needs a closer look
3529             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3530         }
3531
3532       /* Set the register bank to the desired value if nothing else */
3533       /* has done so yet. */
3534       if (!switchedPSW)
3535         {
3536           emitcode ("push", "psw");
3537           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3538         }
3539     }
3540   else
3541     {
3542       /* This is a non-ISR function. The caller has already switched register */
3543       /* banks, if necessary, so just handle the callee-saves option. */
3544
3545       /* if callee-save to be used for this function
3546          then save the registers being used in this function */
3547       if (IFFUNC_CALLEESAVES(sym->type))
3548         {
3549           int i;
3550
3551           /* if any registers used */
3552           if (sym->regsUsed)
3553             {
3554               bool bits_pushed = FALSE;
3555               /* save the registers used */
3556               for (i = 0; i < sym->regsUsed->size; i++)
3557                 {
3558                   if (bitVectBitValue (sym->regsUsed, i))
3559                     {
3560                       /* remember one saved register for later usage */
3561                       if (calleesaves_saved_register < 0)
3562                         calleesaves_saved_register = i;
3563                       bits_pushed = pushReg (i, bits_pushed);
3564                       _G.nRegsSaved++;
3565                     }
3566                 }
3567             }
3568         }
3569     }
3570
3571   if (fReentrant)
3572     {
3573       if (options.useXstack)
3574         {
3575           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3576             {
3577               emitcode ("mov", "r0,%s", spname);
3578               emitcode ("inc", "%s", spname);
3579               emitcode ("xch", "a,_bpx");
3580               emitcode ("movx", "@r0,a");
3581               emitcode ("inc", "r0");
3582               emitcode ("mov", "a,r0");
3583               emitcode ("xch", "a,_bpx");
3584             }
3585           if (sym->stack)
3586             {
3587               emitcode ("push", "_bp");     /* save the callers stack  */
3588               emitcode ("mov", "_bp,sp");
3589             }
3590         }
3591       else
3592         {
3593           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3594             {
3595               /* set up the stack */
3596               emitcode ("push", "_bp");     /* save the callers stack  */
3597               emitcode ("mov", "_bp,sp");
3598             }
3599         }
3600     }
3601
3602   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3603   /* before setting up the stack frame completely. */
3604   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3605     {
3606       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3607
3608       if (rsym->isitmp)
3609         {
3610           if (rsym && rsym->regType == REG_CND)
3611             rsym = NULL;
3612           if (rsym && (rsym->accuse || rsym->ruonly))
3613             rsym = NULL;
3614           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3615             rsym = rsym->usl.spillLoc;
3616         }
3617
3618       /* If the RECEIVE operand immediately spills to the first entry on the */
3619       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3620       /* rather than the usual @r0/r1 machinations. */
3621       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3622         {
3623           int ofs;
3624
3625           _G.current_iCode = ric;
3626           D(emitcode (";", "genReceive"));
3627           for (ofs=0; ofs < sym->recvSize; ofs++)
3628             {
3629               if (!strcmp (fReturn[ofs], "a"))
3630                 emitcode ("push", "acc");
3631               else
3632                 emitcode ("push", fReturn[ofs]);
3633             }
3634           stackAdjust -= sym->recvSize;
3635           if (stackAdjust<0)
3636             {
3637               assert (stackAdjust>=0);
3638               stackAdjust = 0;
3639             }
3640           _G.current_iCode = ic;
3641           ric->generated = 1;
3642           accIsFree = 1;
3643         }
3644       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3645       /* to free up the accumulator. */
3646       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3647         {
3648           int ofs;
3649
3650           _G.current_iCode = ric;
3651           D(emitcode (";", "genReceive"));
3652           for (ofs=0; ofs < sym->recvSize; ofs++)
3653             {
3654               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3655             }
3656           _G.current_iCode = ic;
3657           ric->generated = 1;
3658           accIsFree = 1;
3659         }
3660     }
3661
3662   /* adjust the stack for the function */
3663   if (stackAdjust)
3664     {
3665       int i = stackAdjust;
3666       if (i > 256)
3667         werror (W_STACK_OVERFLOW, sym->name);
3668
3669       if (i > 3 && accIsFree)
3670         {
3671           emitcode ("mov", "a,sp");
3672           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3673           emitcode ("mov", "sp,a");
3674         }
3675       else if (i > 5)
3676         {
3677           /* The accumulator is not free, so we will need another register */
3678           /* to clobber. No need to worry about a possible conflict with */
3679           /* the above early RECEIVE optimizations since they would have */
3680           /* freed the accumulator if they were generated. */
3681
3682           if (IFFUNC_CALLEESAVES(sym->type))
3683             {
3684               /* if it's a callee-saves function we need a saved register */
3685               if (calleesaves_saved_register >= 0)
3686                 {
3687                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3688                   emitcode ("mov", "a,sp");
3689                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3690                   emitcode ("mov", "sp,a");
3691                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3692                 }
3693               else
3694                 /* do it the hard way */
3695                 while (i--)
3696                   emitcode ("inc", "sp");
3697             }
3698           else
3699             {
3700               /* not callee-saves, we can clobber r0 */
3701               emitcode ("mov", "r0,a");
3702               emitcode ("mov", "a,sp");
3703               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3704               emitcode ("mov", "sp,a");
3705               emitcode ("mov", "a,r0");
3706             }
3707         }
3708       else
3709         while (i--)
3710           emitcode ("inc", "sp");
3711     }
3712
3713   if (sym->xstack)
3714     {
3715       char i = ((char) sym->xstack & 0xff);
3716
3717       if (i > 3 && accIsFree)
3718         {
3719           emitcode ("mov", "a,_spx");
3720           emitcode ("add", "a,#0x%02x", i & 0xff);
3721           emitcode ("mov", "_spx,a");
3722         }
3723       else if (i > 5)
3724         {
3725           emitcode ("push", "acc");
3726           emitcode ("mov", "a,_spx");
3727           emitcode ("add", "a,#0x%02x", i & 0xff);
3728           emitcode ("mov", "_spx,a");
3729           emitcode ("pop", "acc");
3730         }
3731       else
3732         {
3733           while (i--)
3734             emitcode ("inc", "_spx");
3735         }
3736     }
3737
3738   /* if critical function then turn interrupts off */
3739   if (IFFUNC_ISCRITICAL (ftype))
3740     {
3741       symbol *tlbl = newiTempLabel (NULL);
3742       emitcode ("setb", "c");
3743       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3744       emitcode ("clr", "c");
3745       emitLabel (tlbl);
3746       emitcode ("push", "psw"); /* save old ea via c in psw */
3747     }
3748 }
3749
3750 /*-----------------------------------------------------------------*/
3751 /* genEndFunction - generates epilogue for functions               */
3752 /*-----------------------------------------------------------------*/
3753 static void
3754 genEndFunction (iCode * ic)
3755 {
3756   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3757   lineNode *lnp = lineCurr;
3758   bitVect  *regsUsed;
3759   bitVect  *regsUsedPrologue;
3760   bitVect  *regsUnneeded;
3761   int      idx;
3762
3763   _G.currentFunc = NULL;
3764   if (IFFUNC_ISNAKED(sym->type))
3765   {
3766       emitcode(";", "naked function: no epilogue.");
3767       if (options.debug && currFunc)
3768         debugFile->writeEndFunction (currFunc, ic, 0);
3769       return;
3770   }
3771
3772   if (IFFUNC_ISCRITICAL (sym->type))
3773     {
3774       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3775         {
3776           emitcode ("rlc", "a");   /* save c in a */
3777           emitcode ("pop", "psw"); /* restore ea via c in psw */
3778           emitcode ("mov", "ea,c");
3779           emitcode ("rrc", "a");   /* restore c from a */
3780         }
3781       else
3782         {
3783           emitcode ("pop", "psw"); /* restore ea via c in psw */
3784           emitcode ("mov", "ea,c");
3785         }
3786     }
3787
3788   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3789     {
3790       if (options.useXstack)
3791         {
3792           if (sym->stack)
3793             {
3794               emitcode ("mov", "sp,_bp");
3795               emitcode ("pop", "_bp");
3796             }
3797           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3798             {
3799               emitcode ("xch", "a,_bpx");
3800               emitcode ("mov", "r0,a");
3801               emitcode ("dec", "r0");
3802               emitcode ("movx", "a,@r0");
3803               emitcode ("xch", "a,_bpx");
3804               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3805             }
3806         }
3807       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3808         {
3809           if (sym->stack)
3810             emitcode ("mov", "sp,_bp");
3811           emitcode ("pop", "_bp");
3812         }
3813     }
3814
3815   /* restore the register bank  */
3816   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3817   {
3818     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3819      || !options.useXstack)
3820     {
3821         /* Special case of ISR using non-zero bank with useXstack
3822          * is handled below.
3823          */
3824         emitcode ("pop", "psw");
3825     }
3826   }
3827
3828   if (IFFUNC_ISISR (sym->type))
3829     {
3830       bitVect *rsavebits;
3831
3832       /* now we need to restore the registers */
3833       /* if this isr has no bank i.e. is going to
3834          run with bank 0 , then we need to save more
3835          registers :-) */
3836       if (!FUNC_REGBANK (sym->type))
3837         {
3838           int i;
3839           /* if this function does not call any other
3840              function then we can be economical and
3841              save only those registers that are used */
3842           if (!IFFUNC_HASFCALL(sym->type))
3843             {
3844               /* if any registers used */
3845               if (sym->regsUsed)
3846                 {
3847                   /* save the registers used */
3848                   for (i = sym->regsUsed->size; i >= 0; i--)
3849                     {
3850                       if (bitVectBitValue (sym->regsUsed, i))
3851                         popReg (i, TRUE);
3852                     }
3853                 }
3854             }
3855           else
3856             {
3857               if (options.parms_in_bank1) {
3858                   for (i = 7 ; i >= 0 ; i-- ) {
3859                       emitcode ("pop","%s",rb1regs[i]);
3860                   }
3861               }
3862               /* this function has a function call. We cannot
3863                  determine register usage so we will have to pop the
3864                  entire bank */
3865               unsaveRBank (0, ic, FALSE);
3866             }
3867         }
3868         else
3869         {
3870             /* This ISR uses a non-zero bank.
3871              *
3872              * Restore any register banks saved by genFunction
3873              * in reverse order.
3874              */
3875             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3876             int ix;
3877
3878             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3879             {
3880                 if (savedBanks & (1 << ix))
3881                 {
3882                     unsaveRBank(ix, NULL, FALSE);
3883                 }
3884             }
3885
3886             if (options.useXstack)
3887             {
3888                 /* Restore bank AFTER calling unsaveRBank,
3889                  * since it can trash r0.
3890                  */
3891                 emitcode ("pop", "psw");
3892             }
3893         }
3894
3895       if (!inExcludeList ("dph"))
3896         emitcode ("pop", "dph");
3897       if (!inExcludeList ("dpl"))
3898         emitcode ("pop", "dpl");
3899       if (!inExcludeList ("b"))
3900         emitcode ("pop", "b");
3901       if (!inExcludeList ("acc"))
3902         emitcode ("pop", "acc");
3903
3904       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3905       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3906         emitcode ("pop", "bits");
3907       freeBitVect (rsavebits);
3908
3909       /* if debug then send end of function */
3910       if (options.debug && currFunc)
3911         {
3912           debugFile->writeEndFunction (currFunc, ic, 1);
3913         }
3914
3915       emitcode ("reti", "");
3916     }
3917   else
3918     {
3919       if (IFFUNC_CALLEESAVES(sym->type))
3920         {
3921           int i;
3922
3923           /* if any registers used */
3924           if (sym->regsUsed)
3925             {
3926               /* save the registers used */
3927               for (i = sym->regsUsed->size; i >= 0; i--)
3928                 {
3929                   if (bitVectBitValue (sym->regsUsed, i) ||
3930                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3931                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3932                 }
3933             }
3934           else if (mcs51_ptrRegReq)
3935             {
3936               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3937               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3938             }
3939
3940         }
3941
3942       /* if debug then send end of function */
3943       if (options.debug && currFunc)
3944         {
3945           debugFile->writeEndFunction (currFunc, ic, 1);
3946         }
3947
3948       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3949         {
3950           emitcode ("ljmp", "__sdcc_banked_ret");
3951         }
3952       else
3953         {
3954           emitcode ("ret", "");
3955         }
3956     }
3957
3958   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3959     return;
3960
3961   /* If this was an interrupt handler using bank 0 that called another */
3962   /* function, then all registers must be saved; nothing to optimized. */
3963   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3964       && !FUNC_REGBANK(sym->type))
3965     return;
3966
3967   /* There are no push/pops to optimize if not callee-saves or ISR */
3968   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3969     return;
3970
3971   /* If there were stack parameters, we cannot optimize without also    */
3972   /* fixing all of the stack offsets; this is too dificult to consider. */
3973   if (FUNC_HASSTACKPARM(sym->type))
3974     return;
3975
3976   /* Compute the registers actually used */
3977   regsUsed = newBitVect (mcs51_nRegs);
3978   regsUsedPrologue = newBitVect (mcs51_nRegs);
3979   while (lnp)
3980     {
3981       if (lnp->ic && lnp->ic->op == FUNCTION)
3982         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3983       else
3984         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3985
3986       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3987           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3988         break;
3989       if (!lnp->prev)
3990         break;
3991       lnp = lnp->prev;
3992     }
3993
3994   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3995       && !bitVectBitValue (regsUsed, CND_IDX))
3996     {
3997       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3998       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3999           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
4000         bitVectUnSetBit (regsUsed, CND_IDX);
4001     }
4002   else
4003     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4004
4005   /* If this was an interrupt handler that called another function */
4006   /* function, then assume A, B, DPH, & DPL may be modified by it. */
4007   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4008     {
4009       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4010       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4011       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4012       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4013       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4014     }
4015
4016   /* Remove the unneeded push/pops */
4017   regsUnneeded = newBitVect (mcs51_nRegs);
4018   while (lnp)
4019     {
4020       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4021         {
4022           if (!strncmp(lnp->line, "push", 4))
4023             {
4024               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4025               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4026                 {
4027                   connectLine (lnp->prev, lnp->next);
4028                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4029                 }
4030             }
4031           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4032             {
4033               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4034               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4035                 {
4036                   connectLine (lnp->prev, lnp->next);
4037                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4038                 }
4039             }
4040         }
4041       lnp = lnp->next;
4042     }
4043
4044   for (idx = 0; idx < regsUnneeded->size; idx++)
4045     if (bitVectBitValue (regsUnneeded, idx))
4046       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4047
4048   freeBitVect (regsUnneeded);
4049   freeBitVect (regsUsed);
4050   freeBitVect (regsUsedPrologue);
4051 }
4052
4053 /*-----------------------------------------------------------------*/
4054 /* genRet - generate code for return statement                     */
4055 /*-----------------------------------------------------------------*/
4056 static void
4057 genRet (iCode * ic)
4058 {
4059   int size, offset = 0, pushed = 0;
4060
4061   D (emitcode (";", "genRet"));
4062
4063   /* if we have no return value then
4064      just generate the "ret" */
4065   if (!IC_LEFT (ic))
4066     goto jumpret;
4067
4068   /* we have something to return then
4069      move the return value into place */
4070   aopOp (IC_LEFT (ic), ic, FALSE);
4071   size = AOP_SIZE (IC_LEFT (ic));
4072
4073   if (IS_BIT(_G.currentFunc->etype))
4074     {
4075       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4076         toCarry (IC_LEFT (ic));
4077     }
4078   else
4079     {
4080       while (size--)
4081         {
4082           char *l;
4083           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4084             {
4085               /* #NOCHANGE */
4086               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4087               emitcode ("push", "%s", l);
4088               pushed++;
4089             }
4090           else
4091             {
4092               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4093               if (strcmp (fReturn[offset], l))
4094                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4095             }
4096         }
4097
4098       while (pushed)
4099         {
4100           pushed--;
4101           if (strcmp (fReturn[pushed], "a"))
4102             emitcode ("pop", fReturn[pushed]);
4103           else
4104             emitcode ("pop", "acc");
4105         }
4106     }
4107   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4108
4109 jumpret:
4110   /* generate a jump to the return label
4111      if the next is not the return statement */
4112   if (!(ic->next && ic->next->op == LABEL &&
4113         IC_LABEL (ic->next) == returnLabel))
4114
4115     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4116
4117 }
4118
4119 /*-----------------------------------------------------------------*/
4120 /* genLabel - generates a label                                    */
4121 /*-----------------------------------------------------------------*/
4122 static void
4123 genLabel (iCode * ic)
4124 {
4125   /* special case never generate */
4126   if (IC_LABEL (ic) == entryLabel)
4127     return;
4128
4129   emitLabel (IC_LABEL (ic));
4130 }
4131
4132 /*-----------------------------------------------------------------*/
4133 /* genGoto - generates a ljmp                                      */
4134 /*-----------------------------------------------------------------*/
4135 static void
4136 genGoto (iCode * ic)
4137 {
4138   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4139 }
4140
4141 /*-----------------------------------------------------------------*/
4142 /* findLabelBackwards: walks back through the iCode chain looking  */
4143 /* for the given label. Returns number of iCode instructions     */
4144 /* between that label and given ic.          */
4145 /* Returns zero if label not found.          */
4146 /*-----------------------------------------------------------------*/
4147 static int
4148 findLabelBackwards (iCode * ic, int key)
4149 {
4150   int count = 0;
4151
4152   while (ic->prev)
4153     {
4154       ic = ic->prev;
4155       count++;
4156
4157       /* If we have any pushes or pops, we cannot predict the distance.
4158          I don't like this at all, this should be dealt with in the
4159          back-end */
4160       if (ic->op == IPUSH || ic->op == IPOP) {
4161         return 0;
4162       }
4163
4164       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4165         {
4166           return count;
4167         }
4168     }
4169
4170   return 0;
4171 }
4172
4173 /*-----------------------------------------------------------------*/
4174 /* genPlusIncr :- does addition with increment if possible         */
4175 /*-----------------------------------------------------------------*/
4176 static bool
4177 genPlusIncr (iCode * ic)
4178 {
4179   unsigned int icount;
4180   unsigned int size = getDataSize (IC_RESULT (ic));
4181
4182   /* will try to generate an increment */
4183   /* if the right side is not a literal
4184      we cannot */
4185   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4186     return FALSE;
4187
4188   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4189
4190   D(emitcode (";","genPlusIncr"));
4191
4192   /* if increment >=16 bits in register or direct space */
4193   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4194         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4195         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4196       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4197       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4198       (size > 1) &&
4199       (icount == 1))
4200     {
4201       symbol *tlbl;
4202       int emitTlbl;
4203       int labelRange;
4204
4205       /* If the next instruction is a goto and the goto target
4206        * is < 10 instructions previous to this, we can generate
4207        * jumps straight to that target.
4208        */
4209       if (ic->next && ic->next->op == GOTO
4210           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4211           && labelRange <= 10)
4212         {
4213           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4214           tlbl = IC_LABEL (ic->next);
4215           emitTlbl = 0;
4216         }
4217       else
4218         {
4219           tlbl = newiTempLabel (NULL);
4220           emitTlbl = 1;
4221         }
4222       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4223       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4224           IS_AOP_PREG (IC_RESULT (ic)))
4225         emitcode ("cjne", "%s,#0x00,%05d$",
4226                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4227                   tlbl->key + 100);
4228       else
4229         {
4230           emitcode ("clr", "a");
4231           emitcode ("cjne", "a,%s,%05d$",
4232                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4233                     tlbl->key + 100);
4234         }
4235
4236       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4237       if (size > 2)
4238         {
4239           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4240               IS_AOP_PREG (IC_RESULT (ic)))
4241             emitcode ("cjne", "%s,#0x00,%05d$",
4242                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4243                       tlbl->key + 100);
4244           else
4245             emitcode ("cjne", "a,%s,%05d$",
4246                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4247                       tlbl->key + 100);
4248
4249           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4250         }
4251       if (size > 3)
4252         {
4253           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4254               IS_AOP_PREG (IC_RESULT (ic)))
4255             emitcode ("cjne", "%s,#0x00,%05d$",
4256                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4257                       tlbl->key + 100);
4258           else
4259             {
4260               emitcode ("cjne", "a,%s,%05d$",
4261                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4262                         tlbl->key + 100);
4263             }
4264           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4265         }
4266
4267       if (emitTlbl)
4268         {
4269           emitLabel (tlbl);
4270         }
4271       return TRUE;
4272     }
4273
4274   /* if result is dptr */
4275   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4276       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4277       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4278       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4279     {
4280       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4281         return FALSE;
4282
4283       if (icount > 9)
4284         return FALSE;
4285
4286       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4287         return FALSE;
4288
4289       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4290       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4291       while (icount--)
4292         emitcode ("inc", "dptr");
4293
4294       return TRUE;
4295     }
4296
4297   /* if the literal value of the right hand side
4298      is greater than 4 then it is not worth it */
4299   if (icount > 4)
4300     return FALSE;
4301
4302   /* if the sizes are greater than 1 then we cannot */
4303   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4304       AOP_SIZE (IC_LEFT (ic)) > 1)
4305     return FALSE;
4306
4307   /* we can if the aops of the left & result match or
4308      if they are in registers and the registers are the
4309      same */
4310   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4311     {
4312       if (icount > 3)
4313         {
4314           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4315           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4316           aopPut (IC_RESULT (ic), "a", 0);
4317         }
4318       else
4319         {
4320           while (icount--)
4321             {
4322               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4323             }
4324         }
4325
4326       return TRUE;
4327     }
4328
4329   if (icount == 1)
4330     {
4331       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4332       emitcode ("inc", "a");
4333       aopPut (IC_RESULT (ic), "a", 0);
4334       return TRUE;
4335     }
4336
4337   return FALSE;
4338 }
4339
4340 /*-----------------------------------------------------------------*/
4341 /* outBitAcc - output a bit in acc                                 */
4342 /*-----------------------------------------------------------------*/
4343 static void
4344 outBitAcc (operand * result)
4345 {
4346   symbol *tlbl = newiTempLabel (NULL);
4347   /* if the result is a bit */
4348   if (AOP_TYPE (result) == AOP_CRY)
4349     {
4350       aopPut (result, "a", 0);
4351     }
4352   else
4353     {
4354       emitcode ("jz", "%05d$", tlbl->key + 100);
4355       emitcode ("mov", "a,%s", one);
4356       emitLabel (tlbl);
4357       outAcc (result);
4358     }
4359 }
4360
4361 /*-----------------------------------------------------------------*/
4362 /* genPlusBits - generates code for addition of two bits           */
4363 /*-----------------------------------------------------------------*/
4364 static void
4365 genPlusBits (iCode * ic)
4366 {
4367   D (emitcode (";", "genPlusBits"));
4368
4369   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4370   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4371     {
4372       symbol *lbl = newiTempLabel (NULL);
4373       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4374       emitcode ("cpl", "c");
4375       emitLabel (lbl);
4376       outBitC (IC_RESULT (ic));
4377     }
4378   else
4379     {
4380       emitcode ("clr", "a");
4381       emitcode ("rlc", "a");
4382       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4383       emitcode ("addc", "a,%s", zero);
4384       outAcc (IC_RESULT (ic));
4385     }
4386 }
4387
4388 #if 0
4389 /* This is the original version of this code.
4390
4391  * This is being kept around for reference,
4392  * because I am not entirely sure I got it right...
4393  */
4394 static void
4395 adjustArithmeticResult (iCode * ic)
4396 {
4397   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4398       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4399       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4400     aopPut (IC_RESULT (ic),
4401             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4402             2);
4403
4404   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4405       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4406       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4407     aopPut (IC_RESULT (ic),
4408             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4409             2);
4410
4411   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4412       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4413       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4414       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4415       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4416     {
4417       char buffer[5];
4418       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4419       aopPut (IC_RESULT (ic), buffer, 2);
4420     }
4421 }
4422 #else
4423 /* This is the pure and virtuous version of this code.
4424  * I'm pretty certain it's right, but not enough to toss the old
4425  * code just yet...
4426  */
4427 static void
4428 adjustArithmeticResult (iCode * ic)
4429 {
4430   if (opIsGptr (IC_RESULT (ic)) &&
4431       opIsGptr (IC_LEFT (ic)) &&
4432       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4433     {
4434       aopPut (IC_RESULT (ic),
4435               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4436               GPTRSIZE - 1);
4437     }
4438
4439   if (opIsGptr (IC_RESULT (ic)) &&
4440       opIsGptr (IC_RIGHT (ic)) &&
4441       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4442     {
4443       aopPut (IC_RESULT (ic),
4444               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4445               GPTRSIZE - 1);
4446     }
4447
4448   if (opIsGptr (IC_RESULT (ic)) &&
4449       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4450       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4451       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4452       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4453     {
4454       char buffer[5];
4455       SNPRINTF (buffer, sizeof(buffer),
4456                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4457       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4458     }
4459 }
4460 #endif
4461
4462 /*-----------------------------------------------------------------*/
4463 /* genPlus - generates code for addition                           */
4464 /*-----------------------------------------------------------------*/
4465 static void
4466 genPlus (iCode * ic)
4467 {
4468   int size, offset = 0;
4469   int skip_bytes = 0;
4470   char *add = "add";
4471   bool swappedLR = FALSE;
4472   operand *leftOp, *rightOp;
4473   operand * op;
4474
4475   D (emitcode (";", "genPlus"));
4476
4477   /* special cases :- */
4478
4479   aopOp (IC_LEFT (ic), ic, FALSE);
4480   aopOp (IC_RIGHT (ic), ic, FALSE);
4481   aopOp (IC_RESULT (ic), ic, TRUE);
4482
4483   /* if literal, literal on the right or
4484      if left requires ACC or right is already
4485      in ACC */
4486   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4487       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4488       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4489     {
4490       operand *t = IC_RIGHT (ic);
4491       IC_RIGHT (ic) = IC_LEFT (ic);
4492       IC_LEFT (ic) = t;
4493       swappedLR = TRUE;
4494     }
4495
4496   /* if both left & right are in bit
4497      space */
4498   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4499       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4500     {
4501       genPlusBits (ic);
4502       goto release;
4503     }
4504
4505   /* if left in bit space & right literal */
4506   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4507       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4508     {
4509       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4510       /* if result in bit space */
4511       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4512         {
4513           if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4514             emitcode ("cpl", "c");
4515           outBitC (IC_RESULT (ic));
4516         }
4517       else
4518         {
4519           size = getDataSize (IC_RESULT (ic));
4520           while (size--)
4521             {
4522               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4523               emitcode ("addc", "a,%s", zero);
4524               aopPut (IC_RESULT (ic), "a", offset++);
4525             }
4526         }
4527       goto release;
4528     }
4529
4530   /* if I can do an increment instead
4531      of add then GOOD for ME */
4532   if (genPlusIncr (ic) == TRUE)
4533     goto release;
4534
4535   size = getDataSize (IC_RESULT (ic));
4536   leftOp = IC_LEFT(ic);
4537   rightOp = IC_RIGHT(ic);
4538   op = IC_LEFT(ic);
4539
4540   /* if this is an add for an array access
4541      at a 256 byte boundary */
4542   if ( 2 == size
4543        && AOP_TYPE (op) == AOP_IMMD
4544        && IS_SYMOP (op)
4545        && IS_SPEC (OP_SYM_ETYPE (op))
4546        && SPEC_ABSA (OP_SYM_ETYPE (op))
4547        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4548      )
4549     {
4550       D(emitcode (";", "genPlus aligned array"));
4551       aopPut (IC_RESULT (ic),
4552               aopGet (rightOp, 0, FALSE, FALSE),
4553               0);
4554
4555       if( 1 == getDataSize (IC_RIGHT (ic)) )
4556         {
4557           aopPut (IC_RESULT (ic),
4558                   aopGet (leftOp, 1, FALSE, FALSE),
4559                   1);
4560         }
4561       else
4562         {
4563           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4564           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4565           aopPut (IC_RESULT (ic), "a", 1);
4566         }
4567       goto release;
4568     }
4569
4570   /* if the lower bytes of a literal are zero skip the addition */
4571   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4572     {
4573        while ((0 == ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4574               (skip_bytes+1 < size))
4575          {
4576            skip_bytes++;
4577          }
4578        if (skip_bytes)
4579          D(emitcode (";", "genPlus shortcut"));
4580     }
4581
4582   while (size--)
4583     {
4584       if( offset >= skip_bytes )
4585         {
4586           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4587             {
4588               bool pushedB;
4589               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4590               pushedB = pushB ();
4591               emitcode("xch", "a,b");
4592               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4593               emitcode (add, "a,b");
4594               popB (pushedB);
4595             }
4596           else if (aopGetUsesAcc (leftOp, offset))
4597             {
4598               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4599               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4600             }
4601           else
4602             {
4603               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4604               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4605             }
4606           aopPut (IC_RESULT (ic), "a", offset);
4607           add = "addc";  /* further adds must propagate carry */
4608         }
4609       else
4610         {
4611           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4612               isOperandVolatile (IC_RESULT (ic), FALSE))
4613             {
4614               /* just move */
4615               aopPut (IC_RESULT (ic),
4616                       aopGet (leftOp, offset, FALSE, FALSE),
4617                       offset);
4618             }
4619         }
4620       offset++;
4621     }
4622
4623   adjustArithmeticResult (ic);
4624
4625 release:
4626   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4627   if (!swappedLR)
4628     {
4629       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4630       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4631     }
4632   else
4633     {
4634       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4635       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4636     }
4637 }
4638
4639 /*-----------------------------------------------------------------*/
4640 /* genMinusDec :- does subtraction with decrement if possible      */
4641 /*-----------------------------------------------------------------*/
4642 static bool
4643 genMinusDec (iCode * ic)
4644 {
4645   unsigned int icount;
4646   unsigned int size = getDataSize (IC_RESULT (ic));
4647
4648   /* will try to generate an increment */
4649   /* if the right side is not a literal
4650      we cannot */
4651   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4652     return FALSE;
4653
4654   /* if the literal value of the right hand side
4655      is greater than 4 then it is not worth it */
4656   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4657     return FALSE;
4658
4659   D (emitcode (";", "genMinusDec"));
4660
4661   /* if decrement >=16 bits in register or direct space */
4662   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4663         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4664         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4665       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4666       (size > 1) &&
4667       (icount == 1))
4668     {
4669       symbol *tlbl;
4670       int emitTlbl;
4671       int labelRange;
4672
4673       /* If the next instruction is a goto and the goto target
4674        * is <= 10 instructions previous to this, we can generate
4675        * jumps straight to that target.
4676        */
4677       if (ic->next && ic->next->op == GOTO
4678           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4679           && labelRange <= 10)
4680         {
4681           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4682           tlbl = IC_LABEL (ic->next);
4683           emitTlbl = 0;
4684         }
4685       else
4686         {
4687           tlbl = newiTempLabel (NULL);
4688           emitTlbl = 1;
4689         }
4690
4691       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4692       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4693           IS_AOP_PREG (IC_RESULT (ic)))
4694         emitcode ("cjne", "%s,#0xff,%05d$"
4695                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4696                   ,tlbl->key + 100);
4697       else
4698         {
4699           emitcode ("mov", "a,#0xff");
4700           emitcode ("cjne", "a,%s,%05d$"
4701                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4702                     ,tlbl->key + 100);
4703         }
4704       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4705       if (size > 2)
4706         {
4707           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4708               IS_AOP_PREG (IC_RESULT (ic)))
4709             emitcode ("cjne", "%s,#0xff,%05d$"
4710                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4711                       ,tlbl->key + 100);
4712           else
4713             {
4714               emitcode ("cjne", "a,%s,%05d$"
4715                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4716                         ,tlbl->key + 100);
4717             }
4718           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4719         }
4720       if (size > 3)
4721         {
4722           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4723               IS_AOP_PREG (IC_RESULT (ic)))
4724             emitcode ("cjne", "%s,#0xff,%05d$"
4725                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4726                       ,tlbl->key + 100);
4727           else
4728             {
4729               emitcode ("cjne", "a,%s,%05d$"
4730                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4731                         ,tlbl->key + 100);
4732             }
4733           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4734         }
4735       if (emitTlbl)
4736         {
4737           emitLabel (tlbl);
4738         }
4739       return TRUE;
4740     }
4741
4742   /* if the sizes are greater than 1 then we cannot */
4743   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4744       AOP_SIZE (IC_LEFT (ic)) > 1)
4745     return FALSE;
4746
4747   /* we can if the aops of the left & result match or
4748      if they are in registers and the registers are the
4749      same */
4750   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4751     {
4752       char *l;
4753
4754       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4755         {
4756           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4757           l = "a";
4758         }
4759       else
4760         {
4761           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4762         }
4763
4764       while (icount--)
4765         {
4766           emitcode ("dec", "%s", l);
4767         }
4768
4769       if (AOP_NEEDSACC (IC_RESULT (ic)))
4770         aopPut (IC_RESULT (ic), "a", 0);
4771
4772       return TRUE;
4773     }
4774
4775   if (icount == 1)
4776     {
4777       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4778       emitcode ("dec", "a");
4779       aopPut (IC_RESULT (ic), "a", 0);
4780       return TRUE;
4781     }
4782
4783   return FALSE;
4784 }
4785
4786 /*-----------------------------------------------------------------*/
4787 /* addSign - complete with sign                                    */
4788 /*-----------------------------------------------------------------*/
4789 static void
4790 addSign (operand * result, int offset, int sign)
4791 {
4792   int size = (getDataSize (result) - offset);
4793   if (size > 0)
4794     {
4795       if (sign)
4796         {
4797           emitcode ("rlc", "a");
4798           emitcode ("subb", "a,acc");
4799           while (size--)
4800             {
4801               aopPut (result, "a", offset++);
4802             }
4803         }
4804       else
4805         {
4806           while (size--)
4807             {
4808               aopPut (result, zero, offset++);
4809             }
4810         }
4811     }
4812 }
4813
4814 /*-----------------------------------------------------------------*/
4815 /* genMinusBits - generates code for subtraction  of two bits      */
4816 /*-----------------------------------------------------------------*/
4817 static void
4818 genMinusBits (iCode * ic)
4819 {
4820   symbol *lbl = newiTempLabel (NULL);
4821
4822   D (emitcode (";", "genMinusBits"));
4823
4824   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4825     {
4826       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4827       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4828       emitcode ("cpl", "c");
4829       emitLabel (lbl);
4830       outBitC (IC_RESULT (ic));
4831     }
4832   else
4833     {
4834       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4835       emitcode ("subb", "a,acc");
4836       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4837       emitcode ("inc", "a");
4838       emitLabel (lbl);
4839       aopPut (IC_RESULT (ic), "a", 0);
4840       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4841     }
4842 }
4843
4844 /*-----------------------------------------------------------------*/
4845 /* genMinus - generates code for subtraction                       */
4846 /*-----------------------------------------------------------------*/
4847 static void
4848 genMinus (iCode * ic)
4849 {
4850   int size, offset = 0;
4851
4852   D (emitcode (";", "genMinus"));
4853
4854   aopOp (IC_LEFT (ic), ic, FALSE);
4855   aopOp (IC_RIGHT (ic), ic, FALSE);
4856   aopOp (IC_RESULT (ic), ic, TRUE);
4857
4858   /* special cases :- */
4859   /* if both left & right are in bit space */
4860   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4861       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4862     {
4863       genMinusBits (ic);
4864       goto release;
4865     }
4866
4867   /* if I can do an decrement instead
4868      of subtract then GOOD for ME */
4869   if (genMinusDec (ic) == TRUE)
4870     goto release;
4871
4872   size = getDataSize (IC_RESULT (ic));
4873
4874   /* if literal, add a,#-lit, else normal subb */
4875   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4876     {
4877       unsigned long lit = 0L;
4878       bool useCarry = FALSE;
4879
4880       lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4881       lit = -(long) lit;
4882
4883       while (size--)
4884         {
4885           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4886             {
4887               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4888               if (!offset && !size && lit== (unsigned long) -1)
4889                 {
4890                   emitcode ("dec", "a");
4891                 }
4892               else if (!useCarry)
4893                 {
4894                   /* first add without previous c */
4895                   emitcode ("add", "a,#0x%02x",
4896                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4897                   useCarry = TRUE;
4898                 }
4899               else
4900                 {
4901                   emitcode ("addc", "a,#0x%02x",
4902                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4903                 }
4904               aopPut (IC_RESULT (ic), "a", offset++);
4905             }
4906           else
4907             {
4908               /* no need to add zeroes */
4909               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4910                 {
4911                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4912                           offset);
4913                 }
4914               offset++;
4915             }
4916         }
4917     }
4918   else
4919     {
4920       operand *leftOp, *rightOp;
4921
4922       leftOp = IC_LEFT(ic);
4923       rightOp = IC_RIGHT(ic);
4924
4925       while (size--)
4926         {
4927           if (aopGetUsesAcc(rightOp, offset)) {
4928             if (aopGetUsesAcc(leftOp, offset)) {
4929               bool pushedB;
4930
4931               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4932               pushedB = pushB ();
4933               emitcode ("mov", "b,a");
4934               if (offset == 0)
4935                 CLRC;
4936               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4937               emitcode ("subb", "a,b");
4938               popB (pushedB);
4939             } else {
4940               /* reverse subtraction with 2's complement */
4941               if (offset == 0)
4942                 emitcode( "setb", "c");
4943               else
4944                 emitcode( "cpl", "c");
4945               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4946               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4947               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4948               emitcode("cpl", "a");
4949               if (size) /* skip if last byte */
4950                 emitcode( "cpl", "c");
4951             }
4952           } else {
4953             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4954             if (offset == 0)
4955               CLRC;
4956             emitcode ("subb", "a,%s",
4957                       aopGet(rightOp, offset, FALSE, TRUE));
4958           }
4959
4960           aopPut (IC_RESULT (ic), "a", offset++);
4961         }
4962     }
4963
4964   adjustArithmeticResult (ic);
4965
4966 release:
4967   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4968   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4969   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4970 }
4971
4972
4973 /*-----------------------------------------------------------------*/
4974 /* genMultbits :- multiplication of bits                           */
4975 /*-----------------------------------------------------------------*/
4976 static void
4977 genMultbits (operand * left,
4978              operand * right,
4979              operand * result)
4980 {
4981   D (emitcode (";", "genMultbits"));
4982
4983   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4984   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4985   outBitC (result);
4986 }
4987
4988 /*-----------------------------------------------------------------*/
4989 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4990 /*-----------------------------------------------------------------*/
4991 static void
4992 genMultOneByte (operand * left,
4993                 operand * right,
4994                 operand * result)
4995 {
4996   symbol *lbl;
4997   int size = AOP_SIZE (result);
4998   bool runtimeSign, compiletimeSign;
4999   bool lUnsigned, rUnsigned, pushedB;
5000
5001   D (emitcode (";", "genMultOneByte"));
5002
5003   if (size < 1 || size > 2)
5004     {
5005       /* this should never happen */
5006       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5007                AOP_SIZE(result), __FILE__, lineno);
5008       exit (1);
5009     }
5010
5011   /* (if two literals: the value is computed before) */
5012   /* if one literal, literal on the right */
5013   if (AOP_TYPE (left) == AOP_LIT)
5014     {
5015       operand *t = right;
5016       right = left;
5017       left = t;
5018       /* emitcode (";", "swapped left and right"); */
5019     }
5020   /* if no literal, unsigned on the right: shorter code */
5021   if (   AOP_TYPE (right) != AOP_LIT
5022       && SPEC_USIGN (getSpec (operandType (left))))
5023     {
5024       operand *t = right;
5025       right = left;
5026       left = t;
5027     }
5028
5029   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5030   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5031
5032   pushedB = pushB ();
5033
5034   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5035                    no need to take care about the signedness! */
5036       || (lUnsigned && rUnsigned))
5037     {
5038       /* just an unsigned 8 * 8 = 8 multiply
5039          or 8u * 8u = 16u */
5040       /* emitcode (";","unsigned"); */
5041       /* TODO: check for accumulator clash between left & right aops? */
5042
5043       if (AOP_TYPE (right) == AOP_LIT)
5044         {
5045           /* moving to accumulator first helps peepholes */
5046           MOVA (aopGet (left, 0, FALSE, FALSE));
5047           MOVB (aopGet (right, 0, FALSE, FALSE));
5048         }
5049       else
5050         {
5051           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5052           MOVA (aopGet (left, 0, FALSE, FALSE));
5053         }
5054
5055       emitcode ("mul", "ab");
5056       aopPut (result, "a", 0);
5057       if (size == 2)
5058         aopPut (result, "b", 1);
5059
5060       popB (pushedB);
5061       return;
5062     }
5063
5064   /* we have to do a signed multiply */
5065   /* emitcode (";", "signed"); */
5066
5067   /* now sign adjust for both left & right */
5068
5069   /* let's see what's needed: */
5070   /* apply negative sign during runtime */
5071   runtimeSign = FALSE;
5072   /* negative sign from literals */
5073   compiletimeSign = FALSE;
5074
5075   if (!lUnsigned)
5076     {
5077       if (AOP_TYPE(left) == AOP_LIT)
5078         {
5079           /* signed literal */
5080           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5081           if (val < 0)
5082             compiletimeSign = TRUE;
5083         }
5084       else
5085         /* signed but not literal */
5086         runtimeSign = TRUE;
5087     }
5088
5089   if (!rUnsigned)
5090     {
5091       if (AOP_TYPE(right) == AOP_LIT)
5092         {
5093           /* signed literal */
5094           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5095           if (val < 0)
5096             compiletimeSign ^= TRUE;
5097         }
5098       else
5099         /* signed but not literal */
5100         runtimeSign = TRUE;
5101     }
5102
5103   /* initialize F0, which stores the runtime sign */
5104   if (runtimeSign)
5105     {
5106       if (compiletimeSign)
5107         emitcode ("setb", "F0"); /* set sign flag */
5108       else
5109         emitcode ("clr", "F0"); /* reset sign flag */
5110     }
5111
5112   /* save the signs of the operands */
5113   if (AOP_TYPE(right) == AOP_LIT)
5114     {
5115       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5116
5117       if (!rUnsigned && val < 0)
5118         emitcode ("mov", "b,#0x%02x", -val);
5119       else
5120         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5121     }
5122   else /* ! literal */
5123     {
5124       if (rUnsigned)  /* emitcode (";", "signed"); */
5125         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5126       else
5127         {
5128           MOVA (aopGet (right, 0, FALSE, FALSE));
5129           lbl = newiTempLabel (NULL);
5130           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5131           emitcode ("cpl", "F0"); /* complement sign flag */
5132           emitcode ("cpl", "a");  /* 2's complement */
5133           emitcode ("inc", "a");
5134           emitLabel (lbl);
5135           emitcode ("mov", "b,a");
5136         }
5137     }
5138
5139   if (AOP_TYPE(left) == AOP_LIT)
5140     {
5141       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5142
5143       if (!lUnsigned && val < 0)
5144         emitcode ("mov", "a,#0x%02x", -val);
5145       else
5146         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5147     }
5148   else /* ! literal */
5149     {
5150       MOVA (aopGet (left, 0, FALSE, FALSE));
5151
5152       if (!lUnsigned)
5153         {
5154           lbl = newiTempLabel (NULL);
5155           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5156           emitcode ("cpl", "F0"); /* complement sign flag */
5157           emitcode ("cpl", "a"); /* 2's complement */
5158           emitcode ("inc", "a");
5159           emitLabel (lbl);
5160         }
5161     }
5162
5163   /* now the multiplication */
5164   emitcode ("mul", "ab");
5165   if (runtimeSign || compiletimeSign)
5166     {
5167       lbl = newiTempLabel (NULL);
5168       if (runtimeSign)
5169         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5170       emitcode ("cpl", "a"); /* lsb 2's complement */
5171       if (size != 2)
5172         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5173       else
5174         {
5175           emitcode ("add", "a,#1"); /* this sets carry flag */
5176           emitcode ("xch", "a,b");
5177           emitcode ("cpl", "a"); /* msb 2's complement */
5178           emitcode ("addc", "a,#0");
5179           emitcode ("xch", "a,b");
5180         }
5181       emitLabel (lbl);
5182     }
5183   aopPut (result, "a", 0);
5184   if (size == 2)
5185     aopPut (result, "b", 1);
5186
5187   popB (pushedB);
5188 }
5189
5190 /*-----------------------------------------------------------------*/
5191 /* genMult - generates code for multiplication                     */
5192 /*-----------------------------------------------------------------*/
5193 static void
5194 genMult (iCode * ic)
5195 {
5196   operand *left = IC_LEFT (ic);
5197   operand *right = IC_RIGHT (ic);
5198   operand *result = IC_RESULT (ic);
5199
5200   D (emitcode (";", "genMult"));
5201
5202   /* assign the asmops */
5203   aopOp (left, ic, FALSE);
5204   aopOp (right, ic, FALSE);
5205   aopOp (result, ic, TRUE);
5206
5207   /* special cases first */
5208   /* both are bits */
5209   if (AOP_TYPE (left) == AOP_CRY &&
5210       AOP_TYPE (right) == AOP_CRY)
5211     {
5212       genMultbits (left, right, result);
5213       goto release;
5214     }
5215
5216   /* if both are of size == 1 */
5217 #if 0 // one of them can be a sloc shared with the result
5218     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5219 #else
5220   if (getSize(operandType(left)) == 1 &&
5221       getSize(operandType(right)) == 1)
5222 #endif
5223     {
5224       genMultOneByte (left, right, result);
5225       goto release;
5226     }
5227
5228   /* should have been converted to function call */
5229     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5230              getSize(OP_SYMBOL(right)->type));
5231   assert (0);
5232
5233 release:
5234   freeAsmop (result, NULL, ic, TRUE);
5235   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5236   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5237 }
5238
5239 /*-----------------------------------------------------------------*/
5240 /* genDivbits :- division of bits                                  */
5241 /*-----------------------------------------------------------------*/
5242 static void
5243 genDivbits (operand * left,
5244             operand * right,
5245             operand * result)
5246 {
5247   char *l;
5248   bool pushedB;
5249
5250   D(emitcode (";", "genDivbits"));
5251
5252   pushedB = pushB ();
5253
5254   /* the result must be bit */
5255   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5256   l = aopGet (left, 0, FALSE, FALSE);
5257
5258   MOVA (l);
5259
5260   emitcode ("div", "ab");
5261   emitcode ("rrc", "a");
5262
5263   popB (pushedB);
5264
5265   aopPut (result, "c", 0);
5266 }
5267
5268 /*-----------------------------------------------------------------*/
5269 /* genDivOneByte : 8 bit division                                  */
5270 /*-----------------------------------------------------------------*/
5271 static void
5272 genDivOneByte (operand * left,
5273                operand * right,
5274                operand * result)
5275 {
5276   bool lUnsigned, rUnsigned, pushedB;
5277   bool runtimeSign, compiletimeSign;
5278   bool accuse = FALSE;
5279   bool pushedA = FALSE;
5280   symbol *lbl;
5281   int size, offset;
5282
5283   D(emitcode (";", "genDivOneByte"));
5284
5285   /* Why is it necessary that genDivOneByte() can return an int result?
5286      Have a look at:
5287
5288         volatile unsigned char uc;
5289         volatile signed char sc1, sc2;
5290         volatile int i;
5291
5292         uc  = 255;
5293         sc1 = -1;
5294         i = uc / sc1;
5295
5296      Or:
5297
5298         sc1 = -128;
5299         sc2 = -1;
5300         i = sc1 / sc2;
5301
5302      In all cases a one byte result would overflow, the following cast to int
5303      would return the wrong result.
5304
5305      Two possible solution:
5306         a) cast operands to int, if ((unsigned) / (signed)) or
5307            ((signed) / (signed))
5308         b) return an 16 bit signed int; this is what we're doing here!
5309   */
5310
5311   size = AOP_SIZE (result) - 1;
5312   offset = 1;
5313   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5314   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5315
5316   pushedB = pushB ();
5317
5318   /* signed or unsigned */
5319   if (lUnsigned && rUnsigned)
5320     {
5321       /* unsigned is easy */
5322       MOVB (aopGet (right, 0, FALSE, FALSE));
5323       MOVA (aopGet (left, 0, FALSE, FALSE));
5324       emitcode ("div", "ab");
5325       aopPut (result, "a", 0);
5326       while (size--)
5327         aopPut (result, zero, offset++);
5328
5329       popB (pushedB);
5330       return;
5331     }
5332
5333   /* signed is a little bit more difficult */
5334
5335   /* now sign adjust for both left & right */
5336
5337   /* let's see what's needed: */
5338   /* apply negative sign during runtime */
5339   runtimeSign = FALSE;
5340   /* negative sign from literals */
5341   compiletimeSign = FALSE;
5342
5343   if (!lUnsigned)
5344     {
5345       if (AOP_TYPE(left) == AOP_LIT)
5346         {
5347           /* signed literal */
5348           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5349           if (val < 0)
5350             compiletimeSign = TRUE;
5351         }
5352       else
5353         /* signed but not literal */
5354         runtimeSign = TRUE;
5355     }
5356
5357   if (!rUnsigned)
5358     {
5359       if (AOP_TYPE(right) == AOP_LIT)
5360         {
5361           /* signed literal */
5362           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5363           if (val < 0)
5364             compiletimeSign ^= TRUE;
5365         }
5366       else
5367         /* signed but not literal */
5368         runtimeSign = TRUE;
5369     }
5370
5371   /* initialize F0, which stores the runtime sign */
5372   if (runtimeSign)
5373     {
5374       if (compiletimeSign)
5375         emitcode ("setb", "F0"); /* set sign flag */
5376       else
5377         emitcode ("clr", "F0"); /* reset sign flag */
5378     }
5379
5380   /* save the signs of the operands */
5381   if (AOP_TYPE(right) == AOP_LIT)
5382     {
5383       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5384
5385       if (!rUnsigned && val < 0)
5386         emitcode ("mov", "b,#0x%02x", -val);
5387       else
5388         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5389     }
5390   else /* ! literal */
5391     {
5392       if (rUnsigned)
5393         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5394       else
5395         {
5396           MOVA (aopGet (right, 0, FALSE, FALSE));
5397           lbl = newiTempLabel (NULL);
5398           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5399           emitcode ("cpl", "F0"); /* complement sign flag */
5400           emitcode ("cpl", "a");  /* 2's complement */
5401           emitcode ("inc", "a");
5402           emitLabel (lbl);
5403           emitcode ("mov", "b,a");
5404         }
5405     }
5406
5407   if (AOP_TYPE(left) == AOP_LIT)
5408     {
5409       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5410
5411       if (!lUnsigned && val < 0)
5412         emitcode ("mov", "a,#0x%02x", -val);
5413       else
5414         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5415     }
5416   else /* ! literal */
5417     {
5418       MOVA (aopGet (left, 0, FALSE, FALSE));
5419
5420       if (!lUnsigned)
5421         {
5422           lbl = newiTempLabel (NULL);
5423           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5424           emitcode ("cpl", "F0"); /* complement sign flag */
5425           emitcode ("cpl", "a");  /* 2's complement */
5426           emitcode ("inc", "a");
5427           emitLabel (lbl);
5428         }
5429     }
5430
5431   /* now the division */
5432   emitcode ("div", "ab");
5433
5434   if (runtimeSign || compiletimeSign)
5435     {
5436       lbl = newiTempLabel (NULL);
5437       if (runtimeSign)
5438         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5439       emitcode ("cpl", "a"); /* lsb 2's complement */
5440       emitcode ("inc", "a");
5441       emitLabel (lbl);
5442
5443       accuse = aopPut (result, "a", 0);
5444       if (size > 0)
5445         {
5446           /* msb is 0x00 or 0xff depending on the sign */
5447           if (runtimeSign)
5448             {
5449               if (accuse)
5450                 {
5451                   emitcode ("push", "acc");
5452                   pushedA = TRUE;
5453                 }
5454               emitcode ("mov", "c,F0");
5455               emitcode ("subb", "a,acc");
5456               while (size--)
5457                 aopPut (result, "a", offset++);
5458             }
5459           else /* compiletimeSign */
5460             {
5461               if (aopPutUsesAcc (result, "#0xFF", offset))
5462                 {
5463                   emitcode ("push", "acc");
5464                   pushedA = TRUE;
5465                 }
5466               while (size--)
5467                 aopPut (result, "#0xff", offset++);
5468             }
5469         }
5470     }
5471   else
5472     {
5473       aopPut (result, "a", 0);
5474       while (size--)
5475         aopPut (result, zero, offset++);
5476     }
5477
5478   if (pushedA)
5479     emitcode ("pop", "acc");
5480   popB (pushedB);
5481 }
5482
5483 /*-----------------------------------------------------------------*/
5484 /* genDiv - generates code for division                            */
5485 /*-----------------------------------------------------------------*/
5486 static void
5487 genDiv (iCode * ic)
5488 {
5489   operand *left = IC_LEFT (ic);
5490   operand *right = IC_RIGHT (ic);
5491   operand *result = IC_RESULT (ic);
5492
5493   D (emitcode (";", "genDiv"));
5494
5495   /* assign the asmops */
5496   aopOp (left, ic, FALSE);
5497   aopOp (right, ic, FALSE);
5498   aopOp (result, ic, TRUE);
5499
5500   /* special cases first */
5501   /* both are bits */
5502   if (AOP_TYPE (left) == AOP_CRY &&
5503       AOP_TYPE (right) == AOP_CRY)
5504     {
5505       genDivbits (left, right, result);
5506       goto release;
5507     }
5508
5509   /* if both are of size == 1 */
5510   if (AOP_SIZE (left) == 1 &&
5511       AOP_SIZE (right) == 1)
5512     {
5513       genDivOneByte (left, right, result);
5514       goto release;
5515     }
5516
5517   /* should have been converted to function call */
5518   assert (0);
5519 release:
5520   freeAsmop (result, NULL, ic, TRUE);
5521   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5522   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5523 }
5524
5525 /*-----------------------------------------------------------------*/
5526 /* genModbits :- modulus of bits                                   */
5527 /*-----------------------------------------------------------------*/
5528 static void
5529 genModbits (operand * left,
5530             operand * right,
5531             operand * result)
5532 {
5533   char *l;
5534   bool pushedB;
5535
5536   D (emitcode (";", "genModbits"));
5537
5538   pushedB = pushB ();
5539
5540   /* the result must be bit */
5541   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5542   l = aopGet (left, 0, FALSE, FALSE);
5543
5544   MOVA (l);
5545
5546   emitcode ("div", "ab");
5547   emitcode ("mov", "a,b");
5548   emitcode ("rrc", "a");
5549
5550   popB (pushedB);
5551
5552   aopPut (result, "c", 0);
5553 }
5554
5555 /*-----------------------------------------------------------------*/
5556 /* genModOneByte : 8 bit modulus                                   */
5557 /*-----------------------------------------------------------------*/
5558 static void
5559 genModOneByte (operand * left,
5560                operand * right,
5561                operand * result)
5562 {
5563   bool lUnsigned, rUnsigned, pushedB;
5564   bool runtimeSign, compiletimeSign;
5565   symbol *lbl;
5566   int size, offset;
5567
5568   D (emitcode (";", "genModOneByte"));
5569
5570   size = AOP_SIZE (result) - 1;
5571   offset = 1;
5572   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5573   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5574
5575   /* if right is a literal, check it for 2^n */
5576   if (AOP_TYPE(right) == AOP_LIT)
5577     {
5578       unsigned char val = abs((int) operandLitValue(right));
5579       symbol *lbl2 = NULL;
5580
5581       switch (val)
5582         {
5583           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5584           case 2:
5585           case 4:
5586           case 8:
5587           case 16:
5588           case 32:
5589           case 64:
5590           case 128:
5591             if (lUnsigned)
5592               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5593                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5594               /* because iCode should have been changed to genAnd  */
5595               /* see file "SDCCopt.c", function "convertToFcall()" */
5596
5597             MOVA (aopGet (left, 0, FALSE, FALSE));
5598             emitcode ("mov", "c,acc.7");
5599             emitcode ("anl", "a,#0x%02x", val - 1);
5600             lbl = newiTempLabel (NULL);
5601             emitcode ("jz", "%05d$", (lbl->key + 100));
5602             emitcode ("jnc", "%05d$", (lbl->key + 100));
5603             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5604             if (size)
5605               {
5606                 int size2 = size;
5607                 int offs2 = offset;
5608
5609                 aopPut (result, "a", 0);
5610                 while (size2--)
5611                   aopPut (result, "#0xff", offs2++);
5612                 lbl2 = newiTempLabel (NULL);
5613                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5614               }
5615             emitLabel (lbl);
5616             aopPut (result, "a", 0);
5617             while (size--)
5618               aopPut (result, zero, offset++);
5619             if (lbl2)
5620               {
5621                 emitLabel (lbl2);
5622               }
5623             return;
5624
5625           default:
5626             break;
5627         }
5628     }
5629
5630   pushedB = pushB ();
5631
5632   /* signed or unsigned */
5633   if (lUnsigned && rUnsigned)
5634     {
5635       /* unsigned is easy */
5636       MOVB (aopGet (right, 0, FALSE, FALSE));
5637       MOVA (aopGet (left, 0, FALSE, FALSE));
5638       emitcode ("div", "ab");
5639       aopPut (result, "b", 0);
5640       while (size--)
5641         aopPut (result, zero, offset++);
5642
5643       popB (pushedB);
5644       return;
5645     }
5646
5647   /* signed is a little bit more difficult */
5648
5649   /* now sign adjust for both left & right */
5650
5651   /* modulus: sign of the right operand has no influence on the result! */
5652   if (AOP_TYPE(right) == AOP_LIT)
5653     {
5654       signed char val = (char) operandLitValue(right);
5655
5656       if (!rUnsigned && val < 0)
5657         emitcode ("mov", "b,#0x%02x", -val);
5658       else
5659         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5660     }
5661   else /* not literal */
5662     {
5663       if (rUnsigned)
5664         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5665       else
5666         {
5667           MOVA (aopGet (right, 0, FALSE, FALSE));
5668           lbl = newiTempLabel (NULL);
5669           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5670           emitcode ("cpl", "a"); /* 2's complement */
5671           emitcode ("inc", "a");
5672           emitLabel (lbl);
5673           emitcode ("mov", "b,a");
5674         }
5675     }
5676
5677   /* let's see what's needed: */
5678   /* apply negative sign during runtime */
5679   runtimeSign = FALSE;
5680   /* negative sign from literals */
5681   compiletimeSign = FALSE;
5682
5683   /* sign adjust left side */
5684   if (AOP_TYPE(left) == AOP_LIT)
5685     {
5686       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5687
5688       if (!lUnsigned && val < 0)
5689         {
5690           compiletimeSign = TRUE; /* set sign flag */
5691           emitcode ("mov", "a,#0x%02x", -val);
5692         }
5693       else
5694         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5695     }
5696   else /* ! literal */
5697     {
5698       MOVA (aopGet (left, 0, FALSE, FALSE));
5699
5700       if (!lUnsigned)
5701         {
5702           runtimeSign = TRUE;
5703           emitcode ("clr", "F0"); /* clear sign flag */
5704
5705           lbl = newiTempLabel (NULL);
5706           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5707           emitcode ("setb", "F0"); /* set sign flag */
5708           emitcode ("cpl", "a");   /* 2's complement */
5709           emitcode ("inc", "a");
5710           emitLabel (lbl);
5711         }
5712     }
5713
5714   /* now the modulus */
5715   emitcode ("div", "ab");
5716
5717   if (runtimeSign || compiletimeSign)
5718     {
5719       emitcode ("mov", "a,b");
5720       lbl = newiTempLabel (NULL);
5721       if (runtimeSign)
5722         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5723       emitcode ("cpl", "a"); /* 2's complement */
5724       emitcode ("inc", "a");
5725       emitLabel (lbl);
5726
5727       aopPut (result, "a", 0);
5728       if (size > 0)
5729         {
5730           /* msb is 0x00 or 0xff depending on the sign */
5731           if (runtimeSign)
5732             {
5733               emitcode ("mov", "c,F0");
5734               emitcode ("subb", "a,acc");
5735               while (size--)
5736                 aopPut (result, "a", offset++);
5737             }
5738           else /* compiletimeSign */
5739             while (size--)
5740               aopPut (result, "#0xff", offset++);
5741         }
5742     }
5743   else
5744     {
5745       aopPut (result, "b", 0);
5746       while (size--)
5747         aopPut (result, zero, offset++);
5748     }
5749
5750   popB (pushedB);
5751 }
5752
5753 /*-----------------------------------------------------------------*/
5754 /* genMod - generates code for division                            */
5755 /*-----------------------------------------------------------------*/
5756 static void
5757 genMod (iCode * ic)
5758 {
5759   operand *left = IC_LEFT (ic);
5760   operand *right = IC_RIGHT (ic);
5761   operand *result = IC_RESULT (ic);
5762
5763   D (emitcode (";", "genMod"));
5764
5765   /* assign the asmops */
5766   aopOp (left, ic, FALSE);
5767   aopOp (right, ic, FALSE);
5768   aopOp (result, ic, TRUE);
5769
5770   /* special cases first */
5771   /* both are bits */
5772   if (AOP_TYPE (left) == AOP_CRY &&
5773       AOP_TYPE (right) == AOP_CRY)
5774     {
5775       genModbits (left, right, result);
5776       goto release;
5777     }
5778
5779   /* if both are of size == 1 */
5780   if (AOP_SIZE (left) == 1 &&
5781       AOP_SIZE (right) == 1)
5782     {
5783       genModOneByte (left, right, result);
5784       goto release;
5785     }
5786
5787   /* should have been converted to function call */
5788   assert (0);
5789
5790 release:
5791   freeAsmop (result, NULL, ic, TRUE);
5792   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5793   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5794 }
5795
5796 /*-----------------------------------------------------------------*/
5797 /* genIfxJump :- will create a jump depending on the ifx           */
5798 /*-----------------------------------------------------------------*/
5799 static void
5800 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5801 {
5802   symbol *jlbl;
5803   symbol *tlbl = newiTempLabel (NULL);
5804   char *inst;
5805
5806   D (emitcode (";", "genIfxJump"));
5807
5808   /* if true label then we jump if condition
5809      supplied is true */
5810   if (IC_TRUE (ic))
5811     {
5812       jlbl = IC_TRUE (ic);
5813       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5814                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5815     }
5816   else
5817     {
5818       /* false label is present */
5819       jlbl = IC_FALSE (ic);
5820       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5821                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5822     }
5823   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5824     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5825   else
5826     emitcode (inst, "%05d$", tlbl->key + 100);
5827   freeForBranchAsmop (result);
5828   freeForBranchAsmop (right);
5829   freeForBranchAsmop (left);
5830   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5831   emitLabel (tlbl);
5832
5833   /* mark the icode as generated */
5834   ic->generated = 1;
5835 }
5836
5837 /*-----------------------------------------------------------------*/
5838 /* genCmp :- greater or less than comparison                       */
5839 /*-----------------------------------------------------------------*/
5840 static void
5841 genCmp (operand * left, operand * right,
5842         operand * result, iCode * ifx, int sign, iCode *ic)
5843 {
5844   int size, offset = 0;
5845   unsigned long lit = 0L;
5846   bool rightInB;
5847
5848   D (emitcode (";", "genCmp"));
5849
5850   /* if left & right are bit variables */
5851   if (AOP_TYPE (left) == AOP_CRY &&
5852       AOP_TYPE (right) == AOP_CRY)
5853     {
5854       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5855       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5856     }
5857   else
5858     {
5859       /* subtract right from left if at the
5860          end the carry flag is set then we know that
5861          left is greater than right */
5862       size = max (AOP_SIZE (left), AOP_SIZE (right));
5863
5864       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5865       if ((size == 1) && !sign &&
5866           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5867         {
5868           symbol *lbl = newiTempLabel (NULL);
5869           emitcode ("cjne", "%s,%s,%05d$",
5870                     aopGet (left, offset, FALSE, FALSE),
5871                     aopGet (right, offset, FALSE, FALSE),
5872                     lbl->key + 100);
5873           emitLabel (lbl);
5874         }
5875       else
5876         {
5877           if (AOP_TYPE (right) == AOP_LIT)
5878             {
5879               lit = ulFromVal (AOP (right)->aopu.aop_lit);
5880               /* optimize if(x < 0) or if(x >= 0) */
5881               if (lit == 0L)
5882                 {
5883                   if (!sign)
5884                     {
5885                       CLRC;
5886                     }
5887                   else
5888                     {
5889                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5890                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5891                         {
5892                           genIfxJump (ifx, "acc.7", left, right, result);
5893                           freeAsmop (right, NULL, ic, TRUE);
5894                           freeAsmop (left, NULL, ic, TRUE);
5895
5896                           return;
5897                         }
5898                       else
5899                         {
5900                           emitcode ("rlc", "a");
5901                         }
5902                     }
5903                   goto release;
5904                 }
5905               else
5906                 {//nonzero literal
5907                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5908                   while (size && (bytelit == 0))
5909                     {
5910                       offset++;
5911                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5912                       size--;
5913                     }
5914                   CLRC;
5915                   while (size--)
5916                     {
5917                       MOVA (aopGet (left, offset, FALSE, FALSE));
5918                       if (sign && size == 0)
5919                         {
5920                           emitcode ("xrl", "a,#0x80");
5921                           emitcode ("subb", "a,#0x%02x",
5922                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5923                         }
5924                       else
5925                         {
5926                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5927                         }
5928                       offset++;
5929                     }
5930                   goto release;
5931                 }
5932             }
5933           CLRC;
5934           while (size--)
5935             {
5936               bool pushedB = FALSE;
5937               rightInB = aopGetUsesAcc(right, offset);
5938               if (rightInB)
5939                 {
5940                   pushedB = pushB ();
5941                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5942                 }
5943               MOVA (aopGet (left, offset, FALSE, FALSE));
5944               if (sign && size == 0)
5945                 {
5946                   emitcode ("xrl", "a,#0x80");
5947                   if (!rightInB)
5948                     {
5949                       pushedB = pushB ();
5950                       rightInB++;
5951                       MOVB (aopGet (right, offset, FALSE, FALSE));
5952                     }
5953                   emitcode ("xrl", "b,#0x80");
5954                   emitcode ("subb", "a,b");
5955                 }
5956               else
5957                 {
5958                   if (rightInB)
5959                     emitcode ("subb", "a,b");
5960                   else
5961                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5962                 }
5963               if (rightInB)
5964                 popB (pushedB);
5965               offset++;
5966             }
5967         }
5968     }
5969
5970 release:
5971   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5972   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5973   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5974     {
5975       outBitC (result);
5976     }
5977   else
5978     {
5979       /* if the result is used in the next
5980          ifx conditional branch then generate
5981          code a little differently */
5982       if (ifx)
5983         {
5984           genIfxJump (ifx, "c", NULL, NULL, result);
5985         }
5986       else
5987         {
5988           outBitC (result);
5989         }
5990       /* leave the result in acc */
5991     }
5992 }
5993
5994 /*-----------------------------------------------------------------*/
5995 /* genCmpGt :- greater than comparison                             */
5996 /*-----------------------------------------------------------------*/
5997 static void
5998 genCmpGt (iCode * ic, iCode * ifx)
5999 {
6000   operand *left, *right, *result;
6001   sym_link *letype, *retype;
6002   int sign;
6003
6004   D (emitcode (";", "genCmpGt"));
6005
6006   left = IC_LEFT (ic);
6007   right = IC_RIGHT (ic);
6008   result = IC_RESULT (ic);
6009
6010   letype = getSpec (operandType (left));
6011   retype = getSpec (operandType (right));
6012   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6013            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6014   /* assign the asmops */
6015   aopOp (result, ic, TRUE);
6016   aopOp (left, ic, FALSE);
6017   aopOp (right, ic, FALSE);
6018
6019   genCmp (right, left, result, ifx, sign, ic);
6020
6021   freeAsmop (result, NULL, ic, TRUE);
6022 }
6023
6024 /*-----------------------------------------------------------------*/
6025 /* genCmpLt - less than comparisons                                */
6026 /*-----------------------------------------------------------------*/
6027 static void
6028 genCmpLt (iCode * ic, iCode * ifx)
6029 {
6030   operand *left, *right, *result;
6031   sym_link *letype, *retype;
6032   int sign;
6033
6034   D (emitcode (";", "genCmpLt"));
6035
6036   left = IC_LEFT (ic);
6037   right = IC_RIGHT (ic);
6038   result = IC_RESULT (ic);
6039
6040   letype = getSpec (operandType (left));
6041   retype = getSpec (operandType (right));
6042   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6043            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6044   /* assign the asmops */
6045   aopOp (result, ic, TRUE);
6046   aopOp (left, ic, FALSE);
6047   aopOp (right, ic, FALSE);
6048
6049   genCmp (left, right, result, ifx, sign, ic);
6050
6051   freeAsmop (result, NULL, ic, TRUE);
6052 }
6053
6054 /*-----------------------------------------------------------------*/
6055 /* gencjneshort - compare and jump if not equal                    */
6056 /*-----------------------------------------------------------------*/
6057 static void
6058 gencjneshort (operand * left, operand * right, symbol * lbl)
6059 {
6060   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6061   int offset = 0;
6062   unsigned long lit = 0L;
6063
6064   D (emitcode (";", "gencjneshort"));
6065
6066   /* if the left side is a literal or
6067      if the right is in a pointer register and left
6068      is not */
6069   if ((AOP_TYPE (left) == AOP_LIT)  ||
6070       (AOP_TYPE (left) == AOP_IMMD) ||
6071       (AOP_TYPE (left) == AOP_DIR)  ||
6072       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6073     {
6074       operand *t = right;
6075       right = left;
6076       left = t;
6077     }
6078
6079   if (AOP_TYPE (right) == AOP_LIT)
6080     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6081
6082   /* if the right side is a literal then anything goes */
6083   if (AOP_TYPE (right) == AOP_LIT &&
6084       AOP_TYPE (left) != AOP_DIR  &&
6085       AOP_TYPE (left) != AOP_IMMD)
6086     {
6087       while (size--)
6088         {
6089           emitcode ("cjne", "%s,%s,%05d$",
6090                     aopGet (left, offset, FALSE, FALSE),
6091                     aopGet (right, offset, FALSE, FALSE),
6092                     lbl->key + 100);
6093           offset++;
6094         }
6095     }
6096
6097   /* if the right side is in a register or in direct space or
6098      if the left is a pointer register & right is not */
6099   else if (AOP_TYPE (right) == AOP_REG ||
6100            AOP_TYPE (right) == AOP_DIR ||
6101            AOP_TYPE (right) == AOP_LIT ||
6102            AOP_TYPE (right) == AOP_IMMD ||
6103            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6104            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6105     {
6106       while (size--)
6107         {
6108           MOVA (aopGet (left, offset, FALSE, FALSE));
6109           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6110               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6111             emitcode ("jnz", "%05d$", lbl->key + 100);
6112           else
6113             emitcode ("cjne", "a,%s,%05d$",
6114                       aopGet (right, offset, FALSE, TRUE),
6115                       lbl->key + 100);
6116           offset++;
6117         }
6118     }
6119   else
6120     {
6121       /* right is a pointer reg need both a & b */
6122       while (size--)
6123         {
6124           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6125           wassertl(!BINUSE, "B was in use");
6126           MOVB (aopGet (left, offset, FALSE, FALSE));
6127           MOVA (aopGet (right, offset, FALSE, FALSE));
6128           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6129           offset++;
6130         }
6131     }
6132 }
6133
6134 /*-----------------------------------------------------------------*/
6135 /* gencjne - compare and jump if not equal                         */
6136 /*-----------------------------------------------------------------*/
6137 static void
6138 gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
6139 {
6140   symbol *tlbl = newiTempLabel (NULL);
6141
6142   D (emitcode (";", "gencjne"));
6143
6144   gencjneshort (left, right, lbl);
6145
6146   if (useCarry)
6147       SETC;
6148   else
6149       MOVA (one);
6150   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6151   emitLabel (lbl);
6152   if (useCarry)
6153       CLRC;
6154   else
6155       MOVA (zero);
6156   emitLabel (tlbl);
6157 }
6158
6159 /*-----------------------------------------------------------------*/
6160 /* genCmpEq - generates code for equal to                          */
6161 /*-----------------------------------------------------------------*/
6162 static void
6163 genCmpEq (iCode * ic, iCode * ifx)
6164 {
6165   bool swappedLR = FALSE;
6166   operand *left, *right, *result;
6167
6168   D (emitcode (";", "genCmpEq"));
6169
6170   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6171   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6172   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6173
6174   /* if literal, literal on the right or
6175      if the right is in a pointer register and left
6176      is not */
6177   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6178       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6179     {
6180       operand *t = IC_RIGHT (ic);
6181       IC_RIGHT (ic) = IC_LEFT (ic);
6182       IC_LEFT (ic) = t;
6183       swappedLR = TRUE;
6184     }
6185
6186   if (ifx && !AOP_SIZE (result))
6187     {
6188       symbol *tlbl;
6189       /* if they are both bit variables */
6190       if (AOP_TYPE (left) == AOP_CRY &&
6191           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6192         {
6193           if (AOP_TYPE (right) == AOP_LIT)
6194             {
6195               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6196               if (lit == 0L)
6197                 {
6198                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6199                   emitcode ("cpl", "c");
6200                 }
6201               else if (lit == 1L)
6202                 {
6203                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6204                 }
6205               else
6206                 {
6207                   emitcode ("clr", "c");
6208                 }
6209               /* AOP_TYPE(right) == AOP_CRY */
6210             }
6211           else
6212             {
6213               symbol *lbl = newiTempLabel (NULL);
6214               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6215               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6216               emitcode ("cpl", "c");
6217               emitLabel (lbl);
6218             }
6219           /* if true label then we jump if condition
6220              supplied is true */
6221           tlbl = newiTempLabel (NULL);
6222           if (IC_TRUE (ifx))
6223             {
6224               emitcode ("jnc", "%05d$", tlbl->key + 100);
6225               freeForBranchAsmop (result);
6226               freeForBranchAsmop (right);
6227               freeForBranchAsmop (left);
6228               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6229             }
6230           else
6231             {
6232               emitcode ("jc", "%05d$", tlbl->key + 100);
6233               freeForBranchAsmop (result);
6234               freeForBranchAsmop (right);
6235               freeForBranchAsmop (left);
6236               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6237             }
6238           emitLabel (tlbl);
6239         }
6240       else
6241         {
6242           tlbl = newiTempLabel (NULL);
6243           gencjneshort (left, right, tlbl);
6244           if (IC_TRUE (ifx))
6245             {
6246               freeForBranchAsmop (result);
6247               freeForBranchAsmop (right);
6248               freeForBranchAsmop (left);
6249               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6250               emitLabel (tlbl);
6251             }
6252           else
6253             {
6254               symbol *lbl = newiTempLabel (NULL);
6255               emitcode ("sjmp", "%05d$", lbl->key + 100);
6256               emitLabel (tlbl);
6257               freeForBranchAsmop (result);
6258               freeForBranchAsmop (right);
6259               freeForBranchAsmop (left);
6260               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6261               emitLabel (lbl);
6262             }
6263         }
6264       /* mark the icode as generated */
6265       ifx->generated = 1;
6266       goto release;
6267     }
6268
6269   /* if they are both bit variables */
6270   if (AOP_TYPE (left) == AOP_CRY &&
6271       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6272     {
6273       if (AOP_TYPE (right) == AOP_LIT)
6274         {
6275           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6276           if (lit == 0L)
6277             {
6278               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6279               emitcode ("cpl", "c");
6280             }
6281           else if (lit == 1L)
6282             {
6283               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6284             }
6285           else
6286             {
6287               emitcode ("clr", "c");
6288             }
6289           /* AOP_TYPE(right) == AOP_CRY */
6290         }
6291       else
6292         {
6293           symbol *lbl = newiTempLabel (NULL);
6294           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6295           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6296           emitcode ("cpl", "c");
6297           emitLabel (lbl);
6298         }
6299       /* c = 1 if egal */
6300       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6301         {
6302           outBitC (result);
6303           goto release;
6304         }
6305       if (ifx)
6306         {
6307           genIfxJump (ifx, "c", left, right, result);
6308           goto release;
6309         }
6310       /* if the result is used in an arithmetic operation
6311          then put the result in place */
6312       outBitC (result);
6313     }
6314   else
6315     {
6316       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6317         {
6318           gencjne (left, right, newiTempLabel (NULL), TRUE);
6319           aopPut (result, "c", 0);
6320           goto release;
6321         }
6322       gencjne (left, right, newiTempLabel (NULL), FALSE);
6323       if (ifx)
6324         {
6325           genIfxJump (ifx, "a", left, right, result);
6326           goto release;
6327         }
6328       /* if the result is used in an arithmetic operation
6329          then put the result in place */
6330       if (AOP_TYPE (result) != AOP_CRY)
6331         outAcc (result);
6332       /* leave the result in acc */
6333     }
6334
6335 release:
6336   freeAsmop (result, NULL, ic, TRUE);
6337   if (!swappedLR)
6338     {
6339       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6340       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6341     }
6342   else
6343     {
6344       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6345       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6346     }
6347 }
6348
6349 /*-----------------------------------------------------------------*/
6350 /* ifxForOp - returns the icode containing the ifx for operand     */
6351 /*-----------------------------------------------------------------*/
6352 static iCode *
6353 ifxForOp (operand * op, iCode * ic)
6354 {
6355   /* if true symbol then needs to be assigned */
6356   if (IS_TRUE_SYMOP (op))
6357     return NULL;
6358
6359   /* if this has register type condition and
6360      the next instruction is ifx with the same operand
6361      and live to of the operand is upto the ifx only then */
6362   if (ic->next &&
6363       ic->next->op == IFX &&
6364       IC_COND (ic->next)->key == op->key &&
6365       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6366     return ic->next;
6367
6368   return NULL;
6369 }
6370
6371 /*-----------------------------------------------------------------*/
6372 /* hasInc - operand is incremented before any other use            */
6373 /*-----------------------------------------------------------------*/
6374 static iCode *
6375 hasInc (operand *op, iCode *ic, int osize)
6376 {
6377   sym_link *type = operandType(op);
6378   sym_link *retype = getSpec (type);
6379   iCode *lic = ic->next;
6380   int isize ;
6381
6382   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6383   if (!IS_SYMOP(op)) return NULL;
6384
6385   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6386   if (IS_AGGREGATE(type->next)) return NULL;
6387   if (osize != (isize = getSize(type->next))) return NULL;
6388
6389   while (lic) {
6390     /* if operand of the form op = op + <sizeof *op> */
6391     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6392         isOperandEqual(IC_RESULT(lic),op) &&
6393         isOperandLiteral(IC_RIGHT(lic)) &&
6394         operandLitValue(IC_RIGHT(lic)) == isize) {
6395       return lic;
6396     }
6397     /* if the operand used or deffed */
6398     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6399       return NULL;
6400     }
6401     /* if GOTO or IFX */
6402     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6403     lic = lic->next;
6404   }
6405   return NULL;
6406 }
6407
6408 /*-----------------------------------------------------------------*/
6409 /* genAndOp - for && operation                                     */
6410 /*-----------------------------------------------------------------*/
6411 static void
6412 genAndOp (iCode * ic)
6413 {
6414   operand *left, *right, *result;
6415   symbol *tlbl;
6416
6417   D (emitcode (";", "genAndOp"));
6418
6419   /* note here that && operations that are in an
6420      if statement are taken away by backPatchLabels
6421      only those used in arthmetic operations remain */
6422   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6423   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6424   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6425
6426   /* if both are bit variables */
6427   if (AOP_TYPE (left) == AOP_CRY &&
6428       AOP_TYPE (right) == AOP_CRY)
6429     {
6430       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6431       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6432       outBitC (result);
6433     }
6434   else
6435     {
6436       tlbl = newiTempLabel (NULL);
6437       toBoolean (left);
6438       emitcode ("jz", "%05d$", tlbl->key + 100);
6439       toBoolean (right);
6440       emitLabel (tlbl);
6441       outBitAcc (result);
6442     }
6443
6444   freeAsmop (result, NULL, ic, TRUE);
6445   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6446   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6447 }
6448
6449
6450 /*-----------------------------------------------------------------*/
6451 /* genOrOp - for || operation                                      */
6452 /*-----------------------------------------------------------------*/
6453 static void
6454 genOrOp (iCode * ic)
6455 {
6456   operand *left, *right, *result;
6457   symbol *tlbl;
6458
6459   D (emitcode (";", "genOrOp"));
6460
6461   /* note here that || operations that are in an
6462      if statement are taken away by backPatchLabels
6463      only those used in arthmetic operations remain */
6464   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6465   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6466   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6467
6468   /* if both are bit variables */
6469   if (AOP_TYPE (left) == AOP_CRY &&
6470       AOP_TYPE (right) == AOP_CRY)
6471     {
6472       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6473       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6474       outBitC (result);
6475     }
6476   else
6477     {
6478       tlbl = newiTempLabel (NULL);
6479       toBoolean (left);
6480       emitcode ("jnz", "%05d$", tlbl->key + 100);
6481       toBoolean (right);
6482       emitLabel (tlbl);
6483       outBitAcc (result);
6484     }
6485
6486   freeAsmop (result, NULL, ic, TRUE);
6487   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6488   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6489 }
6490
6491 /*-----------------------------------------------------------------*/
6492 /* isLiteralBit - test if lit == 2^n                               */
6493 /*-----------------------------------------------------------------*/
6494 static int
6495 isLiteralBit (unsigned long lit)
6496 {
6497   unsigned long pw[32] =
6498   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6499    0x100L, 0x200L, 0x400L, 0x800L,
6500    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6501    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6502    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6503    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6504    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6505   int idx;
6506
6507   for (idx = 0; idx < 32; idx++)
6508     if (lit == pw[idx])
6509       return idx + 1;
6510   return 0;
6511 }
6512
6513 /*-----------------------------------------------------------------*/
6514 /* continueIfTrue -                                                */
6515 /*-----------------------------------------------------------------*/
6516 static void
6517 continueIfTrue (iCode * ic)
6518 {
6519   if (IC_TRUE (ic))
6520     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6521   ic->generated = 1;
6522 }
6523
6524 /*-----------------------------------------------------------------*/
6525 /* jmpIfTrue -                                                     */
6526 /*-----------------------------------------------------------------*/
6527 static void
6528 jumpIfTrue (iCode * ic)
6529 {
6530   if (!IC_TRUE (ic))
6531     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6532   ic->generated = 1;
6533 }
6534
6535 /*-----------------------------------------------------------------*/
6536 /* jmpTrueOrFalse -                                                */
6537 /*-----------------------------------------------------------------*/
6538 static void
6539 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6540 {
6541   // ugly but optimized by peephole
6542   if (IC_TRUE (ic))
6543     {
6544       symbol *nlbl = newiTempLabel (NULL);
6545       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6546       emitLabel (tlbl);
6547       freeForBranchAsmop (result);
6548       freeForBranchAsmop (right);
6549       freeForBranchAsmop (left);
6550       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6551       emitLabel (nlbl);
6552     }
6553   else
6554     {
6555       freeForBranchAsmop (result);
6556       freeForBranchAsmop (right);
6557       freeForBranchAsmop (left);
6558       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6559       emitLabel (tlbl);
6560     }
6561   ic->generated = 1;
6562 }
6563
6564 /*-----------------------------------------------------------------*/
6565 /* genAnd  - code for and                                          */
6566 /*-----------------------------------------------------------------*/
6567 static void
6568 genAnd (iCode * ic, iCode * ifx)
6569 {
6570   operand *left, *right, *result;
6571   int size, offset = 0;
6572   unsigned long lit = 0L;
6573   int bytelit = 0;
6574   char buffer[10];
6575
6576   D (emitcode (";", "genAnd"));
6577
6578   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6579   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6580   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6581
6582 #ifdef DEBUG_TYPE
6583   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6584             AOP_TYPE (result),
6585             AOP_TYPE (left), AOP_TYPE (right));
6586   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6587             AOP_SIZE (result),
6588             AOP_SIZE (left), AOP_SIZE (right));
6589 #endif
6590
6591   /* if left is a literal & right is not then exchange them */
6592   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6593       AOP_NEEDSACC (left))
6594     {
6595       operand *tmp = right;
6596       right = left;
6597       left = tmp;
6598     }
6599
6600   /* if result = right then exchange left and right */
6601   if (sameRegs (AOP (result), AOP (right)))
6602     {
6603       operand *tmp = right;
6604       right = left;
6605       left = tmp;
6606     }
6607
6608   /* if right is bit then exchange them */
6609   if (AOP_TYPE (right) == AOP_CRY &&
6610       AOP_TYPE (left) != AOP_CRY)
6611     {
6612       operand *tmp = right;
6613       right = left;
6614       left = tmp;
6615     }
6616   if (AOP_TYPE (right) == AOP_LIT)
6617     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6618
6619   size = AOP_SIZE (result);
6620
6621   // if(bit & yy)
6622   // result = bit & yy;
6623   if (AOP_TYPE (left) == AOP_CRY)
6624     {
6625       // c = bit & literal;
6626       if (AOP_TYPE (right) == AOP_LIT)
6627         {
6628           if (lit & 1)
6629             {
6630               if (size && sameRegs (AOP (result), AOP (left)))
6631                 // no change
6632                 goto release;
6633               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6634             }
6635           else
6636             {
6637               // bit(result) = 0;
6638               if (size && (AOP_TYPE (result) == AOP_CRY))
6639                 {
6640                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6641                   goto release;
6642                 }
6643               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6644                 {
6645                   jumpIfTrue (ifx);
6646                   goto release;
6647                 }
6648               emitcode ("clr", "c");
6649             }
6650         }
6651       else
6652         {
6653           if (AOP_TYPE (right) == AOP_CRY)
6654             {
6655               // c = bit & bit;
6656               if (IS_OP_ACCUSE (left))
6657                 {
6658                   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6659                 }
6660               else
6661                 {
6662                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6663                   emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6664                 }
6665             }
6666           else
6667             {
6668               // c = bit & val;
6669               MOVA (aopGet (right, 0, FALSE, FALSE));
6670               // c = lsb
6671               emitcode ("rrc", "a");
6672               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6673             }
6674         }
6675       // bit = c
6676       // val = c
6677       if (size)
6678         outBitC (result);
6679       // if(bit & ...)
6680       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6681         genIfxJump (ifx, "c", left, right, result);
6682       goto release;
6683     }
6684
6685   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6686   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6687   if ((AOP_TYPE (right) == AOP_LIT) &&
6688       (AOP_TYPE (result) == AOP_CRY) &&
6689       (AOP_TYPE (left) != AOP_CRY))
6690     {
6691       int posbit = isLiteralBit (lit);
6692       /* left &  2^n */
6693       if (posbit)
6694         {
6695           posbit--;
6696           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6697           // bit = left & 2^n
6698           if (size)
6699             {
6700               switch (posbit & 0x07)
6701                 {
6702                   case 0: emitcode ("rrc", "a");
6703                           break;
6704                   case 7: emitcode ("rlc", "a");
6705                           break;
6706                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6707                           break;
6708                 }
6709             }
6710           // if(left &  2^n)
6711           else
6712             {
6713               if (ifx)
6714                 {
6715                   SNPRINTF (buffer, sizeof(buffer),
6716                             "acc.%d", posbit & 0x07);
6717                   genIfxJump (ifx, buffer, left, right, result);
6718                 }
6719               else
6720                 {// what is this case? just found it in ds390/gen.c
6721                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6722                 }
6723               goto release;
6724             }
6725         }
6726       else
6727         {
6728           symbol *tlbl = newiTempLabel (NULL);
6729           int sizel = AOP_SIZE (left);
6730           if (size)
6731             emitcode ("setb", "c");
6732           while (sizel--)
6733             {
6734               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6735                 {
6736                   MOVA (aopGet (left, offset, FALSE, FALSE));
6737                   // byte ==  2^n ?
6738                   if ((posbit = isLiteralBit (bytelit)) != 0)
6739                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6740                   else
6741                     {
6742                       if (bytelit != 0x0FFL)
6743                         emitcode ("anl", "a,%s",
6744                                   aopGet (right, offset, FALSE, TRUE));
6745                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6746                     }
6747                 }
6748               offset++;
6749             }
6750           // bit = left & literal
6751           if (size)
6752             {
6753               emitcode ("clr", "c");
6754               emitLabel (tlbl);
6755             }
6756           // if(left & literal)
6757           else
6758             {
6759               if (ifx)
6760                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6761               else
6762                 emitLabel (tlbl);
6763               goto release;
6764             }
6765         }
6766       outBitC (result);
6767       goto release;
6768     }
6769
6770   /* if left is same as result */
6771   if (sameRegs (AOP (result), AOP (left)))
6772     {
6773       for (; size--; offset++)
6774         {
6775           if (AOP_TYPE (right) == AOP_LIT)
6776             {
6777               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6778               if (bytelit == 0x0FF)
6779                 {
6780                   /* dummy read of volatile operand */
6781                   if (isOperandVolatile (left, FALSE))
6782                     MOVA (aopGet (left, offset, FALSE, FALSE));
6783                   else
6784                     continue;
6785                 }
6786               else if (bytelit == 0)
6787                 {
6788                   aopPut (result, zero, offset);
6789                 }
6790               else if (IS_AOP_PREG (result))
6791                 {
6792                   MOVA (aopGet (left, offset, FALSE, TRUE));
6793                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6794                   aopPut (result, "a", offset);
6795                 }
6796               else
6797                 emitcode ("anl", "%s,%s",
6798                           aopGet (left, offset, FALSE, TRUE),
6799                           aopGet (right, offset, FALSE, FALSE));
6800             }
6801           else
6802             {
6803               if (AOP_TYPE (left) == AOP_ACC)
6804                 {
6805                   if (offset)
6806                     emitcode("mov", "a,b");
6807                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6808                 }
6809               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6810                 {
6811                   MOVB (aopGet (left, offset, FALSE, FALSE));
6812                   MOVA (aopGet (right, offset, FALSE, FALSE));
6813                   emitcode ("anl", "a,b");
6814                   aopPut (result, "a", offset);
6815                 }
6816               else if (aopGetUsesAcc (left, offset))
6817                 {
6818                   MOVA (aopGet (left, offset, FALSE, FALSE));
6819                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6820                   aopPut (result, "a", offset);
6821                 }
6822               else
6823                 {
6824                   MOVA (aopGet (right, offset, FALSE, FALSE));
6825                   if (IS_AOP_PREG (result))
6826                     {
6827                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6828                       aopPut (result, "a", offset);
6829                     }
6830                   else
6831                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6832                 }
6833             }
6834         }
6835     }
6836   else
6837     {
6838       // left & result in different registers
6839       if (AOP_TYPE (result) == AOP_CRY)
6840         {
6841           // result = bit
6842           // if(size), result in bit
6843           // if(!size && ifx), conditional oper: if(left & right)
6844           symbol *tlbl = newiTempLabel (NULL);
6845           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6846           if (size)
6847             emitcode ("setb", "c");
6848           while (sizer--)
6849             {
6850               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6851                   && AOP_TYPE(left)==AOP_ACC)
6852                 {
6853                   if (offset)
6854                     emitcode("mov", "a,b");
6855                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6856                 }
6857               else if (AOP_TYPE(left)==AOP_ACC)
6858                 {
6859                   if (!offset)
6860                     {
6861                       bool pushedB = pushB ();
6862                       emitcode("mov", "b,a");
6863                       MOVA (aopGet (right, offset, FALSE, FALSE));
6864                       emitcode("anl", "a,b");
6865                       popB (pushedB);
6866                     }
6867                   else
6868                     {
6869                       MOVA (aopGet (right, offset, FALSE, FALSE));
6870                       emitcode("anl", "a,b");
6871                     }
6872                 }
6873               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6874                 {
6875                   MOVB (aopGet (left, offset, FALSE, FALSE));
6876                   MOVA (aopGet (right, offset, FALSE, FALSE));
6877                   emitcode ("anl", "a,b");
6878                 }
6879               else if (aopGetUsesAcc (left, offset))
6880                 {
6881                   MOVA (aopGet (left, offset, FALSE, FALSE));
6882                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6883                     }
6884               else
6885                 {
6886                   MOVA (aopGet (right, offset, FALSE, FALSE));
6887                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6888                 }
6889
6890               emitcode ("jnz", "%05d$", tlbl->key + 100);
6891               offset++;
6892             }
6893           if (size)
6894             {
6895               CLRC;
6896               emitLabel (tlbl);
6897               outBitC (result);
6898             }
6899           else if (ifx)
6900             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6901           else
6902             emitLabel (tlbl);
6903         }
6904       else
6905         {
6906           for (; (size--); offset++)
6907             {
6908               // normal case
6909               // result = left & right
6910               if (AOP_TYPE (right) == AOP_LIT)
6911                 {
6912                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6913                   if (bytelit == 0x0FF)
6914                     {
6915                       aopPut (result,
6916                               aopGet (left, offset, FALSE, FALSE),
6917                               offset);
6918                       continue;
6919                     }
6920                   else if (bytelit == 0)
6921                     {
6922                       /* dummy read of volatile operand */
6923                       if (isOperandVolatile (left, FALSE))
6924                         MOVA (aopGet (left, offset, FALSE, FALSE));
6925                       aopPut (result, zero, offset);
6926                       continue;
6927                     }
6928                   else if (AOP_TYPE (left) == AOP_ACC)
6929                     {
6930                       if (!offset)
6931                         {
6932                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6933                           aopPut (result, "a", offset);
6934                           continue;
6935                         }
6936                       else
6937                         {
6938                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6939                           aopPut (result, "b", offset);
6940                           continue;
6941                         }
6942                     }
6943                 }
6944               // faster than result <- left, anl result,right
6945               // and better if result is SFR
6946               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6947                   && AOP_TYPE(left)==AOP_ACC)
6948                 {
6949                   if (offset)
6950                     emitcode("mov", "a,b");
6951                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6952                 }
6953               else if (AOP_TYPE(left)==AOP_ACC)
6954                 {
6955                   if (!offset)
6956                     {
6957                       bool pushedB = pushB ();
6958                       emitcode("mov", "b,a");
6959                       MOVA (aopGet (right, offset, FALSE, FALSE));
6960                       emitcode("anl", "a,b");
6961                       popB (pushedB);
6962                     }
6963                   else
6964                     {
6965                       MOVA (aopGet (right, offset, FALSE, FALSE));
6966                       emitcode("anl", "a,b");
6967                     }
6968                 }
6969               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6970                 {
6971                   MOVB (aopGet (left, offset, FALSE, FALSE));
6972                   MOVA (aopGet (right, offset, FALSE, FALSE));
6973                   emitcode ("anl", "a,b");
6974                 }
6975               else if (aopGetUsesAcc (left, offset))
6976                 {
6977                   MOVA (aopGet (left, offset, FALSE, FALSE));
6978                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6979                 }
6980               else
6981                 {
6982                   MOVA (aopGet (right, offset, FALSE, FALSE));
6983                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6984                 }
6985               aopPut (result, "a", offset);
6986             }
6987         }
6988     }
6989
6990 release:
6991   freeAsmop (result, NULL, ic, TRUE);
6992   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6993   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6994 }
6995
6996 /*-----------------------------------------------------------------*/
6997 /* genOr  - code for or                                            */
6998 /*-----------------------------------------------------------------*/
6999 static void
7000 genOr (iCode * ic, iCode * ifx)
7001 {
7002   operand *left, *right, *result;
7003   int size, offset = 0;
7004   unsigned long lit = 0L;
7005   int bytelit = 0;
7006
7007   D (emitcode (";", "genOr"));
7008
7009   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7010   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7011   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7012
7013 #ifdef DEBUG_TYPE
7014   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7015             AOP_TYPE (result),
7016             AOP_TYPE (left), AOP_TYPE (right));
7017   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7018             AOP_SIZE (result),
7019             AOP_SIZE (left), AOP_SIZE (right));
7020 #endif
7021
7022   /* if left is a literal & right is not then exchange them */
7023   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7024       AOP_NEEDSACC (left))
7025     {
7026       operand *tmp = right;
7027       right = left;
7028       left = tmp;
7029     }
7030
7031   /* if result = right then exchange them */
7032   if (sameRegs (AOP (result), AOP (right)))
7033     {
7034       operand *tmp = right;
7035       right = left;
7036       left = tmp;
7037     }
7038
7039   /* if right is bit then exchange them */
7040   if (AOP_TYPE (right) == AOP_CRY &&
7041       AOP_TYPE (left) != AOP_CRY)
7042     {
7043       operand *tmp = right;
7044       right = left;
7045       left = tmp;
7046     }
7047   if (AOP_TYPE (right) == AOP_LIT)
7048     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7049
7050   size = AOP_SIZE (result);
7051
7052   // if(bit | yy)
7053   // xx = bit | yy;
7054   if (AOP_TYPE (left) == AOP_CRY)
7055     {
7056       if (AOP_TYPE (right) == AOP_LIT)
7057         {
7058           // c = bit | literal;
7059           if (lit)
7060             {
7061               // lit != 0 => result = 1
7062               if (AOP_TYPE (result) == AOP_CRY)
7063                 {
7064                   if (size)
7065                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7066                   else if (ifx)
7067                     continueIfTrue (ifx);
7068                   goto release;
7069                 }
7070               emitcode ("setb", "c");
7071             }
7072           else
7073             {
7074               // lit == 0 => result = left
7075               if (size && sameRegs (AOP (result), AOP (left)))
7076                 goto release;
7077               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7078             }
7079         }
7080       else
7081         {
7082           if (AOP_TYPE (right) == AOP_CRY)
7083             {
7084               // c = bit | bit;
7085               if (IS_OP_ACCUSE (left))
7086                 {
7087                   emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7088                 }
7089               else
7090                 {
7091                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7092                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7093                 }
7094             }
7095           else
7096             {
7097               // c = bit | val;
7098               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7099                 {
7100                   symbol *tlbl = newiTempLabel (NULL);
7101                   emitcode ("jb", "%s,%05d$",
7102                             AOP (left)->aopu.aop_dir, tlbl->key + 100);
7103                   toBoolean (right);
7104                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7105                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7106                   goto release;
7107                 }
7108               else
7109                 {
7110                   toCarry (right);
7111                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7112                 }
7113             }
7114         }
7115       // bit = c
7116       // val = c
7117       if (size)
7118         outBitC (result);
7119       // if(bit | ...)
7120       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7121         genIfxJump (ifx, "c", left, right, result);
7122       goto release;
7123     }
7124
7125   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7126   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7127   if ((AOP_TYPE (right) == AOP_LIT) &&
7128       (AOP_TYPE (result) == AOP_CRY) &&
7129       (AOP_TYPE (left) != AOP_CRY))
7130     {
7131       if (lit)
7132         {
7133           // result = 1
7134           if (size)
7135             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7136           else
7137             continueIfTrue (ifx);
7138           goto release;
7139         }
7140       else
7141         {
7142           // lit = 0, result = boolean(left)
7143           if (size)
7144             emitcode ("setb", "c");
7145           toBoolean (right);
7146           if (size)
7147             {
7148               symbol *tlbl = newiTempLabel (NULL);
7149               emitcode ("jnz", "%05d$", tlbl->key + 100);
7150               CLRC;
7151               emitLabel (tlbl);
7152             }
7153           else
7154             {
7155               genIfxJump (ifx, "a", left, right, result);
7156               goto release;
7157             }
7158         }
7159       outBitC (result);
7160       goto release;
7161     }
7162
7163   /* if left is same as result */
7164   if (sameRegs (AOP (result), AOP (left)))
7165     {
7166       for (; size--; offset++)
7167         {
7168           if (AOP_TYPE (right) == AOP_LIT)
7169             {
7170               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7171               if (bytelit == 0)
7172                 {
7173                   /* dummy read of volatile operand */
7174                   if (isOperandVolatile (left, FALSE))
7175                     MOVA (aopGet (left, offset, FALSE, FALSE));
7176                   else
7177                     continue;
7178                 }
7179               else if (bytelit == 0x0FF)
7180                 {
7181                   aopPut (result, "#0xFF", offset);
7182                 }
7183               else if (IS_AOP_PREG (left))
7184                 {
7185                   MOVA (aopGet (left, offset, FALSE, TRUE));
7186                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7187                   aopPut (result, "a", offset);
7188                 }
7189               else
7190                 {
7191                   emitcode ("orl", "%s,%s",
7192                             aopGet (left, offset, FALSE, TRUE),
7193                             aopGet (right, offset, FALSE, FALSE));
7194                 }
7195             }
7196           else
7197             {
7198               if (AOP_TYPE (left) == AOP_ACC)
7199                 {
7200                   if (offset)
7201                     emitcode("mov", "a,b");
7202                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7203                 }
7204               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7205                 {
7206                   MOVB (aopGet (left, offset, FALSE, FALSE));
7207                   MOVA (aopGet (right, offset, FALSE, FALSE));
7208                   emitcode ("orl", "a,b");
7209                   aopPut (result, "a", offset);
7210                 }
7211               else if (aopGetUsesAcc (left, offset))
7212                 {
7213                   MOVA (aopGet (left, offset, FALSE, FALSE));
7214                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7215                   aopPut (result, "a", offset);
7216                 }
7217               else
7218                 {
7219                   MOVA (aopGet (right, offset, FALSE, FALSE));
7220                   if (IS_AOP_PREG (left))
7221                     {
7222                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7223                       aopPut (result, "a", offset);
7224                     }
7225                   else
7226                     {
7227                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7228                     }
7229                 }
7230             }
7231         }
7232     }
7233   else
7234     {
7235       // left & result in different registers
7236       if (AOP_TYPE (result) == AOP_CRY)
7237         {
7238           // result = bit
7239           // if(size), result in bit
7240           // if(!size && ifx), conditional oper: if(left | right)
7241           symbol *tlbl = newiTempLabel (NULL);
7242           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7243           if (size)
7244             emitcode ("setb", "c");
7245           while (sizer--)
7246             {
7247               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7248                   && AOP_TYPE(left)==AOP_ACC)
7249                 {
7250                   if (offset)
7251                     emitcode("mov", "a,b");
7252                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7253                 }
7254               else if (AOP_TYPE(left)==AOP_ACC)
7255                 {
7256                   if (!offset)
7257                     {
7258                       bool pushedB = pushB ();
7259                       emitcode("mov", "b,a");
7260                       MOVA (aopGet (right, offset, FALSE, FALSE));
7261                       emitcode("orl", "a,b");
7262                       popB (pushedB);
7263                     }
7264                   else
7265                     {
7266                       MOVA (aopGet (right, offset, FALSE, FALSE));
7267                       emitcode("orl", "a,b");
7268                     }
7269                 }
7270               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7271                 {
7272                   MOVB (aopGet (left, offset, FALSE, FALSE));
7273                   MOVA (aopGet (right, offset, FALSE, FALSE));
7274                   emitcode ("orl", "a,b");
7275                 }
7276               else if (aopGetUsesAcc (left, offset))
7277                 {
7278                   MOVA (aopGet (left, offset, FALSE, FALSE));
7279                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7280                 }
7281               else
7282                 {
7283                   MOVA (aopGet (right, offset, FALSE, FALSE));
7284                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7285               }
7286
7287               emitcode ("jnz", "%05d$", tlbl->key + 100);
7288               offset++;
7289             }
7290           if (size)
7291             {
7292               CLRC;
7293               emitLabel (tlbl);
7294               outBitC (result);
7295             }
7296           else if (ifx)
7297             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7298           else
7299             emitLabel (tlbl);
7300         }
7301       else
7302         {
7303           for (; (size--); offset++)
7304             {
7305               // normal case
7306               // result = left | right
7307               if (AOP_TYPE (right) == AOP_LIT)
7308                 {
7309                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7310                   if (bytelit == 0)
7311                     {
7312                       aopPut (result,
7313                               aopGet (left, offset, FALSE, FALSE),
7314                               offset);
7315                       continue;
7316                     }
7317                   else if (bytelit == 0x0FF)
7318                     {
7319                       /* dummy read of volatile operand */
7320                       if (isOperandVolatile (left, FALSE))
7321                         MOVA (aopGet (left, offset, FALSE, FALSE));
7322                       aopPut (result, "#0xFF", offset);
7323                       continue;
7324                     }
7325                 }
7326               // faster than result <- left, orl result,right
7327               // and better if result is SFR
7328               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7329                   && AOP_TYPE(left)==AOP_ACC)
7330                 {
7331                   if (offset)
7332                     emitcode("mov", "a,b");
7333                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7334                 }
7335               else if (AOP_TYPE(left)==AOP_ACC)
7336                 {
7337                   if (!offset)
7338                     {
7339                       bool pushedB = pushB ();
7340                       emitcode("mov", "b,a");
7341                       MOVA (aopGet (right, offset, FALSE, FALSE));
7342                       emitcode("orl", "a,b");
7343                       popB (pushedB);
7344                     }
7345                   else
7346                     {
7347                       MOVA (aopGet (right, offset, FALSE, FALSE));
7348                       emitcode("orl", "a,b");
7349                     }
7350                 }
7351               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7352                 {
7353                   MOVB (aopGet (left, offset, FALSE, FALSE));
7354                   MOVA (aopGet (right, offset, FALSE, FALSE));
7355                   emitcode ("orl", "a,b");
7356                 }
7357               else if (aopGetUsesAcc (left, offset))
7358                 {
7359                   MOVA (aopGet (left, offset, FALSE, FALSE));
7360                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7361                 }
7362               else
7363                 {
7364                   MOVA (aopGet (right, offset, FALSE, FALSE));
7365                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7366                 }
7367               aopPut (result, "a", offset);
7368             }
7369         }
7370     }
7371
7372 release:
7373   freeAsmop (result, NULL, ic, TRUE);
7374   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7375   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7376 }
7377
7378 /*-----------------------------------------------------------------*/
7379 /* genXor - code for xclusive or                                   */
7380 /*-----------------------------------------------------------------*/
7381 static void
7382 genXor (iCode * ic, iCode * ifx)
7383 {
7384   operand *left, *right, *result;
7385   int size, offset = 0;
7386   unsigned long lit = 0L;
7387   int bytelit = 0;
7388
7389   D (emitcode (";", "genXor"));
7390
7391   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7392   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7393   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7394
7395 #ifdef DEBUG_TYPE
7396   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7397             AOP_TYPE (result),
7398             AOP_TYPE (left), AOP_TYPE (right));
7399   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7400             AOP_SIZE (result),
7401             AOP_SIZE (left), AOP_SIZE (right));
7402 #endif
7403
7404   /* if left is a literal & right is not ||
7405      if left needs acc & right does not */
7406   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7407       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7408     {
7409       operand *tmp = right;
7410       right = left;
7411       left = tmp;
7412     }
7413
7414   /* if result = right then exchange them */
7415   if (sameRegs (AOP (result), AOP (right)))
7416     {
7417       operand *tmp = right;
7418       right = left;
7419       left = tmp;
7420     }
7421
7422   /* if right is bit then exchange them */
7423   if (AOP_TYPE (right) == AOP_CRY &&
7424       AOP_TYPE (left) != AOP_CRY)
7425     {
7426       operand *tmp = right;
7427       right = left;
7428       left = tmp;
7429     }
7430
7431   if (AOP_TYPE (right) == AOP_LIT)
7432     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7433
7434   size = AOP_SIZE (result);
7435
7436   // if(bit ^ yy)
7437   // xx = bit ^ yy;
7438   if (AOP_TYPE (left) == AOP_CRY)
7439     {
7440       if (AOP_TYPE (right) == AOP_LIT)
7441         {
7442           // c = bit & literal;
7443           if (lit >> 1)
7444             {
7445               // lit>>1  != 0 => result = 1
7446               if (AOP_TYPE (result) == AOP_CRY)
7447                 {
7448                   if (size)
7449                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7450                   else if (ifx)
7451                     continueIfTrue (ifx);
7452                   goto release;
7453                 }
7454               emitcode ("setb", "c");
7455             }
7456           else
7457             {
7458               // lit == (0 or 1)
7459               if (lit == 0)
7460                 {
7461                   // lit == 0, result = left
7462                   if (size && sameRegs (AOP (result), AOP (left)))
7463                     goto release;
7464                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7465                 }
7466               else
7467                 {
7468                   // lit == 1, result = not(left)
7469                   if (size && sameRegs (AOP (result), AOP (left)))
7470                     {
7471                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7472                       goto release;
7473                     }
7474                   else
7475                     {
7476                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7477                       emitcode ("cpl", "c");
7478                     }
7479                 }
7480             }
7481         }
7482       else
7483         {
7484           // right != literal
7485           symbol *tlbl = newiTempLabel (NULL);
7486           if (AOP_TYPE (right) == AOP_CRY)
7487             {
7488               // c = bit ^ bit;
7489               if (IS_OP_ACCUSE (left))
7490                 {// left already is in the carry
7491                   operand *tmp = right;
7492                   right = left;
7493                   left = tmp;
7494                 }
7495               else
7496                 {
7497                   toCarry (right);
7498                 }
7499             }
7500           else
7501             {
7502               // c = bit ^ val
7503               toCarry (right);
7504             }
7505           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7506           emitcode ("cpl", "c");
7507           emitLabel (tlbl);
7508         }
7509       // bit = c
7510       // val = c
7511       if (size)
7512         outBitC (result);
7513       // if(bit ^ ...)
7514       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7515         genIfxJump (ifx, "c", left, right, result);
7516       goto release;
7517     }
7518
7519   /* if left is same as result */
7520   if (sameRegs (AOP (result), AOP (left)))
7521     {
7522       for (; size--; offset++)
7523         {
7524           if (AOP_TYPE (right) == AOP_LIT)
7525             {
7526               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7527               if (bytelit == 0)
7528                 {
7529                   /* dummy read of volatile operand */
7530                   if (isOperandVolatile (left, FALSE))
7531                     MOVA (aopGet (left, offset, FALSE, FALSE));
7532                   else
7533                     continue;
7534                 }
7535               else if (IS_AOP_PREG (left))
7536                 {
7537                   MOVA (aopGet (left, offset, FALSE, TRUE));
7538                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7539                   aopPut (result, "a", offset);
7540                 }
7541               else
7542                 {
7543                   emitcode ("xrl", "%s,%s",
7544                             aopGet (left, offset, FALSE, TRUE),
7545                             aopGet (right, offset, FALSE, FALSE));
7546                 }
7547             }
7548           else
7549             {
7550               if (AOP_TYPE (left) == AOP_ACC)
7551                 {
7552                   if (offset)
7553                     emitcode("mov", "a,b");
7554                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7555                 }
7556               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7557                 {
7558                   MOVB (aopGet (left, offset, FALSE, FALSE));
7559                   MOVA (aopGet (right, offset, FALSE, FALSE));
7560                   emitcode ("xrl", "a,b");
7561                   aopPut (result, "a", offset);
7562                 }
7563               else if (aopGetUsesAcc (left, offset))
7564                 {
7565                   MOVA (aopGet (left, offset, FALSE, FALSE));
7566                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7567                   aopPut (result, "a", offset);
7568                 }
7569               else
7570                 {
7571                   MOVA (aopGet (right, offset, FALSE, FALSE));
7572                   if (IS_AOP_PREG (left))
7573                     {
7574                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7575                       aopPut (result, "a", offset);
7576                     }
7577                   else
7578                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7579                 }
7580             }
7581         }
7582     }
7583   else
7584     {
7585       // left & result in different registers
7586       if (AOP_TYPE (result) == AOP_CRY)
7587         {
7588           // result = bit
7589           // if(size), result in bit
7590           // if(!size && ifx), conditional oper: if(left ^ right)
7591           symbol *tlbl = newiTempLabel (NULL);
7592           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7593
7594           if (size)
7595             emitcode ("setb", "c");
7596           while (sizer--)
7597             {
7598               if ((AOP_TYPE (right) == AOP_LIT) &&
7599                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7600                 {
7601                   MOVA (aopGet (left, offset, FALSE, FALSE));
7602                 }
7603               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7604                   && AOP_TYPE(left)==AOP_ACC)
7605                 {
7606                   if (offset)
7607                     emitcode("mov", "a,b");
7608                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7609                 }
7610               else if (AOP_TYPE(left)==AOP_ACC)
7611                 {
7612                   if (!offset)
7613                     {
7614                       bool pushedB = pushB ();
7615                       emitcode("mov", "b,a");
7616                       MOVA (aopGet (right, offset, FALSE, FALSE));
7617                       emitcode("xrl", "a,b");
7618                       popB (pushedB);
7619                     }
7620                   else
7621                     {
7622                       MOVA (aopGet (right, offset, FALSE, FALSE));
7623                       emitcode("xrl", "a,b");
7624                     }
7625                 }
7626               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7627                 {
7628                   MOVB (aopGet (left, offset, FALSE, FALSE));
7629                   MOVA (aopGet (right, offset, FALSE, FALSE));
7630                   emitcode ("xrl", "a,b");
7631                 }
7632               else if (aopGetUsesAcc (left, offset))
7633                 {
7634                   MOVA (aopGet (left, offset, FALSE, FALSE));
7635                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7636                 }
7637               else
7638                 {
7639                   MOVA (aopGet (right, offset, FALSE, FALSE));
7640                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7641                 }
7642
7643               emitcode ("jnz", "%05d$", tlbl->key + 100);
7644               offset++;
7645             }
7646           if (size)
7647             {
7648               CLRC;
7649               emitLabel (tlbl);
7650               outBitC (result);
7651             }
7652           else if (ifx)
7653             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7654         }
7655       else
7656         {
7657           for (; (size--); offset++)
7658             {
7659               // normal case
7660               // result = left ^ right
7661               if (AOP_TYPE (right) == AOP_LIT)
7662                 {
7663                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7664                   if (bytelit == 0)
7665                     {
7666                       aopPut (result,
7667                               aopGet (left, offset, FALSE, FALSE),
7668                               offset);
7669                       continue;
7670                     }
7671                 }
7672               // faster than result <- left, xrl result,right
7673               // and better if result is SFR
7674               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7675                   && AOP_TYPE(left)==AOP_ACC)
7676                 {
7677                   if (offset)
7678                     emitcode("mov", "a,b");
7679                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7680                 }
7681               else if (AOP_TYPE(left)==AOP_ACC)
7682                 {
7683                   if (!offset)
7684                     {
7685                       bool pushedB = pushB ();
7686                       emitcode("mov", "b,a");
7687                       MOVA (aopGet (right, offset, FALSE, FALSE));
7688                       emitcode("xrl", "a,b");
7689                       popB (pushedB);
7690                     }
7691                   else
7692                     {
7693                       MOVA (aopGet (right, offset, FALSE, FALSE));
7694                       emitcode("xrl", "a,b");
7695                     }
7696                 }
7697               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7698                 {
7699                   MOVB (aopGet (left, offset, FALSE, FALSE));
7700                   MOVA (aopGet (right, offset, FALSE, FALSE));
7701                   emitcode ("xrl", "a,b");
7702                 }
7703               else if (aopGetUsesAcc (left, offset))
7704                 {
7705                   MOVA (aopGet (left, offset, FALSE, FALSE));
7706                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7707                 }
7708               else
7709                 {
7710                   MOVA (aopGet (right, offset, FALSE, FALSE));
7711                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7712                 }
7713               aopPut (result, "a", offset);
7714             }
7715         }
7716     }
7717
7718 release:
7719   freeAsmop (result, NULL, ic, TRUE);
7720   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7721   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7722 }
7723
7724 /*-----------------------------------------------------------------*/
7725 /* genInline - write the inline code out                           */
7726 /*-----------------------------------------------------------------*/
7727 static void
7728 genInline (iCode * ic)
7729 {
7730   char *buffer, *bp, *bp1;
7731   bool inComment = FALSE;
7732
7733   D (emitcode (";", "genInline"));
7734
7735   _G.inLine += (!options.asmpeep);
7736
7737   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7738
7739   /* emit each line as a code */
7740   while (*bp)
7741     {
7742       switch (*bp)
7743         {
7744         case ';':
7745           inComment = TRUE;
7746           ++bp;
7747           break;
7748
7749         case '\n':
7750           inComment = FALSE;
7751           *bp++ = '\0';
7752           emitcode (bp1, "");
7753           bp1 = bp;
7754           break;
7755
7756         default:
7757           /* Add \n for labels, not dirs such as c:\mydir */
7758           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7759             {
7760               ++bp;
7761               *bp = '\0';
7762               ++bp;
7763               emitcode (bp1, "");
7764               bp1 = bp;
7765             }
7766           else
7767             ++bp;
7768           break;
7769         }
7770     }
7771   if (bp1 != bp)
7772     emitcode (bp1, "");
7773
7774   Safe_free (buffer);
7775
7776   _G.inLine -= (!options.asmpeep);
7777 }
7778
7779 /*-----------------------------------------------------------------*/
7780 /* genRRC - rotate right with carry                                */
7781 /*-----------------------------------------------------------------*/
7782 static void
7783 genRRC (iCode * ic)
7784 {
7785   operand *left, *result;
7786   int size, offset;
7787   char *l;
7788
7789   D (emitcode (";", "genRRC"));
7790
7791   /* rotate right with carry */
7792   left = IC_LEFT (ic);
7793   result = IC_RESULT (ic);
7794   aopOp (left, ic, FALSE);
7795   aopOp (result, ic, FALSE);
7796
7797   /* move it to the result */
7798   size = AOP_SIZE (result);
7799   offset = size - 1;
7800   if (size == 1) { /* special case for 1 byte */
7801       l = aopGet (left, offset, FALSE, FALSE);
7802       MOVA (l);
7803       emitcode ("rr", "a");
7804       goto release;
7805   }
7806   /* no need to clear carry, bit7 will be written later */
7807   while (size--)
7808     {
7809       l = aopGet (left, offset, FALSE, FALSE);
7810       MOVA (l);
7811       emitcode ("rrc", "a");
7812       if (AOP_SIZE (result) > 1)
7813         aopPut (result, "a", offset--);
7814     }
7815   /* now we need to put the carry into the
7816      highest order byte of the result */
7817   if (AOP_SIZE (result) > 1)
7818     {
7819       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7820       MOVA (l);
7821     }
7822   emitcode ("mov", "acc.7,c");
7823  release:
7824   aopPut (result, "a", AOP_SIZE (result) - 1);
7825   freeAsmop (result, NULL, ic, TRUE);
7826   freeAsmop (left, NULL, ic, TRUE);
7827 }
7828
7829 /*-----------------------------------------------------------------*/
7830 /* genRLC - generate code for rotate left with carry               */
7831 /*-----------------------------------------------------------------*/
7832 static void
7833 genRLC (iCode * ic)
7834 {
7835   operand *left, *result;
7836   int size, offset;
7837   char *l;
7838
7839   D (emitcode (";", "genRLC"));
7840
7841   /* rotate right with carry */
7842   left = IC_LEFT (ic);
7843   result = IC_RESULT (ic);
7844   aopOp (left, ic, FALSE);
7845   aopOp (result, ic, FALSE);
7846
7847   /* move it to the result */
7848   size = AOP_SIZE (result);
7849   offset = 0;
7850   if (size--)
7851     {
7852       l = aopGet (left, offset, FALSE, FALSE);
7853       MOVA (l);
7854       if (size == 0) { /* special case for 1 byte */
7855               emitcode("rl","a");
7856               goto release;
7857       }
7858       emitcode("rlc","a"); /* bit0 will be written later */
7859       if (AOP_SIZE (result) > 1)
7860         {
7861           aopPut (result, "a", offset++);
7862         }
7863
7864       while (size--)
7865         {
7866           l = aopGet (left, offset, FALSE, FALSE);
7867           MOVA (l);
7868           emitcode ("rlc", "a");
7869           if (AOP_SIZE (result) > 1)
7870             aopPut (result, "a", offset++);
7871         }
7872     }
7873   /* now we need to put the carry into the
7874      highest order byte of the result */
7875   if (AOP_SIZE (result) > 1)
7876     {
7877       l = aopGet (result, 0, FALSE, FALSE);
7878       MOVA (l);
7879     }
7880   emitcode ("mov", "acc.0,c");
7881  release:
7882   aopPut (result, "a", 0);
7883   freeAsmop (result, NULL, ic, TRUE);
7884   freeAsmop (left, NULL, ic, TRUE);
7885 }
7886
7887 /*-----------------------------------------------------------------*/
7888 /* genGetHbit - generates code get highest order bit               */
7889 /*-----------------------------------------------------------------*/
7890 static void
7891 genGetHbit (iCode * ic)
7892 {
7893   operand *left, *result;
7894
7895   D (emitcode (";", "genGetHbit"));
7896
7897   left = IC_LEFT (ic);
7898   result = IC_RESULT (ic);
7899   aopOp (left, ic, FALSE);
7900   aopOp (result, ic, FALSE);
7901
7902   /* get the highest order byte into a */
7903   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7904   if (AOP_TYPE (result) == AOP_CRY)
7905     {
7906       emitcode ("rlc", "a");
7907       outBitC (result);
7908     }
7909   else
7910     {
7911       emitcode ("rl", "a");
7912       emitcode ("anl", "a,#0x01");
7913       outAcc (result);
7914     }
7915
7916   freeAsmop (result, NULL, ic, TRUE);
7917   freeAsmop (left, NULL, ic, TRUE);
7918 }
7919
7920 /*-----------------------------------------------------------------*/
7921 /* genGetAbit - generates code get a single bit                    */
7922 /*-----------------------------------------------------------------*/
7923 static void
7924 genGetAbit (iCode * ic)
7925 {
7926   operand *left, *right, *result;
7927   int shCount;
7928
7929   D (emitcode (";", "genGetAbit"));
7930
7931   left = IC_LEFT (ic);
7932   right = IC_RIGHT (ic);
7933   result = IC_RESULT (ic);
7934   aopOp (left, ic, FALSE);
7935   aopOp (right, ic, FALSE);
7936   aopOp (result, ic, FALSE);
7937
7938   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7939
7940   /* get the needed byte into a */
7941   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7942   shCount %= 8;
7943   if (AOP_TYPE (result) == AOP_CRY)
7944     {
7945       if ((shCount) == 7)
7946           emitcode ("rlc", "a");
7947       else if ((shCount) == 0)
7948           emitcode ("rrc", "a");
7949       else
7950           emitcode ("mov", "c,acc[%d]", shCount);
7951       outBitC (result);
7952     }
7953   else
7954     {
7955       switch (shCount)
7956         {
7957         case 2:
7958           emitcode ("rr", "a");
7959           //fallthrough
7960         case 1:
7961           emitcode ("rr", "a");
7962           //fallthrough
7963         case 0:
7964           emitcode ("anl", "a,#0x01");
7965           break;
7966         case 3:
7967         case 5:
7968           emitcode ("mov", "c,acc[%d]", shCount);
7969           emitcode ("clr", "a");
7970           emitcode ("rlc", "a");
7971           break;
7972         case 4:
7973           emitcode ("swap", "a");
7974           emitcode ("anl", "a,#0x01");
7975           break;
7976         case 6:
7977           emitcode ("rl", "a");
7978           //fallthrough
7979         case 7:
7980           emitcode ("rl", "a");
7981           emitcode ("anl", "a,#0x01");
7982           break;
7983         }
7984       outAcc (result);
7985     }
7986
7987   freeAsmop (result, NULL, ic, TRUE);
7988   freeAsmop (right, NULL, ic, TRUE);
7989   freeAsmop (left, NULL, ic, TRUE);
7990 }
7991
7992 /*-----------------------------------------------------------------*/
7993 /* genGetByte - generates code get a single byte                   */
7994 /*-----------------------------------------------------------------*/
7995 static void
7996 genGetByte (iCode * ic)
7997 {
7998   operand *left, *right, *result;
7999   int offset;
8000
8001   D (emitcode (";", "genGetByte"));
8002
8003   left = IC_LEFT (ic);
8004   right = IC_RIGHT (ic);
8005   result = IC_RESULT (ic);
8006   aopOp (left, ic, FALSE);
8007   aopOp (right, ic, FALSE);
8008   aopOp (result, ic, FALSE);
8009
8010   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8011   aopPut (result,
8012           aopGet (left, offset, FALSE, FALSE),
8013           0);
8014
8015   freeAsmop (result, NULL, ic, TRUE);
8016   freeAsmop (right, NULL, ic, TRUE);
8017   freeAsmop (left, NULL, ic, TRUE);
8018 }
8019
8020 /*-----------------------------------------------------------------*/
8021 /* genGetWord - generates code get two bytes                       */
8022 /*-----------------------------------------------------------------*/
8023 static void
8024 genGetWord (iCode * ic)
8025 {
8026   operand *left, *right, *result;
8027   int offset;
8028
8029   D (emitcode (";", "genGetWord"));
8030
8031   left = IC_LEFT (ic);
8032   right = IC_RIGHT (ic);
8033   result = IC_RESULT (ic);
8034   aopOp (left, ic, FALSE);
8035   aopOp (right, ic, FALSE);
8036   aopOp (result, ic, FALSE);
8037
8038   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8039   aopPut (result,
8040           aopGet (left, offset, FALSE, FALSE),
8041           0);
8042   aopPut (result,
8043           aopGet (left, offset+1, FALSE, FALSE),
8044           1);
8045
8046   freeAsmop (result, NULL, ic, TRUE);
8047   freeAsmop (right, NULL, ic, TRUE);
8048   freeAsmop (left, NULL, ic, TRUE);
8049 }
8050
8051 /*-----------------------------------------------------------------*/
8052 /* genSwap - generates code to swap nibbles or bytes               */
8053 /*-----------------------------------------------------------------*/
8054 static void
8055 genSwap (iCode * ic)
8056 {
8057   operand *left, *result;
8058
8059   D(emitcode (";", "genSwap"));
8060
8061   left = IC_LEFT (ic);
8062   result = IC_RESULT (ic);
8063   aopOp (left, ic, FALSE);
8064   aopOp (result, ic, FALSE);
8065
8066   switch (AOP_SIZE (left))
8067     {
8068     case 1: /* swap nibbles in byte */
8069       MOVA (aopGet (left, 0, FALSE, FALSE));
8070       emitcode ("swap", "a");
8071       aopPut (result, "a", 0);
8072       break;
8073     case 2: /* swap bytes in word */
8074       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8075         {
8076           MOVA (aopGet (left, 0, FALSE, FALSE));
8077           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8078           aopPut (result, "a", 1);
8079         }
8080       else if (operandsEqu (left, result))
8081         {
8082           char * reg = "a";
8083           bool pushedB = FALSE, leftInB = FALSE;
8084
8085           MOVA (aopGet (left, 0, FALSE, FALSE));
8086           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8087             {
8088               pushedB = pushB ();
8089               emitcode ("mov", "b,a");
8090               reg = "b";
8091               leftInB = TRUE;
8092             }
8093           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8094           aopPut (result, reg, 1);
8095
8096           if (leftInB)
8097             popB (pushedB);
8098         }
8099       else
8100         {
8101           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8102           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8103         }
8104       break;
8105     default:
8106       wassertl(FALSE, "unsupported SWAP operand size");
8107     }
8108
8109   freeAsmop (result, NULL, ic, TRUE);
8110   freeAsmop (left, NULL, ic, TRUE);
8111 }
8112
8113 /*-----------------------------------------------------------------*/
8114 /* AccRol - rotate left accumulator by known count                 */
8115 /*-----------------------------------------------------------------*/
8116 static void
8117 AccRol (int shCount)
8118 {
8119   shCount &= 0x0007;            // shCount : 0..7
8120
8121   switch (shCount)
8122     {
8123     case 0:
8124       break;
8125     case 1:
8126       emitcode ("rl", "a");
8127       break;
8128     case 2:
8129       emitcode ("rl", "a");
8130       emitcode ("rl", "a");
8131       break;
8132     case 3:
8133       emitcode ("swap", "a");
8134       emitcode ("rr", "a");
8135       break;
8136     case 4:
8137       emitcode ("swap", "a");
8138       break;
8139     case 5:
8140       emitcode ("swap", "a");
8141       emitcode ("rl", "a");
8142       break;
8143     case 6:
8144       emitcode ("rr", "a");
8145       emitcode ("rr", "a");
8146       break;
8147     case 7:
8148       emitcode ("rr", "a");
8149       break;
8150     }
8151 }
8152
8153 /*-----------------------------------------------------------------*/
8154 /* AccLsh - left shift accumulator by known count                  */
8155 /*-----------------------------------------------------------------*/
8156 static void
8157 AccLsh (int shCount)
8158 {
8159   if (shCount != 0)
8160     {
8161       if (shCount == 1)
8162         emitcode ("add", "a,acc");
8163       else if (shCount == 2)
8164         {
8165           emitcode ("add", "a,acc");
8166           emitcode ("add", "a,acc");
8167         }
8168       else
8169         {
8170           /* rotate left accumulator */
8171           AccRol (shCount);
8172           /* and kill the lower order bits */
8173           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8174         }
8175     }
8176 }
8177
8178 /*-----------------------------------------------------------------*/
8179 /* AccRsh - right shift accumulator by known count                 */
8180 /*-----------------------------------------------------------------*/
8181 static void
8182 AccRsh (int shCount)
8183 {
8184   if (shCount != 0)
8185     {
8186       if (shCount == 1)
8187         {
8188           CLRC;
8189           emitcode ("rrc", "a");
8190         }
8191       else
8192         {
8193           /* rotate right accumulator */
8194           AccRol (8 - shCount);
8195           /* and kill the higher order bits */
8196           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8197         }
8198     }
8199 }
8200
8201 /*-----------------------------------------------------------------*/
8202 /* AccSRsh - signed right shift accumulator by known count                 */
8203 /*-----------------------------------------------------------------*/
8204 static void
8205 AccSRsh (int shCount)
8206 {
8207   symbol *tlbl;
8208   if (shCount != 0)
8209     {
8210       if (shCount == 1)
8211         {
8212           emitcode ("mov", "c,acc.7");
8213           emitcode ("rrc", "a");
8214         }
8215       else if (shCount == 2)
8216         {
8217           emitcode ("mov", "c,acc.7");
8218           emitcode ("rrc", "a");
8219           emitcode ("mov", "c,acc.7");
8220           emitcode ("rrc", "a");
8221         }
8222       else
8223         {
8224           tlbl = newiTempLabel (NULL);
8225           /* rotate right accumulator */
8226           AccRol (8 - shCount);
8227           /* and kill the higher order bits */
8228           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8229           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8230           emitcode ("orl", "a,#0x%02x",
8231                     (unsigned char) ~SRMask[shCount]);
8232           emitLabel (tlbl);
8233         }
8234     }
8235 }
8236
8237 /*-----------------------------------------------------------------*/
8238 /* shiftR1Left2Result - shift right one byte from left to result   */
8239 /*-----------------------------------------------------------------*/
8240 static void
8241 shiftR1Left2Result (operand * left, int offl,
8242                     operand * result, int offr,
8243                     int shCount, int sign)
8244 {
8245   MOVA (aopGet (left, offl, FALSE, FALSE));
8246   /* shift right accumulator */
8247   if (sign)
8248     AccSRsh (shCount);
8249   else
8250     AccRsh (shCount);
8251   aopPut (result, "a", offr);
8252 }
8253
8254 /*-----------------------------------------------------------------*/
8255 /* shiftL1Left2Result - shift left one byte from left to result    */
8256 /*-----------------------------------------------------------------*/
8257 static void
8258 shiftL1Left2Result (operand * left, int offl,
8259                     operand * result, int offr, int shCount)
8260 {
8261   char *l;
8262   l = aopGet (left, offl, FALSE, FALSE);
8263   MOVA (l);
8264   /* shift left accumulator */
8265   AccLsh (shCount);
8266   aopPut (result, "a", offr);
8267 }
8268
8269 /*-----------------------------------------------------------------*/
8270 /* movLeft2Result - move byte from left to result                  */
8271 /*-----------------------------------------------------------------*/
8272 static void
8273 movLeft2Result (operand * left, int offl,
8274                 operand * result, int offr, int sign)
8275 {
8276   char *l;
8277   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8278     {
8279       l = aopGet (left, offl, FALSE, FALSE);
8280
8281       if (*l == '@' && (IS_AOP_PREG (result)))
8282         {
8283           emitcode ("mov", "a,%s", l);
8284           aopPut (result, "a", offr);
8285         }
8286       else
8287         {
8288           if (!sign)
8289             {
8290               aopPut (result, l, offr);
8291             }
8292           else
8293             {
8294               /* MSB sign in acc.7 ! */
8295               if (getDataSize (left) == offl + 1)
8296                 {
8297                   MOVA (l);
8298                   aopPut (result, "a", offr);
8299                 }
8300             }
8301         }
8302     }
8303 }
8304
8305 /*-----------------------------------------------------------------*/
8306 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8307 /*-----------------------------------------------------------------*/
8308 static void
8309 AccAXRrl1 (char *x)
8310 {
8311   emitcode ("rrc", "a");
8312   emitcode ("xch", "a,%s", x);
8313   emitcode ("rrc", "a");
8314   emitcode ("xch", "a,%s", x);
8315 }
8316
8317 /*-----------------------------------------------------------------*/
8318 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8319 /*-----------------------------------------------------------------*/
8320 static void
8321 AccAXLrl1 (char *x)
8322 {
8323   emitcode ("xch", "a,%s", x);
8324   emitcode ("rlc", "a");
8325   emitcode ("xch", "a,%s", x);
8326   emitcode ("rlc", "a");
8327 }
8328
8329 /*-----------------------------------------------------------------*/
8330 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8331 /*-----------------------------------------------------------------*/
8332 static void
8333 AccAXLsh1 (char *x)
8334 {
8335   emitcode ("xch", "a,%s", x);
8336   emitcode ("add", "a,acc");
8337   emitcode ("xch", "a,%s", x);
8338   emitcode ("rlc", "a");
8339 }
8340
8341 /*-----------------------------------------------------------------*/
8342 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8343 /*-----------------------------------------------------------------*/
8344 static void
8345 AccAXLsh (char *x, int shCount)
8346 {
8347   switch (shCount)
8348     {
8349     case 0:
8350       break;
8351     case 1:
8352       AccAXLsh1 (x);
8353       break;
8354     case 2:
8355       AccAXLsh1 (x);
8356       AccAXLsh1 (x);
8357       break;
8358     case 3:
8359     case 4:
8360     case 5:                     // AAAAABBB:CCCCCDDD
8361
8362       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8363
8364       emitcode ("anl", "a,#0x%02x",
8365                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8366
8367       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8368
8369       AccRol (shCount);         // DDDCCCCC:BBB00000
8370
8371       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8372
8373       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8374
8375       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8376
8377       emitcode ("anl", "a,#0x%02x",
8378                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8379
8380       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8381
8382       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8383
8384       break;
8385     case 6:                     // AAAAAABB:CCCCCCDD
8386       emitcode ("anl", "a,#0x%02x",
8387                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8388       emitcode ("mov", "c,acc.0");      // c = B
8389       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8390 #if 0 // REMOVE ME
8391       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8392       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8393 #else
8394       emitcode("rrc","a");
8395       emitcode("xch","a,%s", x);
8396       emitcode("rrc","a");
8397       emitcode("mov","c,acc.0"); //<< get correct bit
8398       emitcode("xch","a,%s", x);
8399
8400       emitcode("rrc","a");
8401       emitcode("xch","a,%s", x);
8402       emitcode("rrc","a");
8403       emitcode("xch","a,%s", x);
8404 #endif
8405       break;
8406     case 7:                     // a:x <<= 7
8407
8408       emitcode ("anl", "a,#0x%02x",
8409                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8410
8411       emitcode ("mov", "c,acc.0");      // c = B
8412
8413       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8414
8415       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8416
8417       break;
8418     default:
8419       break;
8420     }
8421 }
8422
8423 /*-----------------------------------------------------------------*/
8424 /* AccAXRsh - right shift a:x known count (0..7)                   */
8425 /*-----------------------------------------------------------------*/
8426 static void
8427 AccAXRsh (char *x, int shCount)
8428 {
8429   switch (shCount)
8430     {
8431     case 0:
8432       break;
8433     case 1:
8434       CLRC;
8435       AccAXRrl1 (x);            // 0->a:x
8436
8437       break;
8438     case 2:
8439       CLRC;
8440       AccAXRrl1 (x);            // 0->a:x
8441
8442       CLRC;
8443       AccAXRrl1 (x);            // 0->a:x
8444
8445       break;
8446     case 3:
8447     case 4:
8448     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8449
8450       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8451
8452       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8453
8454       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8455
8456       emitcode ("anl", "a,#0x%02x",
8457                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8458
8459       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8460
8461       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8462
8463       emitcode ("anl", "a,#0x%02x",
8464                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8465
8466       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8467
8468       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8469
8470       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8471
8472       break;
8473     case 6:                     // AABBBBBB:CCDDDDDD
8474
8475       emitcode ("mov", "c,acc.7");
8476       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8477
8478       emitcode ("mov", "c,acc.7");
8479       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8480
8481       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8482
8483       emitcode ("anl", "a,#0x%02x",
8484                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8485
8486       break;
8487     case 7:                     // ABBBBBBB:CDDDDDDD
8488
8489       emitcode ("mov", "c,acc.7");      // c = A
8490
8491       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8492
8493       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8494
8495       emitcode ("anl", "a,#0x%02x",
8496                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8497
8498       break;
8499     default:
8500       break;
8501     }
8502 }
8503
8504 /*-----------------------------------------------------------------*/
8505 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8506 /*-----------------------------------------------------------------*/
8507 static void
8508 AccAXRshS (char *x, int shCount)
8509 {
8510   symbol *tlbl;
8511   switch (shCount)
8512     {
8513     case 0:
8514       break;
8515     case 1:
8516       emitcode ("mov", "c,acc.7");
8517       AccAXRrl1 (x);            // s->a:x
8518
8519       break;
8520     case 2:
8521       emitcode ("mov", "c,acc.7");
8522       AccAXRrl1 (x);            // s->a:x
8523
8524       emitcode ("mov", "c,acc.7");
8525       AccAXRrl1 (x);            // s->a:x
8526
8527       break;
8528     case 3:
8529     case 4:
8530     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8531
8532       tlbl = newiTempLabel (NULL);
8533       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8534
8535       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8536
8537       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8538
8539       emitcode ("anl", "a,#0x%02x",
8540                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8541
8542       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8543
8544       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8545
8546       emitcode ("anl", "a,#0x%02x",
8547                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8548
8549       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8550
8551       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8552
8553       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8554
8555       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8556       emitcode ("orl", "a,#0x%02x",
8557                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8558
8559       emitLabel (tlbl);
8560       break;                    // SSSSAAAA:BBBCCCCC
8561
8562     case 6:                     // AABBBBBB:CCDDDDDD
8563
8564       tlbl = newiTempLabel (NULL);
8565       emitcode ("mov", "c,acc.7");
8566       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8567
8568       emitcode ("mov", "c,acc.7");
8569       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8570
8571       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8572
8573       emitcode ("anl", "a,#0x%02x",
8574                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8575
8576       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8577       emitcode ("orl", "a,#0x%02x",
8578                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8579
8580       emitLabel (tlbl);
8581       break;
8582     case 7:                     // ABBBBBBB:CDDDDDDD
8583
8584       tlbl = newiTempLabel (NULL);
8585       emitcode ("mov", "c,acc.7");      // c = A
8586
8587       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8588
8589       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8590
8591       emitcode ("anl", "a,#0x%02x",
8592                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8593
8594       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8595       emitcode ("orl", "a,#0x%02x",
8596                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8597
8598       emitLabel (tlbl);
8599       break;
8600     default:
8601       break;
8602     }
8603 }
8604
8605 /*-----------------------------------------------------------------*/
8606 /* shiftL2Left2Result - shift left two bytes from left to result   */
8607 /*-----------------------------------------------------------------*/
8608 static void
8609 shiftL2Left2Result (operand * left, int offl,
8610                     operand * result, int offr, int shCount)
8611 {
8612   char * x;
8613   bool pushedB = FALSE;
8614   bool usedB = FALSE;
8615
8616   if (sameRegs (AOP (result), AOP (left)) &&
8617       ((offl + MSB16) == offr))
8618     {
8619       /* don't crash result[offr] */
8620       MOVA (aopGet (left, offl, FALSE, FALSE));
8621       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8622       usedB = !strncmp(x, "b", 1);
8623     }
8624   else if (aopGetUsesAcc (result, offr))
8625     {
8626       movLeft2Result (left, offl, result, offr, 0);
8627       pushedB = pushB ();
8628       usedB = TRUE;
8629       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8630       MOVA (aopGet (result, offr, FALSE, FALSE));
8631       emitcode ("xch", "a,b");
8632       x = "b";
8633     }
8634   else
8635     {
8636       movLeft2Result (left, offl, result, offr, 0);
8637       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8638       x = aopGet (result, offr, FALSE, FALSE);
8639     }
8640   /* ax << shCount (x = lsb(result)) */
8641   AccAXLsh (x, shCount);
8642   if (usedB)
8643     {
8644       emitcode ("xch", "a,b");
8645       aopPut (result, "a", offr);
8646       aopPut (result, "b", offr + MSB16);
8647       popB (pushedB);
8648     }
8649   else
8650     {
8651       aopPut (result, "a", offr + MSB16);
8652     }
8653 }
8654
8655
8656 /*-----------------------------------------------------------------*/
8657 /* shiftR2Left2Result - shift right two bytes from left to result  */
8658 /*-----------------------------------------------------------------*/
8659 static void
8660 shiftR2Left2Result (operand * left, int offl,
8661                     operand * result, int offr,
8662                     int shCount, int sign)
8663 {
8664   char * x;
8665   bool pushedB = FALSE;
8666   bool usedB = FALSE;
8667
8668   if (sameRegs (AOP (result), AOP (left)) &&
8669       ((offl + MSB16) == offr))
8670     {
8671       /* don't crash result[offr] */
8672       MOVA (aopGet (left, offl, FALSE, FALSE));
8673       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8674       usedB = !strncmp(x, "b", 1);
8675     }
8676   else if (aopGetUsesAcc (result, offr))
8677     {
8678       movLeft2Result (left, offl, result, offr, 0);
8679       pushedB = pushB ();
8680       usedB = TRUE;
8681       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8682       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8683       x = "b";
8684     }
8685   else
8686     {
8687       movLeft2Result (left, offl, result, offr, 0);
8688       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8689       x = aopGet (result, offr, FALSE, FALSE);
8690     }
8691   /* a:x >> shCount (x = lsb(result)) */
8692   if (sign)
8693     AccAXRshS (x, shCount);
8694   else
8695     AccAXRsh (x, shCount);
8696   if (usedB)
8697     {
8698       emitcode ("xch", "a,b");
8699       aopPut (result, "a", offr);
8700       emitcode ("xch", "a,b");
8701       popB (pushedB);
8702     }
8703   if (getDataSize (result) > 1)
8704     aopPut (result, "a", offr + MSB16);
8705 }
8706
8707 /*-----------------------------------------------------------------*/
8708 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8709 /*-----------------------------------------------------------------*/
8710 static void
8711 shiftLLeftOrResult (operand * left, int offl,
8712                     operand * result, int offr, int shCount)
8713 {
8714   MOVA (aopGet (left, offl, FALSE, FALSE));
8715   /* shift left accumulator */
8716   AccLsh (shCount);
8717   /* or with result */
8718   if (aopGetUsesAcc (result, offr))
8719     {
8720       emitcode ("xch", "a,b");
8721       MOVA (aopGet (result, offr, FALSE, FALSE));
8722       emitcode ("orl", "a,b");
8723     }
8724   else
8725     {
8726       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8727     }
8728   /* back to result */
8729   aopPut (result, "a", offr);
8730 }
8731
8732 /*-----------------------------------------------------------------*/
8733 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8734 /*-----------------------------------------------------------------*/
8735 static void
8736 shiftRLeftOrResult (operand * left, int offl,
8737                     operand * result, int offr, int shCount)
8738 {
8739   MOVA (aopGet (left, offl, FALSE, FALSE));
8740   /* shift right accumulator */
8741   AccRsh (shCount);
8742   /* or with result */
8743   if (aopGetUsesAcc(result, offr))
8744     {
8745       emitcode ("xch", "a,b");
8746       MOVA (aopGet (result, offr, FALSE, FALSE));
8747       emitcode ("orl", "a,b");
8748     }
8749   else
8750     {
8751       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8752     }
8753   /* back to result */
8754   aopPut (result, "a", offr);
8755 }
8756
8757 /*-----------------------------------------------------------------*/
8758 /* genlshOne - left shift a one byte quantity by known count       */
8759 /*-----------------------------------------------------------------*/
8760 static void
8761 genlshOne (operand * result, operand * left, int shCount)
8762 {
8763   D (emitcode (";", "genlshOne"));
8764
8765   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8766 }
8767
8768 /*-----------------------------------------------------------------*/
8769 /* genlshTwo - left shift two bytes by known amount != 0           */
8770 /*-----------------------------------------------------------------*/
8771 static void
8772 genlshTwo (operand * result, operand * left, int shCount)
8773 {
8774   int size;
8775
8776   D (emitcode (";", "genlshTwo"));
8777
8778   size = getDataSize (result);
8779
8780   /* if shCount >= 8 */
8781   if (shCount >= 8)
8782     {
8783       shCount -= 8;
8784
8785       if (size > 1)
8786         {
8787           if (shCount)
8788             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8789           else
8790             movLeft2Result (left, LSB, result, MSB16, 0);
8791         }
8792       aopPut (result, zero, LSB);
8793     }
8794
8795   /*  1 <= shCount <= 7 */
8796   else
8797     {
8798       if (size == 1)
8799         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8800       else
8801         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8802     }
8803 }
8804
8805 /*-----------------------------------------------------------------*/
8806 /* shiftLLong - shift left one long from left to result            */
8807 /* offl = LSB or MSB16                                             */
8808 /*-----------------------------------------------------------------*/
8809 static void
8810 shiftLLong (operand * left, operand * result, int offr)
8811 {
8812   char *l;
8813   int size = AOP_SIZE (result);
8814
8815   if (size >= LSB + offr)
8816     {
8817       l = aopGet (left, LSB, FALSE, FALSE);
8818       MOVA (l);
8819       emitcode ("add", "a,acc");
8820       if (sameRegs (AOP (left), AOP (result)) &&
8821           size >= MSB16 + offr && offr != LSB)
8822         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8823       else
8824         aopPut (result, "a", LSB + offr);
8825     }
8826
8827   if (size >= MSB16 + offr)
8828     {
8829       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8830         {
8831           l = aopGet (left, MSB16, FALSE, FALSE);
8832           MOVA (l);
8833         }
8834       emitcode ("rlc", "a");
8835       if (sameRegs (AOP (left), AOP (result)) &&
8836           size >= MSB24 + offr && offr != LSB)
8837         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8838       else
8839         aopPut (result, "a", MSB16 + offr);
8840     }
8841
8842   if (size >= MSB24 + offr)
8843     {
8844       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8845         {
8846           l = aopGet (left, MSB24, FALSE, FALSE);
8847           MOVA (l);
8848         }
8849       emitcode ("rlc", "a");
8850       if (sameRegs (AOP (left), AOP (result)) &&
8851           size >= MSB32 + offr && offr != LSB)
8852         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8853       else
8854         aopPut (result, "a", MSB24 + offr);
8855     }
8856
8857   if (size > MSB32 + offr)
8858     {
8859       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8860         {
8861           l = aopGet (left, MSB32, FALSE, FALSE);
8862           MOVA (l);
8863         }
8864       emitcode ("rlc", "a");
8865       aopPut (result, "a", MSB32 + offr);
8866     }
8867   if (offr != LSB)
8868     aopPut (result, zero, LSB);
8869 }
8870
8871 /*-----------------------------------------------------------------*/
8872 /* genlshFour - shift four byte by a known amount != 0             */
8873 /*-----------------------------------------------------------------*/
8874 static void
8875 genlshFour (operand * result, operand * left, int shCount)
8876 {
8877   int size;
8878
8879   D (emitcode (";", "genlshFour"));
8880
8881   size = AOP_SIZE (result);
8882
8883   /* if shifting more that 3 bytes */
8884   if (shCount >= 24)
8885     {
8886       shCount -= 24;
8887       if (shCount)
8888         /* lowest order of left goes to the highest
8889            order of the destination */
8890         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8891       else
8892         movLeft2Result (left, LSB, result, MSB32, 0);
8893       aopPut (result, zero, LSB);
8894       aopPut (result, zero, MSB16);
8895       aopPut (result, zero, MSB24);
8896       return;
8897     }
8898
8899   /* more than two bytes */
8900   else if (shCount >= 16)
8901     {
8902       /* lower order two bytes goes to higher order two bytes */
8903       shCount -= 16;
8904       /* if some more remaining */
8905       if (shCount)
8906         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8907       else
8908         {
8909           movLeft2Result (left, MSB16, result, MSB32, 0);
8910           movLeft2Result (left, LSB, result, MSB24, 0);
8911         }
8912       aopPut (result, zero, MSB16);
8913       aopPut (result, zero, LSB);
8914       return;
8915     }
8916
8917   /* if more than 1 byte */
8918   else if (shCount >= 8)
8919     {
8920       /* lower order three bytes goes to higher order  three bytes */
8921       shCount -= 8;
8922       if (size == 2)
8923         {
8924           if (shCount)
8925             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8926           else
8927             movLeft2Result (left, LSB, result, MSB16, 0);
8928         }
8929       else
8930         {                       /* size = 4 */
8931           if (shCount == 0)
8932             {
8933               movLeft2Result (left, MSB24, result, MSB32, 0);
8934               movLeft2Result (left, MSB16, result, MSB24, 0);
8935               movLeft2Result (left, LSB, result, MSB16, 0);
8936               aopPut (result, zero, LSB);
8937             }
8938           else if (shCount == 1)
8939             shiftLLong (left, result, MSB16);
8940           else
8941             {
8942               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8943               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8944               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8945               aopPut (result, zero, LSB);
8946             }
8947         }
8948     }
8949
8950   /* 1 <= shCount <= 7 */
8951   else if (shCount <= 2)
8952     {
8953       shiftLLong (left, result, LSB);
8954       if (shCount == 2)
8955         shiftLLong (result, result, LSB);
8956     }
8957   /* 3 <= shCount <= 7, optimize */
8958   else
8959     {
8960       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8961       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8962       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8963     }
8964 }
8965
8966 /*-----------------------------------------------------------------*/
8967 /* genLeftShiftLiteral - left shifting by known count              */
8968 /*-----------------------------------------------------------------*/
8969 static void
8970 genLeftShiftLiteral (operand * left,
8971                      operand * right,
8972                      operand * result,
8973                      iCode * ic)
8974 {
8975   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
8976   int size;
8977
8978   D (emitcode (";", "genLeftShiftLiteral"));
8979
8980   freeAsmop (right, NULL, ic, TRUE);
8981
8982   aopOp (left, ic, FALSE);
8983   aopOp (result, ic, FALSE);
8984
8985   size = getSize (operandType (result));
8986
8987 #if VIEW_SIZE
8988   emitcode ("; shift left ", "result %d, left %d", size,
8989             AOP_SIZE (left));
8990 #endif
8991
8992   /* I suppose that the left size >= result size */
8993   if (shCount == 0)
8994     {
8995       while (size--)
8996         {
8997           movLeft2Result (left, size, result, size, 0);
8998         }
8999     }
9000   else if (shCount >= (size * 8))
9001     {
9002       while (size--)
9003         {
9004           aopPut (result, zero, size);
9005         }
9006     }
9007   else
9008     {
9009       switch (size)
9010         {
9011         case 1:
9012           genlshOne (result, left, shCount);
9013           break;
9014
9015         case 2:
9016           genlshTwo (result, left, shCount);
9017           break;
9018
9019         case 4:
9020           genlshFour (result, left, shCount);
9021           break;
9022         default:
9023           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9024                   "*** ack! mystery literal shift!\n");
9025           break;
9026         }
9027     }
9028   freeAsmop (result, NULL, ic, TRUE);
9029   freeAsmop (left, NULL, ic, TRUE);
9030 }
9031
9032 /*-----------------------------------------------------------------*/
9033 /* genLeftShift - generates code for left shifting                 */
9034 /*-----------------------------------------------------------------*/
9035 static void
9036 genLeftShift (iCode * ic)
9037 {
9038   operand *left, *right, *result;
9039   int size, offset;
9040   char *l;
9041   symbol *tlbl, *tlbl1;
9042   bool pushedB;
9043
9044   D (emitcode (";", "genLeftShift"));
9045
9046   right = IC_RIGHT (ic);
9047   left = IC_LEFT (ic);
9048   result = IC_RESULT (ic);
9049
9050   aopOp (right, ic, FALSE);
9051
9052   /* if the shift count is known then do it
9053      as efficiently as possible */
9054   if (AOP_TYPE (right) == AOP_LIT)
9055     {
9056       genLeftShiftLiteral (left, right, result, ic);
9057       return;
9058     }
9059
9060   /* shift count is unknown then we have to form
9061      a loop get the loop count in B : Note: we take
9062      only the lower order byte since shifting
9063      more that 32 bits make no sense anyway, ( the
9064      largest size of an object can be only 32 bits ) */
9065
9066   pushedB = pushB ();
9067   MOVB (aopGet (right, 0, FALSE, FALSE));
9068   emitcode ("inc", "b");
9069   freeAsmop (right, NULL, ic, TRUE);
9070   aopOp (left, ic, FALSE);
9071   aopOp (result, ic, FALSE);
9072
9073   /* now move the left to the result if they are not the same */
9074   if (!sameRegs (AOP (left), AOP (result)) &&
9075       AOP_SIZE (result) > 1)
9076     {
9077
9078       size = AOP_SIZE (result);
9079       offset = 0;
9080       while (size--)
9081         {
9082           l = aopGet (left, offset, FALSE, TRUE);
9083           if (*l == '@' && (IS_AOP_PREG (result)))
9084             {
9085
9086               emitcode ("mov", "a,%s", l);
9087               aopPut (result, "a", offset);
9088             }
9089           else
9090             aopPut (result, l, offset);
9091           offset++;
9092         }
9093     }
9094
9095   tlbl = newiTempLabel (NULL);
9096   size = AOP_SIZE (result);
9097   offset = 0;
9098   tlbl1 = newiTempLabel (NULL);
9099
9100   /* if it is only one byte then */
9101   if (size == 1)
9102     {
9103       symbol *tlbl1 = newiTempLabel (NULL);
9104
9105       l = aopGet (left, 0, FALSE, FALSE);
9106       MOVA (l);
9107       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9108       emitLabel (tlbl);
9109       emitcode ("add", "a,acc");
9110       emitLabel (tlbl1);
9111       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9112       popB (pushedB);
9113       aopPut (result, "a", 0);
9114       goto release;
9115     }
9116
9117   reAdjustPreg (AOP (result));
9118
9119   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9120   emitLabel (tlbl);
9121   l = aopGet (result, offset, FALSE, FALSE);
9122   MOVA (l);
9123   emitcode ("add", "a,acc");
9124   aopPut (result, "a", offset++);
9125   while (--size)
9126     {
9127       l = aopGet (result, offset, FALSE, FALSE);
9128       MOVA (l);
9129       emitcode ("rlc", "a");
9130       aopPut (result, "a", offset++);
9131     }
9132   reAdjustPreg (AOP (result));
9133
9134   emitLabel (tlbl1);
9135   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9136   popB (pushedB);
9137 release:
9138   freeAsmop (result, NULL, ic, TRUE);
9139   freeAsmop (left, NULL, ic, TRUE);
9140 }
9141
9142 /*-----------------------------------------------------------------*/
9143 /* genrshOne - right shift a one byte quantity by known count      */
9144 /*-----------------------------------------------------------------*/
9145 static void
9146 genrshOne (operand * result, operand * left,
9147            int shCount, int sign)
9148 {
9149   D (emitcode (";", "genrshOne"));
9150
9151   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9152 }
9153
9154 /*-----------------------------------------------------------------*/
9155 /* genrshTwo - right shift two bytes by known amount != 0          */
9156 /*-----------------------------------------------------------------*/
9157 static void
9158 genrshTwo (operand * result, operand * left,
9159            int shCount, int sign)
9160 {
9161   D (emitcode (";", "genrshTwo"));
9162
9163   /* if shCount >= 8 */
9164   if (shCount >= 8)
9165     {
9166       shCount -= 8;
9167       if (shCount)
9168         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9169       else
9170         movLeft2Result (left, MSB16, result, LSB, sign);
9171       addSign (result, MSB16, sign);
9172     }
9173
9174   /*  1 <= shCount <= 7 */
9175   else
9176     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9177 }
9178
9179 /*-----------------------------------------------------------------*/
9180 /* shiftRLong - shift right one long from left to result           */
9181 /* offl = LSB or MSB16                                             */
9182 /*-----------------------------------------------------------------*/
9183 static void
9184 shiftRLong (operand * left, int offl,
9185             operand * result, int sign)
9186 {
9187   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9188
9189   if (overlapping && offl>1)
9190     {
9191       // we are in big trouble, but this shouldn't happen
9192       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9193     }
9194
9195   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9196
9197   if (offl==MSB16)
9198     {
9199       // shift is > 8
9200       if (sign)
9201         {
9202           emitcode ("rlc", "a");
9203           emitcode ("subb", "a,acc");
9204           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9205             {
9206               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9207             }
9208           else
9209             {
9210               aopPut (result, "a", MSB32);
9211               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9212             }
9213         }
9214       else
9215         {
9216           if (aopPutUsesAcc (result, zero, MSB32))
9217             {
9218               emitcode("xch", "a,b");
9219               aopPut (result, zero, MSB32);
9220               emitcode("xch", "a,b");
9221             }
9222           else
9223             {
9224               aopPut (result, zero, MSB32);
9225             }
9226         }
9227     }
9228
9229   if (!sign)
9230     {
9231       emitcode ("clr", "c");
9232     }
9233   else
9234     {
9235       emitcode ("mov", "c,acc.7");
9236     }
9237
9238   emitcode ("rrc", "a");
9239
9240   if (overlapping && offl==MSB16 &&
9241       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9242     {
9243       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9244     }
9245   else
9246     {
9247       aopPut (result, "a", MSB32 - offl);
9248       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9249     }
9250
9251   emitcode ("rrc", "a");
9252   if (overlapping && offl==MSB16 &&
9253       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9254     {
9255       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9256     }
9257   else
9258     {
9259       aopPut (result, "a", MSB24 - offl);
9260       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9261     }
9262
9263   emitcode ("rrc", "a");
9264   if (offl != LSB)
9265     {
9266       aopPut (result, "a", MSB16 - offl);
9267     }
9268   else
9269     {
9270       if (overlapping &&
9271           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9272         {
9273           xch_a_aopGet (left, LSB, FALSE, FALSE);
9274         }
9275       else
9276         {
9277           aopPut (result, "a", MSB16 - offl);
9278           MOVA (aopGet (left, LSB, FALSE, FALSE));
9279         }
9280       emitcode ("rrc", "a");
9281       aopPut (result, "a", LSB);
9282     }
9283 }
9284
9285 /*-----------------------------------------------------------------*/
9286 /* genrshFour - shift four byte by a known amount != 0             */
9287 /*-----------------------------------------------------------------*/
9288 static void
9289 genrshFour (operand * result, operand * left,
9290             int shCount, int sign)
9291 {
9292   D (emitcode (";", "genrshFour"));
9293
9294   /* if shifting more that 3 bytes */
9295   if (shCount >= 24)
9296     {
9297       shCount -= 24;
9298       if (shCount)
9299         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9300       else
9301         movLeft2Result (left, MSB32, result, LSB, sign);
9302       addSign (result, MSB16, sign);
9303     }
9304   else if (shCount >= 16)
9305     {
9306       shCount -= 16;
9307       if (shCount)
9308         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9309       else
9310         {
9311           movLeft2Result (left, MSB24, result, LSB, 0);
9312           movLeft2Result (left, MSB32, result, MSB16, sign);
9313         }
9314       addSign (result, MSB24, sign);
9315     }
9316   else if (shCount >= 8)
9317     {
9318       shCount -= 8;
9319       if (shCount == 1)
9320         {
9321           shiftRLong (left, MSB16, result, sign);
9322         }
9323       else if (shCount == 0)
9324         {
9325           movLeft2Result (left, MSB16, result, LSB, 0);
9326           movLeft2Result (left, MSB24, result, MSB16, 0);
9327           movLeft2Result (left, MSB32, result, MSB24, sign);
9328           addSign (result, MSB32, sign);
9329         }
9330       else
9331         {
9332           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9333           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9334           /* the last shift is signed */
9335           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9336           addSign (result, MSB32, sign);
9337         }
9338     }
9339   else
9340     {
9341       /* 1 <= shCount <= 7 */
9342       if (shCount <= 2)
9343         {
9344           shiftRLong (left, LSB, result, sign);
9345           if (shCount == 2)
9346             shiftRLong (result, LSB, result, sign);
9347         }
9348       else
9349         {
9350           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9351           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9352           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9353         }
9354     }
9355 }
9356
9357 /*-----------------------------------------------------------------*/
9358 /* genRightShiftLiteral - right shifting by known count            */
9359 /*-----------------------------------------------------------------*/
9360 static void
9361 genRightShiftLiteral (operand * left,
9362                       operand * right,
9363                       operand * result,
9364                       iCode * ic,
9365                       int sign)
9366 {
9367   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9368   int size;
9369
9370   D (emitcode (";", "genRightShiftLiteral"));
9371
9372   freeAsmop (right, NULL, ic, TRUE);
9373
9374   aopOp (left, ic, FALSE);
9375   aopOp (result, ic, FALSE);
9376
9377 #if VIEW_SIZE
9378   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9379             AOP_SIZE (left));
9380 #endif
9381
9382   size = getDataSize (left);
9383   /* test the LEFT size !!! */
9384
9385   /* I suppose that the left size >= result size */
9386   if (shCount == 0)
9387     {
9388       size = getDataSize (result);
9389       while (size--)
9390         movLeft2Result (left, size, result, size, 0);
9391     }
9392
9393   else if (shCount >= (size * 8))
9394     {
9395       if (sign)
9396         {
9397           /* get sign in acc.7 */
9398           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9399         }
9400       addSign (result, LSB, sign);
9401     }
9402   else
9403     {
9404       switch (size)
9405         {
9406         case 1:
9407           genrshOne (result, left, shCount, sign);
9408           break;
9409
9410         case 2:
9411           genrshTwo (result, left, shCount, sign);
9412           break;
9413
9414         case 4:
9415           genrshFour (result, left, shCount, sign);
9416           break;
9417         default:
9418           break;
9419         }
9420     }
9421   freeAsmop (result, NULL, ic, TRUE);
9422   freeAsmop (left, NULL, ic, TRUE);
9423 }
9424
9425 /*-----------------------------------------------------------------*/
9426 /* genSignedRightShift - right shift of signed number              */
9427 /*-----------------------------------------------------------------*/
9428 static void
9429 genSignedRightShift (iCode * ic)
9430 {
9431   operand *right, *left, *result;
9432   int size, offset;
9433   char *l;
9434   symbol *tlbl, *tlbl1;
9435   bool pushedB;
9436
9437   D (emitcode (";", "genSignedRightShift"));
9438
9439   /* we do it the hard way put the shift count in b
9440      and loop thru preserving the sign */
9441
9442   right = IC_RIGHT (ic);
9443   left = IC_LEFT (ic);
9444   result = IC_RESULT (ic);
9445
9446   aopOp (right, ic, FALSE);
9447
9448
9449   if (AOP_TYPE (right) == AOP_LIT)
9450     {
9451       genRightShiftLiteral (left, right, result, ic, 1);
9452       return;
9453     }
9454   /* shift count is unknown then we have to form
9455      a loop get the loop count in B : Note: we take
9456      only the lower order byte since shifting
9457      more that 32 bits make no sense anyway, ( the
9458      largest size of an object can be only 32 bits ) */
9459
9460   pushedB = pushB ();
9461   MOVB (aopGet (right, 0, FALSE, FALSE));
9462   emitcode ("inc", "b");
9463   freeAsmop (right, NULL, ic, TRUE);
9464   aopOp (left, ic, FALSE);
9465   aopOp (result, ic, FALSE);
9466
9467   /* now move the left to the result if they are not the
9468      same */
9469   if (!sameRegs (AOP (left), AOP (result)) &&
9470       AOP_SIZE (result) > 1)
9471     {
9472
9473       size = AOP_SIZE (result);
9474       offset = 0;
9475       while (size--)
9476         {
9477           l = aopGet (left, offset, FALSE, TRUE);
9478           if (*l == '@' && IS_AOP_PREG (result))
9479             {
9480
9481               emitcode ("mov", "a,%s", l);
9482               aopPut (result, "a", offset);
9483             }
9484           else
9485             aopPut (result, l, offset);
9486           offset++;
9487         }
9488     }
9489
9490   /* mov the highest order bit to OVR */
9491   tlbl = newiTempLabel (NULL);
9492   tlbl1 = newiTempLabel (NULL);
9493
9494   size = AOP_SIZE (result);
9495   offset = size - 1;
9496   MOVA (aopGet (left, offset, FALSE, FALSE));
9497   emitcode ("rlc", "a");
9498   emitcode ("mov", "ov,c");
9499   /* if it is only one byte then */
9500   if (size == 1)
9501     {
9502       l = aopGet (left, 0, FALSE, FALSE);
9503       MOVA (l);
9504       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9505       emitLabel (tlbl);
9506       emitcode ("mov", "c,ov");
9507       emitcode ("rrc", "a");
9508       emitLabel (tlbl1);
9509       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9510       popB (pushedB);
9511       aopPut (result, "a", 0);
9512       goto release;
9513     }
9514
9515   reAdjustPreg (AOP (result));
9516   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9517   emitLabel (tlbl);
9518   emitcode ("mov", "c,ov");
9519   while (size--)
9520     {
9521       l = aopGet (result, offset, FALSE, FALSE);
9522       MOVA (l);
9523       emitcode ("rrc", "a");
9524       aopPut (result, "a", offset--);
9525     }
9526   reAdjustPreg (AOP (result));
9527   emitLabel (tlbl1);
9528   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9529   popB (pushedB);
9530
9531 release:
9532   freeAsmop (result, NULL, ic, TRUE);
9533   freeAsmop (left, NULL, ic, TRUE);
9534 }
9535
9536 /*-----------------------------------------------------------------*/
9537 /* genRightShift - generate code for right shifting                */
9538 /*-----------------------------------------------------------------*/
9539 static void
9540 genRightShift (iCode * ic)
9541 {
9542   operand *right, *left, *result;
9543   sym_link *letype;
9544   int size, offset;
9545   char *l;
9546   symbol *tlbl, *tlbl1;
9547   bool pushedB;
9548
9549   D (emitcode (";", "genRightShift"));
9550
9551   /* if signed then we do it the hard way preserve the
9552      sign bit moving it inwards */
9553   letype = getSpec (operandType (IC_LEFT (ic)));
9554
9555   if (!SPEC_USIGN (letype))
9556     {
9557       genSignedRightShift (ic);
9558       return;
9559     }
9560
9561   /* signed & unsigned types are treated the same : i.e. the
9562      signed is NOT propagated inwards : quoting from the
9563      ANSI - standard : "for E1 >> E2, is equivalent to division
9564      by 2**E2 if unsigned or if it has a non-negative value,
9565      otherwise the result is implementation defined ", MY definition
9566      is that the sign does not get propagated */
9567
9568   right = IC_RIGHT (ic);
9569   left = IC_LEFT (ic);
9570   result = IC_RESULT (ic);
9571
9572   aopOp (right, ic, FALSE);
9573
9574   /* if the shift count is known then do it
9575      as efficiently as possible */
9576   if (AOP_TYPE (right) == AOP_LIT)
9577     {
9578       genRightShiftLiteral (left, right, result, ic, 0);
9579       return;
9580     }
9581
9582   /* shift count is unknown then we have to form
9583      a loop get the loop count in B : Note: we take
9584      only the lower order byte since shifting
9585      more that 32 bits make no sense anyway, ( the
9586      largest size of an object can be only 32 bits ) */
9587
9588   pushedB = pushB ();
9589   MOVB (aopGet (right, 0, FALSE, FALSE));
9590   emitcode ("inc", "b");
9591   freeAsmop (right, NULL, ic, TRUE);
9592   aopOp (left, ic, FALSE);
9593   aopOp (result, ic, FALSE);
9594
9595   /* now move the left to the result if they are not the
9596      same */
9597   if (!sameRegs (AOP (left), AOP (result)) &&
9598       AOP_SIZE (result) > 1)
9599     {
9600       size = AOP_SIZE (result);
9601       offset = 0;
9602       while (size--)
9603         {
9604           l = aopGet (left, offset, FALSE, TRUE);
9605           if (*l == '@' && IS_AOP_PREG (result))
9606             {
9607
9608               emitcode ("mov", "a,%s", l);
9609               aopPut (result, "a", offset);
9610             }
9611           else
9612             aopPut (result, l, offset);
9613           offset++;
9614         }
9615     }
9616
9617   tlbl = newiTempLabel (NULL);
9618   tlbl1 = newiTempLabel (NULL);
9619   size = AOP_SIZE (result);
9620   offset = size - 1;
9621
9622   /* if it is only one byte then */
9623   if (size == 1)
9624     {
9625       l = aopGet (left, 0, FALSE, FALSE);
9626       MOVA (l);
9627       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9628       emitLabel (tlbl);
9629       CLRC;
9630       emitcode ("rrc", "a");
9631       emitLabel (tlbl1);
9632       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9633       popB (pushedB);
9634       aopPut (result, "a", 0);
9635       goto release;
9636     }
9637
9638   reAdjustPreg (AOP (result));
9639   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9640   emitLabel (tlbl);
9641   CLRC;
9642   while (size--)
9643     {
9644       l = aopGet (result, offset, FALSE, FALSE);
9645       MOVA (l);
9646       emitcode ("rrc", "a");
9647       aopPut (result, "a", offset--);
9648     }
9649   reAdjustPreg (AOP (result));
9650
9651   emitLabel (tlbl1);
9652   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9653   popB (pushedB);
9654
9655 release:
9656   freeAsmop (result, NULL, ic, TRUE);
9657   freeAsmop (left, NULL, ic, TRUE);
9658 }
9659
9660 /*-----------------------------------------------------------------*/
9661 /* emitPtrByteGet - emits code to get a byte into A through a      */
9662 /*                  pointer register (R0, R1, or DPTR). The        */
9663 /*                  original value of A can be preserved in B.     */
9664 /*-----------------------------------------------------------------*/
9665 static void
9666 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9667 {
9668   switch (p_type)
9669     {
9670     case IPOINTER:
9671     case POINTER:
9672       if (preserveAinB)
9673         emitcode ("mov", "b,a");
9674       emitcode ("mov", "a,@%s", rname);
9675       break;
9676
9677     case PPOINTER:
9678       if (preserveAinB)
9679         emitcode ("mov", "b,a");
9680       emitcode ("movx", "a,@%s", rname);
9681       break;
9682
9683     case FPOINTER:
9684       if (preserveAinB)
9685         emitcode ("mov", "b,a");
9686       emitcode ("movx", "a,@dptr");
9687       break;
9688
9689     case CPOINTER:
9690       if (preserveAinB)
9691         emitcode ("mov", "b,a");
9692       emitcode ("clr", "a");
9693       emitcode ("movc", "a,@a+dptr");
9694       break;
9695
9696     case GPOINTER:
9697       if (preserveAinB)
9698         {
9699           emitcode ("push", "b");
9700           emitcode ("push", "acc");
9701         }
9702       emitcode ("lcall", "__gptrget");
9703       if (preserveAinB)
9704         emitcode ("pop", "b");
9705       break;
9706     }
9707 }
9708
9709 /*-----------------------------------------------------------------*/
9710 /* emitPtrByteSet - emits code to set a byte from src through a    */
9711 /*                  pointer register (R0, R1, or DPTR).            */
9712 /*-----------------------------------------------------------------*/
9713 static void
9714 emitPtrByteSet (char *rname, int p_type, char *src)
9715 {
9716   switch (p_type)
9717     {
9718     case IPOINTER:
9719     case POINTER:
9720       if (*src=='@')
9721         {
9722           MOVA (src);
9723           emitcode ("mov", "@%s,a", rname);
9724         }
9725       else
9726         emitcode ("mov", "@%s,%s", rname, src);
9727       break;
9728
9729     case PPOINTER:
9730       MOVA (src);
9731       emitcode ("movx", "@%s,a", rname);
9732       break;
9733
9734     case FPOINTER:
9735       MOVA (src);
9736       emitcode ("movx", "@dptr,a");
9737       break;
9738
9739     case GPOINTER:
9740       MOVA (src);
9741       emitcode ("lcall", "__gptrput");
9742       break;
9743     }
9744 }
9745
9746 /*-----------------------------------------------------------------*/
9747 /* genUnpackBits - generates code for unpacking bits               */
9748 /*-----------------------------------------------------------------*/
9749 static char*
9750 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9751 {
9752   int offset = 0;       /* result byte offset */
9753   int rsize;            /* result size */
9754   int rlen = 0;         /* remaining bitfield length */
9755   sym_link *etype;      /* bitfield type information */
9756   int blen;             /* bitfield length */
9757   int bstr;             /* bitfield starting bit within byte */
9758   static char* const accBits[] = {"acc.0", "acc.1", "acc.2", "acc.3",
9759                                   "acc.4", "acc.5", "acc.6", "acc.7"};
9760
9761   D(emitcode (";", "genUnpackBits"));
9762
9763   etype = getSpec (operandType (result));
9764   rsize = getSize (operandType (result));
9765   blen = SPEC_BLEN (etype);
9766   bstr = SPEC_BSTR (etype);
9767
9768   if (ifx && blen <= 8)
9769     {
9770       emitPtrByteGet (rname, ptype, FALSE);
9771       if (blen == 1)
9772         {
9773           return accBits[bstr];;
9774         }
9775       else
9776         {
9777           if (blen < 8)
9778             emitcode ("anl", "a,#0x%02x",
9779                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9780           return "a";
9781         }
9782     }
9783   wassert (!ifx);
9784
9785   /* If the bitfield length is less than a byte */
9786   if (blen < 8)
9787     {
9788       emitPtrByteGet (rname, ptype, FALSE);
9789       AccRol (8 - bstr);
9790       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9791       if (!SPEC_USIGN (etype))
9792         {
9793           /* signed bitfield */
9794           symbol *tlbl = newiTempLabel (NULL);
9795
9796           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9797           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9798           emitLabel (tlbl);
9799         }
9800       aopPut (result, "a", offset++);
9801       goto finish;
9802     }
9803
9804   /* Bit field did not fit in a byte. Copy all
9805      but the partial byte at the end.  */
9806   for (rlen=blen;rlen>=8;rlen-=8)
9807     {
9808       emitPtrByteGet (rname, ptype, FALSE);
9809       aopPut (result, "a", offset++);
9810       if (rlen>8)
9811         emitcode ("inc", "%s", rname);
9812     }
9813
9814   /* Handle the partial byte at the end */
9815   if (rlen)
9816     {
9817       emitPtrByteGet (rname, ptype, FALSE);
9818       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9819       if (!SPEC_USIGN (etype))
9820         {
9821           /* signed bitfield */
9822           symbol *tlbl = newiTempLabel (NULL);
9823
9824           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9825           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9826           emitLabel (tlbl);
9827         }
9828       aopPut (result, "a", offset++);
9829     }
9830
9831 finish:
9832   if (offset < rsize)
9833     {
9834       char *source;
9835
9836       if (SPEC_USIGN (etype))
9837         source = zero;
9838       else
9839         {
9840           /* signed bitfield: sign extension with 0x00 or 0xff */
9841           emitcode ("rlc", "a");
9842           emitcode ("subb", "a,acc");
9843
9844           source = "a";
9845         }
9846       rsize -= offset;
9847       while (rsize--)
9848         aopPut (result, source, offset++);
9849     }
9850   return NULL;
9851 }
9852
9853
9854 /*-----------------------------------------------------------------*/
9855 /* genDataPointerGet - generates code when ptr offset is known     */
9856 /*-----------------------------------------------------------------*/
9857 static void
9858 genDataPointerGet (operand * left,
9859                    operand * result,
9860                    iCode * ic)
9861 {
9862   char *l;
9863   char buffer[256];
9864   int size, offset = 0;
9865
9866   D (emitcode (";", "genDataPointerGet"));
9867
9868   aopOp (result, ic, TRUE);
9869
9870   /* get the string representation of the name */
9871   l = aopGet (left, 0, FALSE, TRUE);
9872   l++; // remove #
9873   size = AOP_SIZE (result);
9874   while (size--)
9875     {
9876       if (offset)
9877         {
9878           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9879         }
9880       else
9881         {
9882           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9883         }
9884       aopPut (result, buffer, offset++);
9885     }
9886
9887   freeAsmop (result, NULL, ic, TRUE);
9888   freeAsmop (left, NULL, ic, TRUE);
9889 }
9890
9891 /*-----------------------------------------------------------------*/
9892 /* genNearPointerGet - emitcode for near pointer fetch             */
9893 /*-----------------------------------------------------------------*/
9894 static void
9895 genNearPointerGet (operand * left,
9896                    operand * result,
9897                    iCode * ic,
9898                    iCode * pi,
9899                    iCode * ifx)
9900 {
9901   asmop *aop = NULL;
9902   regs *preg = NULL;
9903   char *rname;
9904   char *ifxCond = "a";
9905   sym_link *rtype, *retype;
9906   sym_link *ltype = operandType (left);
9907
9908   D (emitcode (";", "genNearPointerGet"));
9909
9910   rtype = operandType (result);
9911   retype = getSpec (rtype);
9912
9913   aopOp (left, ic, FALSE);
9914
9915   /* if left is rematerialisable and
9916      result is not bitfield variable type and
9917      the left is pointer to data space i.e
9918      lower 128 bytes of space */
9919   if (AOP_TYPE (left) == AOP_IMMD &&
9920       !IS_BITFIELD (retype) &&
9921       DCL_TYPE (ltype) == POINTER)
9922     {
9923       genDataPointerGet (left, result, ic);
9924       return;
9925     }
9926
9927   //aopOp (result, ic, FALSE);
9928   aopOp (result, ic, result?TRUE:FALSE);
9929
9930  /* if the value is already in a pointer register
9931      then don't need anything more */
9932   if (!AOP_INPREG (AOP (left)))
9933     {
9934       if (IS_AOP_PREG (left))
9935         {
9936           // Aha, it is a pointer, just in disguise.
9937           rname = aopGet (left, 0, FALSE, FALSE);
9938           if (*rname != '@')
9939             {
9940               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9941                       __FILE__, __LINE__);
9942             }
9943           else
9944             {
9945               // Expected case.
9946               emitcode ("mov", "a%s,%s", rname + 1, rname);
9947               rname++;  // skip the '@'.
9948             }
9949         }
9950       else
9951         {
9952           /* otherwise get a free pointer register */
9953           aop = newAsmop (0);
9954           preg = getFreePtr (ic, &aop, FALSE);
9955           emitcode ("mov", "%s,%s",
9956                     preg->name,
9957                     aopGet (left, 0, FALSE, TRUE));
9958           rname = preg->name;
9959         }
9960     }
9961   else
9962     rname = aopGet (left, 0, FALSE, FALSE);
9963
9964   /* if bitfield then unpack the bits */
9965   if (IS_BITFIELD (retype))
9966     ifxCond = genUnpackBits (result, rname, POINTER, ifx);
9967   else
9968     {
9969       /* we have can just get the values */
9970       int size = AOP_SIZE (result);
9971       int offset = 0;
9972
9973       while (size--)
9974         {
9975           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9976             {
9977
9978               emitcode ("mov", "a,@%s", rname);
9979               if (!ifx)
9980                 aopPut (result, "a", offset);
9981             }
9982           else
9983             {
9984               char buffer[80];
9985
9986               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9987               aopPut (result, buffer, offset);
9988             }
9989           offset++;
9990           if (size || pi)
9991             emitcode ("inc", "%s", rname);
9992         }
9993     }
9994
9995   /* now some housekeeping stuff */
9996   if (aop)       /* we had to allocate for this iCode */
9997     {
9998       if (pi) { /* post increment present */
9999         aopPut (left, rname, 0);
10000       }
10001       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10002     }
10003   else
10004     {
10005       /* we did not allocate which means left
10006          already in a pointer register, then
10007          if size > 0 && this could be used again
10008          we have to point it back to where it
10009          belongs */
10010       if ((AOP_SIZE (result) > 1 &&
10011            !OP_SYMBOL (left)->remat &&
10012            (OP_SYMBOL (left)->liveTo > ic->seq ||
10013             ic->depth)) &&
10014           !pi)
10015         {
10016           int size = AOP_SIZE (result) - 1;
10017           while (size--)
10018             emitcode ("dec", "%s", rname);
10019         }
10020     }
10021
10022   if (ifx && !ifx->generated)
10023     {
10024       genIfxJump (ifx, ifxCond, left, NULL, result);
10025     }
10026
10027   /* done */
10028   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10029   freeAsmop (left, NULL, ic, TRUE);
10030   if (pi) pi->generated = 1;
10031 }
10032
10033 /*-----------------------------------------------------------------*/
10034 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10035 /*-----------------------------------------------------------------*/
10036 static void
10037 genPagedPointerGet (operand * left,
10038                     operand * result,
10039                     iCode * ic,
10040                     iCode *pi,
10041                     iCode *ifx)
10042 {
10043   asmop *aop = NULL;
10044   regs *preg = NULL;
10045   char *rname;
10046   char *ifxCond = "a";
10047   sym_link *rtype, *retype;
10048
10049   D (emitcode (";", "genPagedPointerGet"));
10050
10051   rtype = operandType (result);
10052   retype = getSpec (rtype);
10053
10054   aopOp (left, ic, FALSE);
10055
10056   aopOp (result, ic, FALSE);
10057
10058   /* if the value is already in a pointer register
10059      then don't need anything more */
10060   if (!AOP_INPREG (AOP (left)))
10061     {
10062       /* otherwise get a free pointer register */
10063       aop = newAsmop (0);
10064       preg = getFreePtr (ic, &aop, FALSE);
10065       emitcode ("mov", "%s,%s",
10066                 preg->name,
10067                 aopGet (left, 0, FALSE, TRUE));
10068       rname = preg->name;
10069     }
10070   else
10071     rname = aopGet (left, 0, FALSE, FALSE);
10072
10073   /* if bitfield then unpack the bits */
10074   if (IS_BITFIELD (retype))
10075     ifxCond = genUnpackBits (result, rname, PPOINTER, ifx);
10076   else
10077     {
10078       /* we have can just get the values */
10079       int size = AOP_SIZE (result);
10080       int offset = 0;
10081
10082       while (size--)
10083         {
10084
10085           emitcode ("movx", "a,@%s", rname);
10086           if (!ifx)
10087             aopPut (result, "a", offset);
10088
10089           offset++;
10090
10091           if (size || pi)
10092             emitcode ("inc", "%s", rname);
10093         }
10094     }
10095
10096   /* now some housekeeping stuff */
10097   if (aop) /* we had to allocate for this iCode */
10098     {
10099       if (pi)
10100         aopPut (left, rname, 0);
10101       freeAsmop (NULL, aop, ic, TRUE);
10102     }
10103   else
10104     {
10105       /* we did not allocate which means left
10106          already in a pointer register, then
10107          if size > 0 && this could be used again
10108          we have to point it back to where it
10109          belongs */
10110       if ((AOP_SIZE (result) > 1 &&
10111            !OP_SYMBOL (left)->remat &&
10112            (OP_SYMBOL (left)->liveTo > ic->seq ||
10113             ic->depth)) &&
10114           !pi)
10115         {
10116           int size = AOP_SIZE (result) - 1;
10117           while (size--)
10118             emitcode ("dec", "%s", rname);
10119         }
10120     }
10121
10122   if (ifx && !ifx->generated)
10123     {
10124       genIfxJump (ifx, ifxCond, left, NULL, result);
10125     }
10126
10127   /* done */
10128   freeAsmop (result, NULL, ic, TRUE);
10129   freeAsmop (left, NULL, ic, TRUE);
10130   if (pi) pi->generated = 1;
10131 }
10132
10133 /*--------------------------------------------------------------------*/
10134 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10135 /*--------------------------------------------------------------------*/
10136 static void
10137 loadDptrFromOperand (operand *op, bool loadBToo)
10138 {
10139   if (AOP_TYPE (op) != AOP_STR)
10140     {
10141       /* if this is rematerializable */
10142       if (AOP_TYPE (op) == AOP_IMMD)
10143         {
10144           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10145           if (loadBToo)
10146             {
10147               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10148                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10149               else
10150                 {
10151                   wassertl(FALSE, "need pointerCode");
10152                   emitcode (";", "mov b,???");
10153                   /* genPointerGet and genPointerSet originally did different
10154                   ** things for this case. Both seem wrong.
10155                   ** from genPointerGet:
10156                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10157                   ** from genPointerSet:
10158                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10159                   */
10160                 }
10161             }
10162         }
10163       else if (AOP_TYPE (op) == AOP_DPTR)
10164         {
10165           if (loadBToo)
10166             {
10167               MOVA (aopGet (op, 0, FALSE, FALSE));
10168               emitcode ("push", "acc");
10169               MOVA (aopGet (op, 1, FALSE, FALSE));
10170               emitcode ("push", "acc");
10171               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10172               emitcode ("pop", "dph");
10173               emitcode ("pop", "dpl");
10174             }
10175           else
10176             {
10177               MOVA (aopGet (op, 0, FALSE, FALSE));
10178               emitcode ("push", "acc");
10179               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10180               emitcode ("pop", "dpl");
10181             }
10182         }
10183       else
10184         {                       /* we need to get it byte by byte */
10185           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10186           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10187           if (loadBToo)
10188             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10189         }
10190     }
10191 }
10192
10193 /*-----------------------------------------------------------------*/
10194 /* genFarPointerGet - get value from far space                     */
10195 /*-----------------------------------------------------------------*/
10196 static void
10197 genFarPointerGet (operand * left,
10198                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10199 {
10200   int size, offset;
10201   char *ifxCond = "a";
10202   sym_link *retype = getSpec (operandType (result));
10203
10204   D (emitcode (";", "genFarPointerGet"));
10205
10206   aopOp (left, ic, FALSE);
10207   loadDptrFromOperand (left, FALSE);
10208
10209   /* so dptr now contains the address */
10210   aopOp (result, ic, FALSE);
10211
10212   /* if bit then unpack */
10213   if (IS_BITFIELD (retype))
10214     ifxCond = genUnpackBits (result, "dptr", FPOINTER, ifx);
10215   else
10216     {
10217       size = AOP_SIZE (result);
10218       offset = 0;
10219
10220       while (size--)
10221         {
10222           emitcode ("movx", "a,@dptr");
10223           if (!ifx)
10224             aopPut (result, "a", offset++);
10225           if (size || pi)
10226             emitcode ("inc", "dptr");
10227         }
10228     }
10229
10230   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10231     {
10232       aopPut (left, "dpl", 0);
10233       aopPut (left, "dph", 1);
10234       pi->generated = 1;
10235     }
10236
10237   if (ifx && !ifx->generated)
10238     {
10239       genIfxJump (ifx, ifxCond, left, NULL, result);
10240     }
10241
10242   freeAsmop (result, NULL, ic, TRUE);
10243   freeAsmop (left, NULL, ic, TRUE);
10244 }
10245
10246 /*-----------------------------------------------------------------*/
10247 /* genCodePointerGet - get value from code space                   */
10248 /*-----------------------------------------------------------------*/
10249 static void
10250 genCodePointerGet (operand * left,
10251                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10252 {
10253   int size, offset;
10254   char *ifxCond = "a";
10255   sym_link *retype = getSpec (operandType (result));
10256
10257   D (emitcode (";", "genCodePointerGet"));
10258
10259   aopOp (left, ic, FALSE);
10260   loadDptrFromOperand (left, FALSE);
10261
10262   /* so dptr now contains the address */
10263   aopOp (result, ic, FALSE);
10264
10265   /* if bit then unpack */
10266   if (IS_BITFIELD (retype))
10267     ifxCond = genUnpackBits (result, "dptr", CPOINTER, ifx);
10268   else
10269     {
10270       size = AOP_SIZE (result);
10271       offset = 0;
10272
10273       while (size--)
10274         {
10275           emitcode ("clr", "a");
10276           emitcode ("movc", "a,@a+dptr");
10277           if (!ifx)
10278             aopPut (result, "a", offset++);
10279           if (size || pi)
10280             emitcode ("inc", "dptr");
10281         }
10282     }
10283
10284   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10285     {
10286       aopPut (left, "dpl", 0);
10287       aopPut (left, "dph", 1);
10288       pi->generated = 1;
10289     }
10290
10291   if (ifx && !ifx->generated)
10292     {
10293       genIfxJump (ifx, ifxCond, left, NULL, result);
10294     }
10295
10296   freeAsmop (result, NULL, ic, TRUE);
10297   freeAsmop (left, NULL, ic, TRUE);
10298 }
10299
10300 /*-----------------------------------------------------------------*/
10301 /* genGenPointerGet - get value from generic pointer space         */
10302 /*-----------------------------------------------------------------*/
10303 static void
10304 genGenPointerGet (operand * left,
10305                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10306 {
10307   int size, offset;
10308   char *ifxCond = "a";
10309   sym_link *retype = getSpec (operandType (result));
10310
10311   D (emitcode (";", "genGenPointerGet"));
10312
10313   aopOp (left, ic, FALSE);
10314   loadDptrFromOperand (left, TRUE);
10315
10316   /* so dptr now contains the address */
10317   aopOp (result, ic, FALSE);
10318
10319   /* if bit then unpack */
10320   if (IS_BITFIELD (retype))
10321     {
10322       ifxCond = genUnpackBits (result, "dptr", GPOINTER, ifx);
10323     }
10324   else
10325     {
10326       size = AOP_SIZE (result);
10327       offset = 0;
10328
10329       while (size--)
10330         {
10331           emitcode ("lcall", "__gptrget");
10332           if (!ifx)
10333             aopPut (result, "a", offset++);
10334           if (size || pi)
10335             emitcode ("inc", "dptr");
10336         }
10337     }
10338
10339   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10340     {
10341       aopPut (left, "dpl", 0);
10342       aopPut (left, "dph", 1);
10343       pi->generated = 1;
10344     }
10345
10346   if (ifx && !ifx->generated)
10347     {
10348       genIfxJump (ifx, ifxCond, left, NULL, result);
10349     }
10350
10351   freeAsmop (result, NULL, ic, TRUE);
10352   freeAsmop (left, NULL, ic, TRUE);
10353 }
10354
10355 /*-----------------------------------------------------------------*/
10356 /* genPointerGet - generate code for pointer get                   */
10357 /*-----------------------------------------------------------------*/
10358 static void
10359 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10360 {
10361   operand *left, *result;
10362   sym_link *type, *etype;
10363   int p_type;
10364
10365   D (emitcode (";", "genPointerGet"));
10366
10367   left = IC_LEFT (ic);
10368   result = IC_RESULT (ic);
10369
10370   if (getSize (operandType (result))>1)
10371     ifx = NULL;
10372
10373   /* depending on the type of pointer we need to
10374      move it to the correct pointer register */
10375   type = operandType (left);
10376   etype = getSpec (type);
10377   /* if left is of type of pointer then it is simple */
10378   if (IS_PTR (type) && !IS_FUNC (type->next))
10379     {
10380       p_type = DCL_TYPE (type);
10381     }
10382   else
10383     {
10384       /* we have to go by the storage class */
10385       p_type = PTR_TYPE (SPEC_OCLS (etype));
10386     }
10387
10388   /* special case when cast remat */
10389   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10390       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10391     {
10392       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10393       type = operandType (left);
10394       p_type = DCL_TYPE (type);
10395     }
10396   /* now that we have the pointer type we assign
10397      the pointer values */
10398   switch (p_type)
10399     {
10400
10401     case POINTER:
10402     case IPOINTER:
10403       genNearPointerGet (left, result, ic, pi, ifx);
10404       break;
10405
10406     case PPOINTER:
10407       genPagedPointerGet (left, result, ic, pi, ifx);
10408       break;
10409
10410     case FPOINTER:
10411       genFarPointerGet (left, result, ic, pi, ifx);
10412       break;
10413
10414     case CPOINTER:
10415       genCodePointerGet (left, result, ic, pi, ifx);
10416       break;
10417
10418     case GPOINTER:
10419       genGenPointerGet (left, result, ic, pi, ifx);
10420       break;
10421     }
10422 }
10423
10424
10425 /*-----------------------------------------------------------------*/
10426 /* genPackBits - generates code for packed bit storage             */
10427 /*-----------------------------------------------------------------*/
10428 static void
10429 genPackBits (sym_link * etype,
10430              operand * right,
10431              char *rname, int p_type)
10432 {
10433   int offset = 0;       /* source byte offset */
10434   int rlen = 0;         /* remaining bitfield length */
10435   int blen;             /* bitfield length */
10436   int bstr;             /* bitfield starting bit within byte */
10437   int litval;           /* source literal value (if AOP_LIT) */
10438   unsigned char mask;   /* bitmask within current byte */
10439
10440   D(emitcode (";", "genPackBits"));
10441
10442   blen = SPEC_BLEN (etype);
10443   bstr = SPEC_BSTR (etype);
10444
10445   /* If the bitfield length is less than a byte */
10446   if (blen < 8)
10447     {
10448       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10449               (unsigned char) (0xFF >> (8 - bstr)));
10450
10451       if (AOP_TYPE (right) == AOP_LIT)
10452         {
10453           /* Case with a bitfield length <8 and literal source
10454           */
10455           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10456           litval <<= bstr;
10457           litval &= (~mask) & 0xff;
10458           emitPtrByteGet (rname, p_type, FALSE);
10459           if ((mask|litval)!=0xff)
10460             emitcode ("anl","a,#0x%02x", mask);
10461           if (litval)
10462             emitcode ("orl","a,#0x%02x", litval);
10463         }
10464       else
10465         {
10466           if ((blen==1) && (p_type!=GPOINTER))
10467             {
10468               /* Case with a bitfield length == 1 and no generic pointer
10469               */
10470               if (AOP_TYPE (right) == AOP_CRY)
10471                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10472               else
10473                 {
10474                   MOVA (aopGet (right, 0, FALSE, FALSE));
10475                   emitcode ("rrc","a");
10476                 }
10477               emitPtrByteGet (rname, p_type, FALSE);
10478               emitcode ("mov","acc.%d,c",bstr);
10479             }
10480           else
10481             {
10482               bool pushedB;
10483               /* Case with a bitfield length < 8 and arbitrary source
10484               */
10485               MOVA (aopGet (right, 0, FALSE, FALSE));
10486               /* shift and mask source value */
10487               AccLsh (bstr);
10488               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10489
10490               pushedB = pushB ();
10491               /* transfer A to B and get next byte */
10492               emitPtrByteGet (rname, p_type, TRUE);
10493
10494               emitcode ("anl", "a,#0x%02x", mask);
10495               emitcode ("orl", "a,b");
10496               if (p_type == GPOINTER)
10497                 emitcode ("pop", "b");
10498
10499               popB (pushedB);
10500            }
10501         }
10502
10503       emitPtrByteSet (rname, p_type, "a");
10504       return;
10505     }
10506
10507   /* Bit length is greater than 7 bits. In this case, copy  */
10508   /* all except the partial byte at the end                 */
10509   for (rlen=blen;rlen>=8;rlen-=8)
10510     {
10511       emitPtrByteSet (rname, p_type,
10512                       aopGet (right, offset++, FALSE, TRUE) );
10513       if (rlen>8)
10514         emitcode ("inc", "%s", rname);
10515     }
10516
10517   /* If there was a partial byte at the end */
10518   if (rlen)
10519     {
10520       mask = (((unsigned char) -1 << rlen) & 0xff);
10521
10522       if (AOP_TYPE (right) == AOP_LIT)
10523         {
10524           /* Case with partial byte and literal source
10525           */
10526           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10527           litval >>= (blen-rlen);
10528           litval &= (~mask) & 0xff;
10529           emitPtrByteGet (rname, p_type, FALSE);
10530           if ((mask|litval)!=0xff)
10531             emitcode ("anl","a,#0x%02x", mask);
10532           if (litval)
10533             emitcode ("orl","a,#0x%02x", litval);
10534         }
10535       else
10536         {
10537           bool pushedB;
10538           /* Case with partial byte and arbitrary source
10539           */
10540           MOVA (aopGet (right, offset++, FALSE, FALSE));
10541           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10542
10543           pushedB = pushB ();
10544           /* transfer A to B and get next byte */
10545           emitPtrByteGet (rname, p_type, TRUE);
10546
10547           emitcode ("anl", "a,#0x%02x", mask);
10548           emitcode ("orl", "a,b");
10549           if (p_type == GPOINTER)
10550             emitcode ("pop", "b");
10551
10552           popB (pushedB);
10553         }
10554       emitPtrByteSet (rname, p_type, "a");
10555     }
10556 }
10557
10558
10559 /*-----------------------------------------------------------------*/
10560 /* genDataPointerSet - remat pointer to data space                 */
10561 /*-----------------------------------------------------------------*/
10562 static void
10563 genDataPointerSet (operand * right,
10564                    operand * result,
10565                    iCode * ic)
10566 {
10567   int size, offset = 0;
10568   char *l, buffer[256];
10569
10570   D (emitcode (";", "genDataPointerSet"));
10571
10572   aopOp (right, ic, FALSE);
10573
10574   l = aopGet (result, 0, FALSE, TRUE);
10575   l++; //remove #
10576   size = max (AOP_SIZE (right), AOP_SIZE (result));
10577   while (size--)
10578     {
10579       if (offset)
10580         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10581       else
10582         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10583       emitcode ("mov", "%s,%s", buffer,
10584                 aopGet (right, offset++, FALSE, FALSE));
10585     }
10586
10587   freeAsmop (right, NULL, ic, TRUE);
10588   freeAsmop (result, NULL, ic, TRUE);
10589 }
10590
10591 /*-----------------------------------------------------------------*/
10592 /* genNearPointerSet - emitcode for near pointer put               */
10593 /*-----------------------------------------------------------------*/
10594 static void
10595 genNearPointerSet (operand * right,
10596                    operand * result,
10597                    iCode * ic,
10598                    iCode * pi)
10599 {
10600   asmop *aop = NULL;
10601   regs *preg = NULL;
10602   char *rname, *l;
10603   sym_link *retype, *letype;
10604   sym_link *ptype = operandType (result);
10605
10606   D (emitcode (";", "genNearPointerSet"));
10607
10608   retype = getSpec (operandType (right));
10609   letype = getSpec (ptype);
10610
10611   aopOp (result, ic, FALSE);
10612
10613   /* if the result is rematerializable &
10614      in data space & not a bit variable */
10615   if (AOP_TYPE (result) == AOP_IMMD &&
10616       DCL_TYPE (ptype) == POINTER &&
10617       !IS_BITVAR (retype) &&
10618       !IS_BITVAR (letype))
10619     {
10620       genDataPointerSet (right, result, ic);
10621       return;
10622     }
10623
10624   /* if the value is already in a pointer register
10625      then don't need anything more */
10626   if (!AOP_INPREG (AOP (result)))
10627     {
10628       if (IS_AOP_PREG (result))
10629         {
10630           // Aha, it is a pointer, just in disguise.
10631           rname = aopGet (result, 0, FALSE, FALSE);
10632           if (*rname != '@')
10633             {
10634               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10635                       __FILE__, __LINE__);
10636             }
10637           else
10638             {
10639               // Expected case.
10640               emitcode ("mov", "a%s,%s", rname + 1, rname);
10641               rname++;  // skip the '@'.
10642             }
10643         }
10644       else
10645         {
10646           /* otherwise get a free pointer register */
10647           aop = newAsmop (0);
10648           preg = getFreePtr (ic, &aop, FALSE);
10649           emitcode ("mov", "%s,%s",
10650                     preg->name,
10651                     aopGet (result, 0, FALSE, TRUE));
10652           rname = preg->name;
10653         }
10654     }
10655   else
10656     {
10657       rname = aopGet (result, 0, FALSE, FALSE);
10658     }
10659
10660   aopOp (right, ic, FALSE);
10661
10662   /* if bitfield then unpack the bits */
10663   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10664     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10665   else
10666     {
10667       /* we can just get the values */
10668       int size = AOP_SIZE (right);
10669       int offset = 0;
10670
10671       while (size--)
10672         {
10673           l = aopGet (right, offset, FALSE, TRUE);
10674           if ((*l == '@') || (strcmp (l, "acc") == 0))
10675             {
10676               MOVA (l);
10677               emitcode ("mov", "@%s,a", rname);
10678             }
10679           else
10680             emitcode ("mov", "@%s,%s", rname, l);
10681           if (size || pi)
10682             emitcode ("inc", "%s", rname);
10683           offset++;
10684         }
10685     }
10686
10687   /* now some housekeeping stuff */
10688   if (aop) /* we had to allocate for this iCode */
10689     {
10690       if (pi)
10691         aopPut (result, rname, 0);
10692       freeAsmop (NULL, aop, ic, TRUE);
10693     }
10694   else
10695     {
10696       /* we did not allocate which means left
10697          already in a pointer register, then
10698          if size > 0 && this could be used again
10699          we have to point it back to where it
10700          belongs */
10701       if ((AOP_SIZE (right) > 1 &&
10702            !OP_SYMBOL (result)->remat &&
10703            (OP_SYMBOL (result)->liveTo > ic->seq ||
10704             ic->depth)) &&
10705           !pi)
10706         {
10707           int size = AOP_SIZE (right) - 1;
10708           while (size--)
10709             emitcode ("dec", "%s", rname);
10710         }
10711     }
10712
10713   /* done */
10714   if (pi)
10715     pi->generated = 1;
10716   freeAsmop (right, NULL, ic, TRUE);
10717   freeAsmop (result, NULL, ic, TRUE);
10718 }
10719
10720 /*-----------------------------------------------------------------*/
10721 /* genPagedPointerSet - emitcode for Paged pointer put             */
10722 /*-----------------------------------------------------------------*/
10723 static void
10724 genPagedPointerSet (operand * right,
10725                     operand * result,
10726                     iCode * ic,
10727                     iCode * pi)
10728 {
10729   asmop *aop = NULL;
10730   regs *preg = NULL;
10731   char *rname, *l;
10732   sym_link *retype, *letype;
10733
10734   D (emitcode (";", "genPagedPointerSet"));
10735
10736   retype = getSpec (operandType (right));
10737   letype = getSpec (operandType (result));
10738
10739   aopOp (result, ic, FALSE);
10740
10741   /* if the value is already in a pointer register
10742      then don't need anything more */
10743   if (!AOP_INPREG (AOP (result)))
10744     {
10745       if (IS_AOP_PREG (result))
10746         {
10747           // Aha, it is a pointer, just in disguise.
10748           rname = aopGet (result, 0, FALSE, FALSE);
10749           if (*rname != '@')
10750             {
10751               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10752                       __FILE__, __LINE__);
10753             }
10754           else
10755             {
10756               // Expected case.
10757               emitcode ("mov", "a%s,%s", rname + 1, rname);
10758               rname++;  // skip the '@'.
10759             }
10760         }
10761       else
10762         {
10763           /* otherwise get a free pointer register */
10764           aop = newAsmop (0);
10765           preg = getFreePtr (ic, &aop, FALSE);
10766           emitcode ("mov", "%s,%s",
10767                     preg->name,
10768                     aopGet (result, 0, FALSE, TRUE));
10769           rname = preg->name;
10770         }
10771     }
10772   else
10773     {
10774       rname = aopGet (result, 0, FALSE, FALSE);
10775     }
10776
10777   aopOp (right, ic, FALSE);
10778
10779   /* if bitfield then unpack the bits */
10780   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10781     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10782   else
10783     {
10784       /* we can just get the values */
10785       int size = AOP_SIZE (right);
10786       int offset = 0;
10787
10788       while (size--)
10789         {
10790           l = aopGet (right, offset, FALSE, TRUE);
10791           MOVA (l);
10792           emitcode ("movx", "@%s,a", rname);
10793           if (size || pi)
10794             emitcode ("inc", "%s", rname);
10795           offset++;
10796         }
10797     }
10798
10799   /* now some housekeeping stuff */
10800   if (aop) /* we had to allocate for this iCode */
10801     {
10802       if (pi)
10803         aopPut (result, rname, 0);
10804       freeAsmop (NULL, aop, ic, TRUE);
10805     }
10806   else
10807     {
10808       /* we did not allocate which means left
10809          already in a pointer register, then
10810          if size > 0 && this could be used again
10811          we have to point it back to where it
10812          belongs */
10813       if (AOP_SIZE (right) > 1 &&
10814           !OP_SYMBOL (result)->remat &&
10815           (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) &&
10816           !pi)
10817         {
10818           int size = AOP_SIZE (right) - 1;
10819           while (size--)
10820             emitcode ("dec", "%s", rname);
10821         }
10822     }
10823
10824   /* done */
10825   if (pi)
10826     pi->generated = 1;
10827   freeAsmop (right, NULL, ic, TRUE);
10828   freeAsmop (result, NULL, ic, TRUE);
10829 }
10830
10831 /*-----------------------------------------------------------------*/
10832 /* genFarPointerSet - set value from far space                     */
10833 /*-----------------------------------------------------------------*/
10834 static void
10835 genFarPointerSet (operand * right,
10836                   operand * result, iCode * ic, iCode * pi)
10837 {
10838   int size, offset;
10839   sym_link *retype = getSpec (operandType (right));
10840   sym_link *letype = getSpec (operandType (result));
10841
10842   D(emitcode (";", "genFarPointerSet"));
10843
10844   aopOp (result, ic, FALSE);
10845   loadDptrFromOperand (result, FALSE);
10846
10847   /* so dptr now contains the address */
10848   aopOp (right, ic, FALSE);
10849
10850   /* if bit then unpack */
10851   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10852     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10853   else
10854     {
10855       size = AOP_SIZE (right);
10856       offset = 0;
10857
10858       while (size--)
10859         {
10860           char *l = aopGet (right, offset++, FALSE, FALSE);
10861           MOVA (l);
10862           emitcode ("movx", "@dptr,a");
10863           if (size || pi)
10864             emitcode ("inc", "dptr");
10865         }
10866     }
10867   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10868     aopPut (result, "dpl", 0);
10869     aopPut (result, "dph", 1);
10870     pi->generated=1;
10871   }
10872   freeAsmop (result, NULL, ic, TRUE);
10873   freeAsmop (right, NULL, ic, TRUE);
10874 }
10875
10876 /*-----------------------------------------------------------------*/
10877 /* genGenPointerSet - set value from generic pointer space         */
10878 /*-----------------------------------------------------------------*/
10879 static void
10880 genGenPointerSet (operand * right,
10881                   operand * result, iCode * ic, iCode * pi)
10882 {
10883   int size, offset;
10884   sym_link *retype = getSpec (operandType (right));
10885   sym_link *letype = getSpec (operandType (result));
10886
10887   D (emitcode (";", "genGenPointerSet"));
10888
10889   aopOp (result, ic, FALSE);
10890   loadDptrFromOperand (result, TRUE);
10891
10892   /* so dptr now contains the address */
10893   aopOp (right, ic, FALSE);
10894
10895   /* if bit then unpack */
10896   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10897     {
10898       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10899     }
10900   else
10901     {
10902       size = AOP_SIZE (right);
10903       offset = 0;
10904
10905       while (size--)
10906         {
10907           char *l = aopGet (right, offset++, FALSE, FALSE);
10908           MOVA (l);
10909           emitcode ("lcall", "__gptrput");
10910           if (size || pi)
10911             emitcode ("inc", "dptr");
10912         }
10913     }
10914
10915   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10916     aopPut (result, "dpl", 0);
10917     aopPut (result, "dph", 1);
10918     pi->generated=1;
10919   }
10920   freeAsmop (result, NULL, ic, TRUE);
10921   freeAsmop (right, NULL, ic, TRUE);
10922 }
10923
10924 /*-----------------------------------------------------------------*/
10925 /* genPointerSet - stores the value into a pointer location        */
10926 /*-----------------------------------------------------------------*/
10927 static void
10928 genPointerSet (iCode * ic, iCode *pi)
10929 {
10930   operand *right, *result;
10931   sym_link *type, *etype;
10932   int p_type;
10933
10934   D (emitcode (";", "genPointerSet"));
10935
10936   right = IC_RIGHT (ic);
10937   result = IC_RESULT (ic);
10938
10939   /* depending on the type of pointer we need to
10940      move it to the correct pointer register */
10941   type = operandType (result);
10942   etype = getSpec (type);
10943   /* if left is of type of pointer then it is simple */
10944   if (IS_PTR (type) && !IS_FUNC (type->next))
10945     {
10946       p_type = DCL_TYPE (type);
10947     }
10948   else
10949     {
10950       /* we have to go by the storage class */
10951       p_type = PTR_TYPE (SPEC_OCLS (etype));
10952     }
10953
10954   /* special case when cast remat */
10955   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10956       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10957           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10958           type = operandType (result);
10959           p_type = DCL_TYPE (type);
10960   }
10961
10962   /* now that we have the pointer type we assign
10963      the pointer values */
10964   switch (p_type)
10965     {
10966
10967     case POINTER:
10968     case IPOINTER:
10969       genNearPointerSet (right, result, ic, pi);
10970       break;
10971
10972     case PPOINTER:
10973       genPagedPointerSet (right, result, ic, pi);
10974       break;
10975
10976     case FPOINTER:
10977       genFarPointerSet (right, result, ic, pi);
10978       break;
10979
10980     case GPOINTER:
10981       genGenPointerSet (right, result, ic, pi);
10982       break;
10983
10984     default:
10985       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10986               "genPointerSet: illegal pointer type");
10987     }
10988 }
10989
10990 /*-----------------------------------------------------------------*/
10991 /* genIfx - generate code for Ifx statement                        */
10992 /*-----------------------------------------------------------------*/
10993 static void
10994 genIfx (iCode * ic, iCode * popIc)
10995 {
10996   operand *cond = IC_COND (ic);
10997   int isbit = 0;
10998   char *dup = NULL;
10999
11000   D (emitcode (";", "genIfx"));
11001
11002   aopOp (cond, ic, FALSE);
11003
11004   /* get the value into acc */
11005   if (AOP_TYPE (cond) != AOP_CRY)
11006     {
11007       toBoolean (cond);
11008     }
11009   else
11010     {
11011       isbit = 1;
11012       if (AOP(cond)->aopu.aop_dir)
11013         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11014     }
11015
11016   /* the result is now in the accumulator or a directly addressable bit */
11017   freeAsmop (cond, NULL, ic, TRUE);
11018
11019   /* if there was something to be popped then do it */
11020   if (popIc)
11021     genIpop (popIc);
11022
11023   /* if the condition is a bit variable */
11024   if (isbit && dup)
11025     genIfxJump(ic, dup, NULL, NULL, NULL);
11026   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11027     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
11028   else if (isbit && !IS_ITEMP (cond))
11029     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
11030   else
11031     genIfxJump (ic, "a", NULL, NULL, NULL);
11032
11033   ic->generated = 1;
11034 }
11035
11036 /*-----------------------------------------------------------------*/
11037 /* genAddrOf - generates code for address of                       */
11038 /*-----------------------------------------------------------------*/
11039 static void
11040 genAddrOf (iCode * ic)
11041 {
11042   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11043   int size, offset;
11044
11045   D (emitcode (";", "genAddrOf"));
11046
11047   aopOp (IC_RESULT (ic), ic, FALSE);
11048
11049   /* if the operand is on the stack then we
11050      need to get the stack offset of this
11051      variable */
11052   if (sym->onStack)
11053     {
11054       /* if it has an offset then we need to compute it */
11055       if (sym->stack)
11056         {
11057           int stack_offset = ((sym->stack < 0) ?
11058                               ((char) (sym->stack - _G.nRegsSaved)) :
11059                               ((char) sym->stack)) & 0xff;
11060           if ((abs(stack_offset) == 1) &&
11061               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11062               !isOperandVolatile (IC_RESULT (ic), FALSE))
11063             {
11064               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11065               if (stack_offset > 0)
11066                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11067               else
11068                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11069             }
11070           else
11071             {
11072               emitcode ("mov", "a,%s", SYM_BP (sym));
11073               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11074               aopPut (IC_RESULT (ic), "a", 0);
11075             }
11076         }
11077       else
11078         {
11079           /* we can just move _bp */
11080           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11081         }
11082       /* fill the result with zero */
11083       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11084
11085       offset = 1;
11086       while (size--)
11087         {
11088           aopPut (IC_RESULT (ic), zero, offset++);
11089         }
11090       goto release;
11091     }
11092
11093   /* object not on stack then we need the name */
11094   size = AOP_SIZE (IC_RESULT (ic));
11095   offset = 0;
11096
11097   while (size--)
11098     {
11099       char s[SDCC_NAME_MAX];
11100       if (offset)
11101         sprintf (s, "#(%s >> %d)",
11102                  sym->rname,
11103                  offset * 8);
11104       else
11105         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11106       aopPut (IC_RESULT (ic), s, offset++);
11107     }
11108
11109 release:
11110   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11111
11112 }
11113
11114 /*-----------------------------------------------------------------*/
11115 /* genFarFarAssign - assignment when both are in far space         */
11116 /*-----------------------------------------------------------------*/
11117 static void
11118 genFarFarAssign (operand * result, operand * right, iCode * ic)
11119 {
11120   int size = AOP_SIZE (right);
11121   int offset = 0;
11122   char *l;
11123
11124   D (emitcode (";", "genFarFarAssign"));
11125
11126   /* first push the right side on to the stack */
11127   while (size--)
11128     {
11129       l = aopGet (right, offset++, FALSE, FALSE);
11130       MOVA (l);
11131       emitcode ("push", "acc");
11132     }
11133
11134   freeAsmop (right, NULL, ic, FALSE);
11135   /* now assign DPTR to result */
11136   aopOp (result, ic, FALSE);
11137   size = AOP_SIZE (result);
11138   while (size--)
11139     {
11140       emitcode ("pop", "acc");
11141       aopPut (result, "a", --offset);
11142     }
11143   freeAsmop (result, NULL, ic, FALSE);
11144 }
11145
11146 /*-----------------------------------------------------------------*/
11147 /* genAssign - generate code for assignment                        */
11148 /*-----------------------------------------------------------------*/
11149 static void
11150 genAssign (iCode * ic)
11151 {
11152   operand *result, *right;
11153   int size, offset;
11154   unsigned long lit = 0L;
11155
11156   D (emitcode (";", "genAssign"));
11157
11158   result = IC_RESULT (ic);
11159   right = IC_RIGHT (ic);
11160
11161   /* if they are the same */
11162   if (operandsEqu (result, right) &&
11163       !isOperandVolatile (result, FALSE) &&
11164       !isOperandVolatile (right, FALSE))
11165     return;
11166
11167   aopOp (right, ic, FALSE);
11168
11169   /* special case both in far space */
11170   if (AOP_TYPE (right) == AOP_DPTR &&
11171       IS_TRUE_SYMOP (result) &&
11172       isOperandInFarSpace (result))
11173     {
11174       genFarFarAssign (result, right, ic);
11175       return;
11176     }
11177
11178   aopOp (result, ic, TRUE);
11179
11180   /* if they are the same registers */
11181   if (sameRegs (AOP (right), AOP (result)) &&
11182       !isOperandVolatile (result, FALSE) &&
11183       !isOperandVolatile (right, FALSE))
11184     goto release;
11185
11186   /* if the result is a bit */
11187   if (AOP_TYPE (result) == AOP_CRY)
11188     {
11189       assignBit (result, right);
11190       goto release;
11191     }
11192
11193   /* bit variables done */
11194   /* general case */
11195   size = AOP_SIZE (result);
11196   offset = 0;
11197   if (AOP_TYPE (right) == AOP_LIT)
11198     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11199
11200   if ((size > 1) &&
11201       (AOP_TYPE (result) != AOP_REG) &&
11202       (AOP_TYPE (right) == AOP_LIT) &&
11203       !IS_FLOAT (operandType (right)) &&
11204       (lit < 256L))
11205     {
11206       while ((size) && (lit))
11207         {
11208           aopPut (result,
11209                   aopGet (right, offset, FALSE, FALSE),
11210                   offset);
11211           lit >>= 8;
11212           offset++;
11213           size--;
11214         }
11215       /* And now fill the rest with zeros. */
11216       if (size)
11217         {
11218           emitcode ("clr", "a");
11219         }
11220       while (size--)
11221         {
11222           aopPut (result, "a", offset);
11223           offset++;
11224         }
11225     }
11226   else
11227     {
11228       while (size--)
11229         {
11230           aopPut (result,
11231                   aopGet (right, offset, FALSE, FALSE),
11232                   offset);
11233           offset++;
11234         }
11235     }
11236
11237 release:
11238   freeAsmop (result, NULL, ic, TRUE);
11239   freeAsmop (right, NULL, ic, TRUE);
11240 }
11241
11242 /*-----------------------------------------------------------------*/
11243 /* genJumpTab - generates code for jump table                      */
11244 /*-----------------------------------------------------------------*/
11245 static void
11246 genJumpTab (iCode * ic)
11247 {
11248   symbol *jtab,*jtablo,*jtabhi;
11249   char *l;
11250   unsigned int count;
11251
11252   D (emitcode (";", "genJumpTab"));
11253
11254   count = elementsInSet( IC_JTLABELS (ic) );
11255
11256   if( count <= 16 )
11257     {
11258       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11259          if the switch argument is in a register.
11260          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11261       /* Peephole may not convert ljmp to sjmp or ret
11262          labelIsReturnOnly & labelInRange must check
11263          currPl->ic->op != JUMPTABLE */
11264       aopOp (IC_JTCOND (ic), ic, FALSE);
11265       /* get the condition into accumulator */
11266       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11267       MOVA (l);
11268       /* multiply by three */
11269       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11270         {
11271           emitcode ("mov", "b,#3");
11272           emitcode ("mul", "ab");
11273         }
11274       else
11275         {
11276           emitcode ("add", "a,acc");
11277           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11278         }
11279       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11280
11281       jtab = newiTempLabel (NULL);
11282       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11283       emitcode ("jmp", "@a+dptr");
11284       emitLabel (jtab);
11285       /* now generate the jump labels */
11286       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11287            jtab = setNextItem (IC_JTLABELS (ic)))
11288         emitcode ("ljmp", "%05d$", jtab->key + 100);
11289     }
11290   else
11291     {
11292       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11293          if the switch argument is in a register.
11294          For n>6 this algorithm may be more compact */
11295       jtablo = newiTempLabel (NULL);
11296       jtabhi = newiTempLabel (NULL);
11297
11298       /* get the condition into accumulator.
11299          Using b as temporary storage, if register push/pop is needed */
11300       aopOp (IC_JTCOND (ic), ic, FALSE);
11301       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11302       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11303           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11304         {
11305           // (MB) what if B is in use???
11306           wassertl(!BINUSE, "B was in use");
11307           emitcode ("mov", "b,%s", l);
11308           l = "b";
11309         }
11310       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11311       MOVA (l);
11312       if( count <= 112 )
11313         {
11314           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11315           emitcode ("movc", "a,@a+pc");
11316           emitcode ("push", "acc");
11317
11318           MOVA (l);
11319           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11320           emitcode ("movc", "a,@a+pc");
11321           emitcode ("push", "acc");
11322         }
11323       else
11324         {
11325           /* this scales up to n<=255, but needs two more bytes
11326              and changes dptr */
11327           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11328           emitcode ("movc", "a,@a+dptr");
11329           emitcode ("push", "acc");
11330
11331           MOVA (l);
11332           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11333           emitcode ("movc", "a,@a+dptr");
11334           emitcode ("push", "acc");
11335         }
11336
11337       emitcode ("ret", "");
11338
11339       /* now generate jump table, LSB */
11340       emitLabel (jtablo);
11341       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11342            jtab = setNextItem (IC_JTLABELS (ic)))
11343         emitcode (".db", "%05d$", jtab->key + 100);
11344
11345       /* now generate jump table, MSB */
11346       emitLabel (jtabhi);
11347       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11348            jtab = setNextItem (IC_JTLABELS (ic)))
11349          emitcode (".db", "%05d$>>8", jtab->key + 100);
11350     }
11351 }
11352
11353 /*-----------------------------------------------------------------*/
11354 /* genCast - gen code for casting                                  */
11355 /*-----------------------------------------------------------------*/
11356 static void
11357 genCast (iCode * ic)
11358 {
11359   operand *result = IC_RESULT (ic);
11360   sym_link *ctype = operandType (IC_LEFT (ic));
11361   sym_link *rtype = operandType (IC_RIGHT (ic));
11362   operand *right = IC_RIGHT (ic);
11363   int size, offset;
11364
11365   D (emitcode (";", "genCast"));
11366
11367   /* if they are equivalent then do nothing */
11368   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11369     return;
11370
11371   aopOp (right, ic, FALSE);
11372   aopOp (result, ic, FALSE);
11373
11374   /* if the result is a bit (and not a bitfield) */
11375   if (IS_BIT (OP_SYMBOL (result)->type))
11376     {
11377       assignBit (result, right);
11378       goto release;
11379     }
11380
11381   /* if they are the same size : or less */
11382   if (AOP_SIZE (result) <= AOP_SIZE (right))
11383     {
11384
11385       /* if they are in the same place */
11386       if (sameRegs (AOP (right), AOP (result)))
11387         goto release;
11388
11389       /* if they in different places then copy */
11390       size = AOP_SIZE (result);
11391       offset = 0;
11392       while (size--)
11393         {
11394           aopPut (result,
11395                   aopGet (right, offset, FALSE, FALSE),
11396                   offset);
11397           offset++;
11398         }
11399       goto release;
11400     }
11401
11402   /* if the result is of type pointer */
11403   if (IS_PTR (ctype))
11404     {
11405
11406       int p_type;
11407       sym_link *type = operandType (right);
11408       sym_link *etype = getSpec (type);
11409
11410       /* pointer to generic pointer */
11411       if (IS_GENPTR (ctype))
11412         {
11413           if (IS_PTR (type))
11414             {
11415               p_type = DCL_TYPE (type);
11416             }
11417           else
11418             {
11419               if (SPEC_SCLS(etype)==S_REGISTER) {
11420                 // let's assume it is a generic pointer
11421                 p_type=GPOINTER;
11422               } else {
11423                 /* we have to go by the storage class */
11424                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11425               }
11426             }
11427
11428           /* the first two bytes are known */
11429           size = GPTRSIZE - 1;
11430           offset = 0;
11431           while (size--)
11432             {
11433               aopPut (result,
11434                       aopGet (right, offset, FALSE, FALSE),
11435                       offset);
11436               offset++;
11437             }
11438           /* the last byte depending on type */
11439             {
11440                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11441                 char gpValStr[10];
11442
11443                 if (gpVal == -1)
11444                 {
11445                     // pointerTypeToGPByte will have bitched.
11446                     exit(1);
11447                 }
11448
11449                 sprintf(gpValStr, "#0x%x", gpVal);
11450                 aopPut (result, gpValStr, GPTRSIZE - 1);
11451             }
11452           goto release;
11453         }
11454
11455       /* just copy the pointers */
11456       size = AOP_SIZE (result);
11457       offset = 0;
11458       while (size--)
11459         {
11460           aopPut (result,
11461                   aopGet (right, offset, FALSE, FALSE),
11462                   offset);
11463           offset++;
11464         }
11465       goto release;
11466     }
11467
11468   /* so we now know that the size of destination is greater
11469      than the size of the source */
11470   /* we move to result for the size of source */
11471   size = AOP_SIZE (right);
11472   offset = 0;
11473   while (size--)
11474     {
11475       aopPut (result,
11476               aopGet (right, offset, FALSE, FALSE),
11477               offset);
11478       offset++;
11479     }
11480
11481   /* now depending on the sign of the source && destination */
11482   size = AOP_SIZE (result) - AOP_SIZE (right);
11483   /* if unsigned or not an integral type */
11484   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11485     {
11486       while (size--)
11487         aopPut (result, zero, offset++);
11488     }
11489   else
11490     {
11491       /* we need to extend the sign :{ */
11492       char *l = aopGet (right, AOP_SIZE (right) - 1,
11493                         FALSE, FALSE);
11494       MOVA (l);
11495       emitcode ("rlc", "a");
11496       emitcode ("subb", "a,acc");
11497       while (size--)
11498         aopPut (result, "a", offset++);
11499     }
11500
11501   /* we are done hurray !!!! */
11502
11503 release:
11504   freeAsmop (result, NULL, ic, TRUE);
11505   freeAsmop (right, NULL, ic, TRUE);
11506 }
11507
11508 /*-----------------------------------------------------------------*/
11509 /* genDjnz - generate decrement & jump if not zero instrucion      */
11510 /*-----------------------------------------------------------------*/
11511 static int
11512 genDjnz (iCode * ic, iCode * ifx)
11513 {
11514   symbol *lbl, *lbl1;
11515   if (!ifx)
11516     return 0;
11517
11518   /* if the if condition has a false label
11519      then we cannot save */
11520   if (IC_FALSE (ifx))
11521     return 0;
11522
11523   /* if the minus is not of the form a = a - 1 */
11524   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11525       !IS_OP_LITERAL (IC_RIGHT (ic)))
11526     return 0;
11527
11528   if (operandLitValue (IC_RIGHT (ic)) != 1)
11529     return 0;
11530
11531   /* if the size of this greater than one then no
11532      saving */
11533   if (getSize (operandType (IC_RESULT (ic))) > 1)
11534     return 0;
11535
11536   /* otherwise we can save BIG */
11537
11538   D (emitcode (";", "genDjnz"));
11539
11540   lbl = newiTempLabel (NULL);
11541   lbl1 = newiTempLabel (NULL);
11542
11543   aopOp (IC_RESULT (ic), ic, FALSE);
11544
11545   if (AOP_NEEDSACC(IC_RESULT(ic)))
11546   {
11547       /* If the result is accessed indirectly via
11548        * the accumulator, we must explicitly write
11549        * it back after the decrement.
11550        */
11551       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11552
11553       if (strcmp(rByte, "a"))
11554       {
11555            /* Something is hopelessly wrong */
11556            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11557                    __FILE__, __LINE__);
11558            /* We can just give up; the generated code will be inefficient,
11559             * but what the hey.
11560             */
11561            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11562            return 0;
11563       }
11564       emitcode ("dec", "%s", rByte);
11565       aopPut (IC_RESULT (ic), rByte, 0);
11566       emitcode ("jnz", "%05d$", lbl->key + 100);
11567   }
11568   else if (IS_AOP_PREG (IC_RESULT (ic)))
11569     {
11570       emitcode ("dec", "%s",
11571                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11572       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11573       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11574       ifx->generated = 1;
11575       emitcode ("jnz", "%05d$", lbl->key + 100);
11576     }
11577   else
11578     {
11579       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11580                 lbl->key + 100);
11581     }
11582   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11583   emitLabel (lbl);
11584   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11585   emitLabel (lbl1);
11586
11587   if (!ifx->generated)
11588       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11589   ifx->generated = 1;
11590   return 1;
11591 }
11592
11593 /*-----------------------------------------------------------------*/
11594 /* genReceive - generate code for a receive iCode                  */
11595 /*-----------------------------------------------------------------*/
11596 static void
11597 genReceive (iCode * ic)
11598 {
11599   int size = getSize (operandType (IC_RESULT (ic)));
11600   int offset = 0;
11601
11602   D (emitcode (";", "genReceive"));
11603
11604   if (ic->argreg == 1)
11605     { /* first parameter */
11606       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11607            isOperandInPagedSpace (IC_RESULT (ic))) &&
11608           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11609            IS_TRUE_SYMOP (IC_RESULT (ic))))
11610         {
11611           regs *tempRegs[4];
11612           int receivingA = 0;
11613           int roffset = 0;
11614
11615           for (offset = 0; offset<size; offset++)
11616             if (!strcmp (fReturn[offset], "a"))
11617               receivingA = 1;
11618
11619           if (!receivingA)
11620             {
11621               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11622                 {
11623                   for (offset = size-1; offset>0; offset--)
11624                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11625                   emitcode("mov","a,%s", fReturn[0]);
11626                   _G.accInUse++;
11627                   aopOp (IC_RESULT (ic), ic, FALSE);
11628                   _G.accInUse--;
11629                   aopPut (IC_RESULT (ic), "a", offset);
11630                   for (offset = 1; offset<size; offset++)
11631                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11632                   goto release;
11633                 }
11634             }
11635           else
11636             {
11637               if (getTempRegs(tempRegs, size, ic))
11638                 {
11639                   for (offset = 0; offset<size; offset++)
11640                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11641                   aopOp (IC_RESULT (ic), ic, FALSE);
11642                   for (offset = 0; offset<size; offset++)
11643                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11644                   goto release;
11645                 }
11646             }
11647
11648           offset = fReturnSizeMCS51 - size;
11649           while (size--)
11650             {
11651               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11652                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11653               offset++;
11654             }
11655           aopOp (IC_RESULT (ic), ic, FALSE);
11656           size = AOP_SIZE (IC_RESULT (ic));
11657           offset = 0;
11658           while (size--)
11659             {
11660               emitcode ("pop", "acc");
11661               aopPut (IC_RESULT (ic), "a", offset++);
11662             }
11663         }
11664       else
11665         {
11666           _G.accInUse++;
11667           aopOp (IC_RESULT (ic), ic, FALSE);
11668           _G.accInUse--;
11669           assignResultValue (IC_RESULT (ic), NULL);
11670         }
11671     }
11672   else if (ic->argreg > 12)
11673     { /* bit parameters */
11674       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11675
11676       BitBankUsed = 1;
11677       if (!reg || reg->rIdx != ic->argreg-5)
11678         {
11679           aopOp (IC_RESULT (ic), ic, FALSE);
11680           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11681           outBitC(IC_RESULT (ic));
11682         }
11683     }
11684   else
11685     { /* other parameters */
11686       int rb1off ;
11687       aopOp (IC_RESULT (ic), ic, FALSE);
11688       rb1off = ic->argreg;
11689       while (size--)
11690         {
11691           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11692         }
11693     }
11694
11695 release:
11696   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11697 }
11698
11699 /*-----------------------------------------------------------------*/
11700 /* genDummyRead - generate code for dummy read of volatiles        */
11701 /*-----------------------------------------------------------------*/
11702 static void
11703 genDummyRead (iCode * ic)
11704 {
11705   operand *op;
11706   int size, offset;
11707
11708   D (emitcode(";", "genDummyRead"));
11709
11710   op = IC_RIGHT (ic);
11711   if (op && IS_SYMOP (op))
11712     {
11713       aopOp (op, ic, FALSE);
11714
11715       /* if the result is a bit */
11716       if (AOP_TYPE (op) == AOP_CRY)
11717         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11718       else
11719         {
11720           /* bit variables done */
11721           /* general case */
11722           size = AOP_SIZE (op);
11723           offset = 0;
11724           while (size--)
11725           {
11726             MOVA (aopGet (op, offset, FALSE, FALSE));
11727             offset++;
11728           }
11729         }
11730
11731       freeAsmop (op, NULL, ic, TRUE);
11732     }
11733
11734   op = IC_LEFT (ic);
11735   if (op && IS_SYMOP (op))
11736     {
11737       aopOp (op, ic, FALSE);
11738
11739       /* if the result is a bit */
11740       if (AOP_TYPE (op) == AOP_CRY)
11741         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11742       else
11743         {
11744           /* bit variables done */
11745           /* general case */
11746           size = AOP_SIZE (op);
11747           offset = 0;
11748           while (size--)
11749           {
11750             MOVA (aopGet (op, offset, FALSE, FALSE));
11751             offset++;
11752           }
11753         }
11754
11755       freeAsmop (op, NULL, ic, TRUE);
11756     }
11757 }
11758
11759 /*-----------------------------------------------------------------*/
11760 /* genCritical - generate code for start of a critical sequence    */
11761 /*-----------------------------------------------------------------*/
11762 static void
11763 genCritical (iCode *ic)
11764 {
11765   symbol *tlbl = newiTempLabel (NULL);
11766
11767   D (emitcode(";", "genCritical"));
11768
11769   if (IC_RESULT (ic))
11770     {
11771       aopOp (IC_RESULT (ic), ic, TRUE);
11772       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11773       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11774       aopPut (IC_RESULT (ic), zero, 0);
11775       emitLabel (tlbl);
11776       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11777     }
11778   else
11779     {
11780       emitcode ("setb", "c");
11781       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11782       emitcode ("clr", "c");
11783       emitLabel (tlbl);
11784       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11785     }
11786 }
11787
11788 /*-----------------------------------------------------------------*/
11789 /* genEndCritical - generate code for end of a critical sequence   */
11790 /*-----------------------------------------------------------------*/
11791 static void
11792 genEndCritical (iCode *ic)
11793 {
11794   D(emitcode(";", "genEndCritical"));
11795
11796   if (IC_RIGHT (ic))
11797     {
11798       aopOp (IC_RIGHT (ic), ic, FALSE);
11799       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11800         {
11801           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11802           emitcode ("mov", "ea,c");
11803         }
11804       else
11805         {
11806           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11807             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11808           emitcode ("rrc", "a");
11809           emitcode ("mov", "ea,c");
11810         }
11811       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11812     }
11813   else
11814     {
11815       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11816       emitcode ("mov", "ea,c");
11817     }
11818 }
11819
11820 /*-----------------------------------------------------------------*/
11821 /* gen51Code - generate code for 8051 based controllers            */
11822 /*-----------------------------------------------------------------*/
11823 void
11824 gen51Code (iCode * lic)
11825 {
11826   iCode *ic;
11827   int cln = 0;
11828   /* int cseq = 0; */
11829
11830   _G.currentFunc = NULL;
11831   lineHead = lineCurr = NULL;
11832
11833   /* print the allocation information */
11834   if (allocInfo && currFunc)
11835     printAllocInfo (currFunc, codeOutBuf);
11836   /* if debug information required */
11837   if (options.debug && currFunc)
11838     {
11839       debugFile->writeFunction (currFunc, lic);
11840     }
11841   /* stack pointer name */
11842   if (options.useXstack)
11843     spname = "_spx";
11844   else
11845     spname = "sp";
11846
11847
11848   for (ic = lic; ic; ic = ic->next)
11849     {
11850       _G.current_iCode = ic;
11851
11852       if (ic->lineno && cln != ic->lineno)
11853         {
11854           if (options.debug)
11855             {
11856               debugFile->writeCLine (ic);
11857             }
11858           if (!options.noCcodeInAsm) {
11859             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11860                       printCLine(ic->filename, ic->lineno));
11861           }
11862           cln = ic->lineno;
11863         }
11864       #if 0
11865       if (ic->seqPoint && ic->seqPoint != cseq)
11866         {
11867           emitcode (";", "sequence point %d", ic->seqPoint);
11868           cseq = ic->seqPoint;
11869         }
11870       #endif
11871       if (options.iCodeInAsm) {
11872         char regsInUse[80];
11873         int i;
11874         const char *iLine;
11875
11876         #if 0
11877         for (i=0; i<8; i++) {
11878           sprintf (&regsInUse[i],
11879                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11880         regsInUse[i]=0;
11881         #else
11882         strcpy (regsInUse, "--------");
11883         for (i=0; i < 8; i++) {
11884           if (bitVectBitValue (ic->rMask, i))
11885             {
11886               int offset = regs8051[i].offset;
11887               regsInUse[offset] = offset + '0'; /* show rMask */
11888             }
11889         #endif
11890         }
11891         iLine = printILine(ic);
11892         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11893         dbuf_free(iLine);
11894       }
11895       /* if the result is marked as
11896          spilt and rematerializable or code for
11897          this has already been generated then
11898          do nothing */
11899       if (resultRemat (ic) || ic->generated)
11900         continue;
11901
11902       /* depending on the operation */
11903       switch (ic->op)
11904         {
11905         case '!':
11906           genNot (ic);
11907           break;
11908
11909         case '~':
11910           genCpl (ic);
11911           break;
11912
11913         case UNARYMINUS:
11914           genUminus (ic);
11915           break;
11916
11917         case IPUSH:
11918           genIpush (ic);
11919           break;
11920
11921         case IPOP:
11922           /* IPOP happens only when trying to restore a
11923              spilt live range, if there is an ifx statement
11924              following this pop then the if statement might
11925              be using some of the registers being popped which
11926              would destory the contents of the register so
11927              we need to check for this condition and handle it */
11928           if (ic->next &&
11929               ic->next->op == IFX &&
11930               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11931             genIfx (ic->next, ic);
11932           else
11933             genIpop (ic);
11934           break;
11935
11936         case CALL:
11937           genCall (ic);
11938           break;
11939
11940         case PCALL:
11941           genPcall (ic);
11942           break;
11943
11944         case FUNCTION:
11945           genFunction (ic);
11946           break;
11947
11948         case ENDFUNCTION:
11949           genEndFunction (ic);
11950           break;
11951
11952         case RETURN:
11953           genRet (ic);
11954           break;
11955
11956         case LABEL:
11957           genLabel (ic);
11958           break;
11959
11960         case GOTO:
11961           genGoto (ic);
11962           break;
11963
11964         case '+':
11965           genPlus (ic);
11966           break;
11967
11968         case '-':
11969           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11970             genMinus (ic);
11971           break;
11972
11973         case '*':
11974           genMult (ic);
11975           break;
11976
11977         case '/':
11978           genDiv (ic);
11979           break;
11980
11981         case '%':
11982           genMod (ic);
11983           break;
11984
11985         case '>':
11986           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11987           break;
11988
11989         case '<':
11990           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11991           break;
11992
11993         case LE_OP:
11994         case GE_OP:
11995         case NE_OP:
11996
11997           /* note these two are xlated by algebraic equivalence
11998              in decorateType() in SDCCast.c */
11999           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12000                   "got '>=' or '<=' shouldn't have come here");
12001           break;
12002
12003         case EQ_OP:
12004           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
12005           break;
12006
12007         case AND_OP:
12008           genAndOp (ic);
12009           break;
12010
12011         case OR_OP:
12012           genOrOp (ic);
12013           break;
12014
12015         case '^':
12016           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
12017           break;
12018
12019         case '|':
12020           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
12021           break;
12022
12023         case BITWISEAND:
12024           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
12025           break;
12026
12027         case INLINEASM:
12028           genInline (ic);
12029           break;
12030
12031         case RRC:
12032           genRRC (ic);
12033           break;
12034
12035         case RLC:
12036           genRLC (ic);
12037           break;
12038
12039         case GETHBIT:
12040           genGetHbit (ic);
12041           break;
12042
12043         case GETABIT:
12044           genGetAbit (ic);
12045           break;
12046
12047         case GETBYTE:
12048           genGetByte (ic);
12049           break;
12050
12051         case GETWORD:
12052           genGetWord (ic);
12053           break;
12054
12055         case LEFT_OP:
12056           genLeftShift (ic);
12057           break;
12058
12059         case RIGHT_OP:
12060           genRightShift (ic);
12061           break;
12062
12063         case GET_VALUE_AT_ADDRESS:
12064           genPointerGet (ic,
12065                          hasInc (IC_LEFT (ic), ic,
12066                                  getSize (operandType (IC_RESULT (ic)))),
12067                          ifxForOp (IC_RESULT (ic), ic) );
12068           break;
12069
12070         case '=':
12071           if (POINTER_SET (ic))
12072             genPointerSet (ic,
12073                            hasInc (IC_RESULT (ic), ic,
12074                                    getSize (operandType (IC_RIGHT (ic)))));
12075           else
12076             genAssign (ic);
12077           break;
12078
12079         case IFX:
12080           genIfx (ic, NULL);
12081           break;
12082
12083         case ADDRESS_OF:
12084           genAddrOf (ic);
12085           break;
12086
12087         case JUMPTABLE:
12088           genJumpTab (ic);
12089           break;
12090
12091         case CAST:
12092           genCast (ic);
12093           break;
12094
12095         case RECEIVE:
12096           genReceive (ic);
12097           break;
12098
12099         case SEND:
12100           addSet (&_G.sendSet, ic);
12101           break;
12102
12103         case DUMMY_READ_VOLATILE:
12104           genDummyRead (ic);
12105           break;
12106
12107         case CRITICAL:
12108           genCritical (ic);
12109           break;
12110
12111         case ENDCRITICAL:
12112           genEndCritical (ic);
12113           break;
12114
12115         case SWAP:
12116           genSwap (ic);
12117           break;
12118
12119         default:
12120           ic = ic;
12121         }
12122     }
12123
12124   _G.current_iCode = NULL;
12125
12126   /* now we are ready to call the
12127      peep hole optimizer */
12128   if (!options.nopeep)
12129     peepHole (&lineHead);
12130
12131   /* now do the actual printing */
12132   printLine (lineHead, codeOutBuf);
12133   return;
12134 }