9ce6403ede17a2a7f1631b703a81a95e75d53b83
[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
1675       // source is no literal and not in carry
1676       if ((s != zero) && (s != one) && strcmp (s, "c"))
1677         {
1678           MOVA (s);
1679           /* set C, if a >= 1 */
1680           emitcode ("add", "a,#0xff");
1681           s = "c";
1682         }
1683       // now source is zero, one or carry
1684
1685       /* if result no bit variable */
1686       if (!d)
1687         {
1688           if (!strcmp (s, "c"))
1689             {
1690               /* inefficient: move carry into A and use jz/jnz */
1691               emitcode ("clr", "a");
1692               emitcode ("rlc", "a");
1693               accuse = TRUE;
1694             }
1695           else
1696             {
1697               MOVA (s);
1698               accuse = TRUE;
1699             }
1700         }
1701       else if (s == zero)
1702           emitcode ("clr", "%s", d);
1703       else if (s == one)
1704           emitcode ("setb", "%s", d);
1705       else if (strcmp (s, d))
1706           emitcode ("mov", "%s,c", d);
1707       break;
1708
1709     case AOP_STR:
1710       aop->coff = offset;
1711       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1712         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1713       break;
1714
1715     case AOP_ACC:
1716       accuse = TRUE;
1717       aop->coff = offset;
1718       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1719         break;
1720
1721       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1722         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1723       break;
1724
1725     default:
1726       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1727               "aopPut got unsupported aop->type");
1728       exit (1);
1729     }
1730
1731     return accuse;
1732 }
1733
1734
1735 #if 0
1736 /*-----------------------------------------------------------------*/
1737 /* pointToEnd :- points to the last byte of the operand            */
1738 /*-----------------------------------------------------------------*/
1739 static void
1740 pointToEnd (asmop * aop)
1741 {
1742   int count;
1743   if (!aop)
1744     return;
1745
1746   aop->coff = count = (aop->size - 1);
1747   switch (aop->type)
1748     {
1749     case AOP_R0:
1750     case AOP_R1:
1751       while (count--)
1752         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1753       break;
1754     case AOP_DPTR:
1755       while (count--)
1756         emitcode ("inc", "dptr");
1757       break;
1758     }
1759
1760 }
1761 #endif
1762
1763 /*-----------------------------------------------------------------*/
1764 /* reAdjustPreg - points a register back to where it should        */
1765 /*-----------------------------------------------------------------*/
1766 static void
1767 reAdjustPreg (asmop * aop)
1768 {
1769   if ((aop->coff==0) || (aop->size <= 1))
1770     return;
1771
1772   switch (aop->type)
1773     {
1774     case AOP_R0:
1775     case AOP_R1:
1776       while (aop->coff--)
1777         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1778       break;
1779     case AOP_DPTR:
1780       while (aop->coff--)
1781         {
1782           emitcode ("lcall", "__decdptr");
1783         }
1784       break;
1785     }
1786   aop->coff = 0;
1787 }
1788
1789 /*-----------------------------------------------------------------*/
1790 /* opIsGptr: returns non-zero if the passed operand is             */
1791 /* a generic pointer type.                                         */
1792 /*-----------------------------------------------------------------*/
1793 static int
1794 opIsGptr (operand * op)
1795 {
1796   if (op && IS_GENPTR (operandType (op)) && (AOP_SIZE (op) == GPTRSIZE))
1797     {
1798       return 1;
1799     }
1800   return 0;
1801 }
1802
1803 /*-----------------------------------------------------------------*/
1804 /* getDataSize - get the operand data size                         */
1805 /*-----------------------------------------------------------------*/
1806 static int
1807 getDataSize (operand * op)
1808 {
1809   int size = AOP_SIZE (op);
1810
1811   if (size == GPTRSIZE)
1812     {
1813       sym_link *type = operandType (op);
1814       if (IS_GENPTR (type))
1815         {
1816           /* generic pointer; arithmetic operations
1817            * should ignore the high byte (pointer type).
1818            */
1819           size--;
1820         }
1821     }
1822   return size;
1823 }
1824
1825 /*-----------------------------------------------------------------*/
1826 /* outAcc - output Acc                                             */
1827 /*-----------------------------------------------------------------*/
1828 static void
1829 outAcc (operand * result)
1830 {
1831   int size, offset;
1832   size = getDataSize (result);
1833   if (size)
1834     {
1835       aopPut (result, "a", 0);
1836       size--;
1837       offset = 1;
1838       /* unsigned or positive */
1839       while (size--)
1840         {
1841           aopPut (result, zero, offset++);
1842         }
1843     }
1844 }
1845
1846 /*-----------------------------------------------------------------*/
1847 /* outBitC - output a bit C                                        */
1848 /*-----------------------------------------------------------------*/
1849 static void
1850 outBitC (operand * result)
1851 {
1852   /* if the result is bit */
1853   if (AOP_TYPE (result) == AOP_CRY)
1854     {
1855       if (!IS_OP_RUONLY (result))
1856         aopPut (result, "c", 0);
1857     }
1858   else if (AOP_TYPE (result) != AOP_DUMMY)
1859     {
1860       emitcode ("clr", "a");
1861       emitcode ("rlc", "a");
1862       outAcc (result);
1863     }
1864 }
1865
1866 /*-----------------------------------------------------------------*/
1867 /* toBoolean - emit code for orl a,operator(sizeop)                */
1868 /*-----------------------------------------------------------------*/
1869 static void
1870 toBoolean (operand * oper)
1871 {
1872   int size = AOP_SIZE (oper) - 1;
1873   int offset = 1;
1874   bool AccUsed = FALSE;
1875   bool pushedB;
1876
1877   while (!AccUsed && size--)
1878     {
1879       AccUsed |= aopGetUsesAcc(oper, offset++);
1880     }
1881
1882   size = AOP_SIZE (oper) - 1;
1883   offset = 1;
1884   MOVA (aopGet (oper, 0, FALSE, FALSE));
1885   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1886     {
1887       pushedB = pushB ();
1888       emitcode("mov", "b,a");
1889       while (--size)
1890         {
1891           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1892           emitcode ("orl", "b,a");
1893         }
1894       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1895       emitcode ("orl", "a,b");
1896       popB (pushedB);
1897     }
1898   else
1899     {
1900       while (size--)
1901         {
1902           emitcode ("orl", "a,%s",
1903                     aopGet (oper, offset++, FALSE, FALSE));
1904         }
1905     }
1906 }
1907
1908 /*-----------------------------------------------------------------*/
1909 /* toCarry - make boolean and move into carry                      */
1910 /*-----------------------------------------------------------------*/
1911 static void
1912 toCarry (operand * oper)
1913 {
1914   /* if the operand is a literal then
1915      we know what the value is */
1916   if (AOP_TYPE (oper) == AOP_LIT)
1917     {
1918       if ((int) operandLitValue (oper))
1919         SETC;
1920       else
1921         CLRC;
1922     }
1923   else if (AOP_TYPE (oper) == AOP_CRY)
1924     {
1925       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1926     }
1927   else
1928     {
1929       /* or the operand into a */
1930       toBoolean (oper);
1931       /* set C, if a >= 1 */
1932       emitcode ("add", "a,#0xff");
1933     }
1934 }
1935
1936 /*-----------------------------------------------------------------*/
1937 /* assignBit - assign operand to bit operand                       */
1938 /*-----------------------------------------------------------------*/
1939 static void
1940 assignBit (operand * result, operand * right)
1941 {
1942   /* if the right side is a literal then
1943      we know what the value is */
1944   if (AOP_TYPE (right) == AOP_LIT)
1945     {
1946       if ((int) operandLitValue (right))
1947         aopPut (result, one, 0);
1948       else
1949         aopPut (result, zero, 0);
1950     }
1951   else
1952     {
1953       toCarry (right);
1954       aopPut (result, "c", 0);
1955     }
1956 }
1957
1958
1959 /*-------------------------------------------------------------------*/
1960 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1961 /*-------------------------------------------------------------------*/
1962 static char *
1963 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1964 {
1965   char * l;
1966
1967   if (aopGetUsesAcc (oper, offset))
1968     {
1969       emitcode("mov", "b,a");
1970       MOVA (aopGet (oper, offset, bit16, dname));
1971       emitcode("xch", "a,b");
1972       aopPut (oper, "a", offset);
1973       emitcode("xch", "a,b");
1974       l = "b";
1975     }
1976   else
1977     {
1978       l = aopGet (oper, offset, bit16, dname);
1979       emitcode("xch", "a,%s", l);
1980     }
1981   return l;
1982 }
1983
1984
1985 /*-----------------------------------------------------------------*/
1986 /* genNot - generate code for ! operation                          */
1987 /*-----------------------------------------------------------------*/
1988 static void
1989 genNot (iCode * ic)
1990 {
1991   symbol *tlbl;
1992
1993   D (emitcode (";", "genNot"));
1994
1995   /* assign asmOps to operand & result */
1996   aopOp (IC_LEFT (ic), ic, FALSE);
1997   aopOp (IC_RESULT (ic), ic, TRUE);
1998
1999   /* if in bit space then a special case */
2000   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2001     {
2002       /* if left==result then cpl bit */
2003       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2004         {
2005           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2006         }
2007       else
2008         {
2009           toCarry (IC_LEFT (ic));
2010           emitcode ("cpl", "c");
2011           outBitC (IC_RESULT (ic));
2012         }
2013       goto release;
2014     }
2015
2016   toBoolean (IC_LEFT (ic));
2017
2018   /* set C, if a == 0 */
2019   tlbl = newiTempLabel (NULL);
2020   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2021   emitLabel (tlbl);
2022   outBitC (IC_RESULT (ic));
2023
2024 release:
2025   /* release the aops */
2026   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2027   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2028 }
2029
2030
2031 /*-----------------------------------------------------------------*/
2032 /* genCpl - generate code for complement                           */
2033 /*-----------------------------------------------------------------*/
2034 static void
2035 genCpl (iCode * ic)
2036 {
2037   int offset = 0;
2038   int size;
2039   symbol *tlbl;
2040   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2041
2042   D(emitcode (";", "genCpl"));
2043
2044   /* assign asmOps to operand & result */
2045   aopOp (IC_LEFT (ic), ic, FALSE);
2046   aopOp (IC_RESULT (ic), ic, TRUE);
2047
2048   /* special case if in bit space */
2049   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2050     {
2051       char *l;
2052
2053       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2054           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2055         {
2056           /* promotion rules are responsible for this strange result:
2057              bit -> int -> ~int -> bit
2058              uchar -> int -> ~int -> bit
2059           */
2060           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2061           goto release;
2062         }
2063
2064       tlbl=newiTempLabel(NULL);
2065       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2066       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2067           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2068           IS_AOP_PREG (IC_LEFT (ic)))
2069         {
2070           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2071         }
2072       else
2073         {
2074           MOVA (l);
2075           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2076         }
2077       emitLabel (tlbl);
2078       outBitC (IC_RESULT(ic));
2079       goto release;
2080     }
2081
2082   size = AOP_SIZE (IC_RESULT (ic));
2083   while (size--)
2084     {
2085       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2086       MOVA (l);
2087       emitcode ("cpl", "a");
2088       aopPut (IC_RESULT (ic), "a", offset++);
2089     }
2090
2091
2092 release:
2093   /* release the aops */
2094   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2095   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2096 }
2097
2098 /*-----------------------------------------------------------------*/
2099 /* genUminusFloat - unary minus for floating points                */
2100 /*-----------------------------------------------------------------*/
2101 static void
2102 genUminusFloat (operand * op, operand * result)
2103 {
2104   int size, offset = 0;
2105   char *l;
2106
2107   D (emitcode (";", "genUminusFloat"));
2108
2109   /* for this we just copy and then flip the bit */
2110
2111   size = AOP_SIZE (op) - 1;
2112
2113   while (size--)
2114     {
2115       aopPut (result,
2116               aopGet (op, offset, FALSE, FALSE),
2117               offset);
2118       offset++;
2119     }
2120
2121   l = aopGet (op, offset, FALSE, FALSE);
2122   MOVA (l);
2123
2124   emitcode ("cpl", "acc.7");
2125   aopPut (result, "a", offset);
2126 }
2127
2128 /*-----------------------------------------------------------------*/
2129 /* genUminus - unary minus code generation                         */
2130 /*-----------------------------------------------------------------*/
2131 static void
2132 genUminus (iCode * ic)
2133 {
2134   int offset, size;
2135   sym_link *optype;
2136
2137   D (emitcode (";", "genUminus"));
2138
2139   /* assign asmops */
2140   aopOp (IC_LEFT (ic), ic, FALSE);
2141   aopOp (IC_RESULT (ic), ic, TRUE);
2142
2143   /* if both in bit space then special
2144      case */
2145   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2146       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2147     {
2148
2149       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2150       emitcode ("cpl", "c");
2151       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2152       goto release;
2153     }
2154
2155   optype = operandType (IC_LEFT (ic));
2156
2157   /* if float then do float stuff */
2158   if (IS_FLOAT (optype))
2159     {
2160       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2161       goto release;
2162     }
2163
2164   /* otherwise subtract from zero */
2165   size = AOP_SIZE (IC_LEFT (ic));
2166   offset = 0;
2167   while (size--)
2168     {
2169       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2170       if (!strcmp (l, "a"))
2171         {
2172           if (offset == 0)
2173             SETC;
2174           emitcode ("cpl", "a");
2175           emitcode ("addc", "a,#0x00");
2176         }
2177       else
2178         {
2179           if (offset == 0)
2180             CLRC;
2181           emitcode ("clr", "a");
2182           emitcode ("subb", "a,%s", l);
2183         }
2184       aopPut (IC_RESULT (ic), "a", offset++);
2185     }
2186
2187   /* if any remaining bytes in the result */
2188   /* we just need to propagate the sign   */
2189   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2190     {
2191       emitcode ("rlc", "a");
2192       emitcode ("subb", "a,acc");
2193       while (size--)
2194         aopPut (IC_RESULT (ic), "a", offset++);
2195     }
2196
2197 release:
2198   /* release the aops */
2199   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2200   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2201 }
2202
2203 /*-----------------------------------------------------------------*/
2204 /* saveRegisters - will look for a call and save the registers     */
2205 /*-----------------------------------------------------------------*/
2206 static void
2207 saveRegisters (iCode * lic)
2208 {
2209   int i;
2210   iCode *ic;
2211   bitVect *rsave;
2212
2213   /* look for call */
2214   for (ic = lic; ic; ic = ic->next)
2215     if (ic->op == CALL || ic->op == PCALL)
2216       break;
2217
2218   if (!ic)
2219     {
2220       fprintf (stderr, "found parameter push with no function call\n");
2221       return;
2222     }
2223
2224   /* if the registers have been saved already or don't need to be then
2225      do nothing */
2226   if (ic->regsSaved)
2227     return;
2228   if (IS_SYMOP(IC_LEFT(ic)) &&
2229       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2230        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2231     return;
2232
2233   /* save the registers in use at this time but skip the
2234      ones for the result */
2235   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2236                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2237
2238   ic->regsSaved = 1;
2239   if (options.useXstack)
2240     {
2241       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2242       int nBits = bitVectnBitsOn (rsavebits);
2243       int count = bitVectnBitsOn (rsave);
2244
2245       if (nBits != 0)
2246         {
2247           count = count - nBits + 1;
2248           /* remove all but the first bits as they are pushed all at once */
2249           rsave = bitVectCplAnd (rsave, rsavebits);
2250           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2251         }
2252       freeBitVect (rsavebits);
2253
2254       if (count == 1)
2255         {
2256           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2257           if (reg->type == REG_BIT)
2258             {
2259               emitcode ("mov", "a,%s", reg->base);
2260             }
2261           else
2262             {
2263               emitcode ("mov", "a,%s", reg->name);
2264             }
2265           emitcode ("mov", "r0,%s", spname);
2266           emitcode ("inc", "%s", spname);// allocate before use
2267           emitcode ("movx", "@r0,a");
2268           if (bitVectBitValue (rsave, R0_IDX))
2269             emitcode ("mov", "r0,a");
2270         }
2271       else if (count != 0)
2272         {
2273           if (bitVectBitValue (rsave, R0_IDX))
2274             {
2275               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2276             }
2277           emitcode ("mov", "r0,%s", spname);
2278           MOVA ("r0");
2279           emitcode ("add", "a,#0x%02x", count);
2280           emitcode ("mov", "%s,a", spname);
2281           for (i = 0; i < mcs51_nRegs; i++)
2282             {
2283               if (bitVectBitValue (rsave, i))
2284                 {
2285                   regs * reg = REG_WITH_INDEX (i);
2286                   if (i == R0_IDX)
2287                     {
2288                       emitcode ("pop", "acc");
2289                       emitcode ("push", "acc");
2290                     }
2291                   else if (reg->type == REG_BIT)
2292                     {
2293                       emitcode ("mov", "a,%s", reg->base);
2294                     }
2295                   else
2296                     {
2297                       emitcode ("mov", "a,%s", reg->name);
2298                     }
2299                   emitcode ("movx", "@r0,a");
2300                   if (--count)
2301                     {
2302                       emitcode ("inc", "r0");
2303                     }
2304                 }
2305             }
2306           if (bitVectBitValue (rsave, R0_IDX))
2307             {
2308               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2309             }
2310         }
2311     }
2312   else
2313     {
2314       bool bits_pushed = FALSE;
2315       for (i = 0; i < mcs51_nRegs; i++)
2316         {
2317           if (bitVectBitValue (rsave, i))
2318             {
2319               bits_pushed = pushReg (i, bits_pushed);
2320             }
2321         }
2322     }
2323   freeBitVect (rsave);
2324 }
2325
2326 /*-----------------------------------------------------------------*/
2327 /* unsaveRegisters - pop the pushed registers                      */
2328 /*-----------------------------------------------------------------*/
2329 static void
2330 unsaveRegisters (iCode * ic)
2331 {
2332   int i;
2333   bitVect *rsave;
2334
2335   /* restore the registers in use at this time but skip the
2336      ones for the result */
2337   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2338                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2339
2340   if (options.useXstack)
2341     {
2342       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2343       int nBits = bitVectnBitsOn (rsavebits);
2344       int count = bitVectnBitsOn (rsave);
2345
2346       if (nBits != 0)
2347         {
2348           count = count - nBits + 1;
2349           /* remove all but the first bits as they are popped all at once */
2350           rsave = bitVectCplAnd (rsave, rsavebits);
2351           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2352         }
2353       freeBitVect (rsavebits);
2354
2355       if (count == 1)
2356         {
2357           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2358           emitcode ("mov", "r0,%s", spname);
2359           emitcode ("dec", "r0");
2360           emitcode ("movx", "a,@r0");
2361           if (reg->type == REG_BIT)
2362             {
2363               emitcode ("mov", "%s,a", reg->base);
2364             }
2365           else
2366             {
2367               emitcode ("mov", "%s,a", reg->name);
2368             }
2369           emitcode ("dec", "%s", spname);
2370         }
2371       else if (count != 0)
2372         {
2373           emitcode ("mov", "r0,%s", spname);
2374           for (i = mcs51_nRegs; i >= 0; i--)
2375             {
2376               if (bitVectBitValue (rsave, i))
2377                 {
2378                   regs * reg = REG_WITH_INDEX (i);
2379                   emitcode ("dec", "r0");
2380                   emitcode ("movx", "a,@r0");
2381                   if (i == R0_IDX)
2382                     {
2383                       emitcode ("push", "acc");
2384                     }
2385                   else if (reg->type == REG_BIT)
2386                     {
2387                       emitcode ("mov", "%s,a", reg->base);
2388                     }
2389                   else
2390                     {
2391                       emitcode ("mov", "%s,a", reg->name);
2392                     }
2393                 }
2394             }
2395           emitcode ("mov", "%s,r0", spname);
2396           if (bitVectBitValue (rsave, R0_IDX))
2397             {
2398               emitcode ("pop", "ar0");
2399             }
2400         }
2401     }
2402   else
2403     {
2404       bool bits_popped = FALSE;
2405       for (i = mcs51_nRegs; i >= 0; i--)
2406         {
2407           if (bitVectBitValue (rsave, i))
2408             {
2409               bits_popped = popReg (i, bits_popped);
2410             }
2411         }
2412     }
2413   freeBitVect (rsave);
2414 }
2415
2416
2417 /*-----------------------------------------------------------------*/
2418 /* pushSide -                                                      */
2419 /*-----------------------------------------------------------------*/
2420 static void
2421 pushSide (operand * oper, int size, iCode * ic)
2422 {
2423   int offset = 0;
2424   int nPushed = _G.r0Pushed + _G.r1Pushed;
2425
2426   aopOp (oper, ic, FALSE);
2427
2428   if (nPushed != _G.r0Pushed + _G.r1Pushed)
2429     {
2430       while (offset < size)
2431         {
2432           char *l = aopGet (oper, offset, FALSE, TRUE);
2433           emitcode ("mov", "%s,%s", fReturn[offset++], l);
2434         }
2435       freeAsmop (oper, NULL, ic, TRUE);
2436       offset = 0;
2437       while (offset < size)
2438         {
2439           emitcode ("push", "%s", fReturn[offset++]);
2440         }
2441       return;
2442     }
2443
2444   while (size--)
2445     {
2446       char *l = aopGet (oper, offset++, FALSE, TRUE);
2447       if (AOP_TYPE (oper) != AOP_REG &&
2448           AOP_TYPE (oper) != AOP_DIR &&
2449           strcmp (l, "a"))
2450         {
2451           MOVA (l);
2452           emitcode ("push", "acc");
2453         }
2454       else
2455         {
2456           emitcode ("push", "%s", l);
2457         }
2458     }
2459
2460   freeAsmop (oper, NULL, ic, TRUE);
2461 }
2462
2463 /*-----------------------------------------------------------------*/
2464 /* assignResultValue - also indicates if acc is in use afterwards  */
2465 /*-----------------------------------------------------------------*/
2466 static bool
2467 assignResultValue (operand * oper, operand * func)
2468 {
2469   int offset = 0;
2470   int size = AOP_SIZE (oper);
2471   bool accuse = FALSE;
2472   bool pushedA = FALSE;
2473
2474   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2475     {
2476       outBitC (oper);
2477       return FALSE;
2478     }
2479
2480   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2481     {
2482       emitcode ("push", "acc");
2483       pushedA = TRUE;
2484     }
2485   while (size--)
2486     {
2487       if ((offset == 3) && pushedA)
2488         emitcode ("pop", "acc");
2489       accuse |= aopPut (oper, fReturn[offset], offset);
2490       offset++;
2491     }
2492   return accuse;
2493 }
2494
2495
2496 /*-----------------------------------------------------------------*/
2497 /* genXpush - pushes onto the external stack                       */
2498 /*-----------------------------------------------------------------*/
2499 static void
2500 genXpush (iCode * ic)
2501 {
2502   asmop *aop = newAsmop (0);
2503   regs *r;
2504   int size, offset = 0;
2505
2506   D (emitcode (";", "genXpush"));
2507
2508   aopOp (IC_LEFT (ic), ic, FALSE);
2509   r = getFreePtr (ic, &aop, FALSE);
2510
2511   size = AOP_SIZE (IC_LEFT (ic));
2512
2513   if (size == 1)
2514     {
2515       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2516       emitcode ("mov", "%s,%s", r->name, spname);
2517       emitcode ("inc", "%s", spname); // allocate space first
2518       emitcode ("movx", "@%s,a", r->name);
2519     }
2520   else
2521     {
2522       // allocate space first
2523       emitcode ("mov", "%s,%s", r->name, spname);
2524       MOVA (r->name);
2525       emitcode ("add", "a,#0x%02x", size);
2526       emitcode ("mov", "%s,a", spname);
2527
2528       while (size--)
2529         {
2530           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2531           emitcode ("movx", "@%s,a", r->name);
2532           emitcode ("inc", "%s", r->name);
2533         }
2534     }
2535
2536   freeAsmop (NULL, aop, ic, TRUE);
2537   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2538 }
2539
2540 /*-----------------------------------------------------------------*/
2541 /* genIpush - generate code for pushing this gets a little complex */
2542 /*-----------------------------------------------------------------*/
2543 static void
2544 genIpush (iCode * ic)
2545 {
2546   int size, offset = 0;
2547   char *l;
2548   char *prev = "";
2549
2550   D (emitcode (";", "genIpush"));
2551
2552   /* if this is not a parm push : ie. it is spill push
2553      and spill push is always done on the local stack */
2554   if (!ic->parmPush)
2555     {
2556
2557       /* and the item is spilt then do nothing */
2558       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2559         return;
2560
2561       aopOp (IC_LEFT (ic), ic, FALSE);
2562       size = AOP_SIZE (IC_LEFT (ic));
2563       /* push it on the stack */
2564       while (size--)
2565         {
2566           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2567           if (*l == '#')
2568             {
2569               MOVA (l);
2570               l = "acc";
2571             }
2572           emitcode ("push", "%s", l);
2573         }
2574       return;
2575     }
2576
2577   /* this is a parameter push: in this case we call
2578      the routine to find the call and save those
2579      registers that need to be saved */
2580   saveRegisters (ic);
2581
2582   /* if use external stack then call the external
2583      stack pushing routine */
2584   if (options.useXstack)
2585     {
2586       genXpush (ic);
2587       return;
2588     }
2589
2590   /* then do the push */
2591   aopOp (IC_LEFT (ic), ic, FALSE);
2592
2593   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2594   size = AOP_SIZE (IC_LEFT (ic));
2595
2596   while (size--)
2597     {
2598       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2599       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2600           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2601         {
2602           if (strcmp (l, prev) || *l == '@')
2603             MOVA (l);
2604           emitcode ("push", "acc");
2605         }
2606       else
2607         {
2608           emitcode ("push", "%s", l);
2609         }
2610       prev = l;
2611     }
2612
2613   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2614 }
2615
2616 /*-----------------------------------------------------------------*/
2617 /* genIpop - recover the registers: can happen only for spilling   */
2618 /*-----------------------------------------------------------------*/
2619 static void
2620 genIpop (iCode * ic)
2621 {
2622   int size, offset;
2623
2624   D (emitcode (";", "genIpop"));
2625
2626   /* if the temp was not pushed then */
2627   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2628     return;
2629
2630   aopOp (IC_LEFT (ic), ic, FALSE);
2631   size = AOP_SIZE (IC_LEFT (ic));
2632   offset = (size - 1);
2633   while (size--)
2634     {
2635       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2636                                      FALSE, TRUE));
2637     }
2638
2639   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2640 }
2641
2642 /*-----------------------------------------------------------------*/
2643 /* popForBranch - recover the spilt registers for a branch         */
2644 /*-----------------------------------------------------------------*/
2645 static void
2646 popForBranch (iCode * ic, bool markGenerated)
2647 {
2648   while (ic && ic->op == IPOP)
2649     {
2650       genIpop (ic);
2651       if (markGenerated)
2652         ic->generated = 1;    /* mark the icode as generated */
2653       ic = ic->next;
2654     }
2655 }
2656
2657 /*-----------------------------------------------------------------*/
2658 /* saveRBank - saves an entire register bank on the stack          */
2659 /*-----------------------------------------------------------------*/
2660 static void
2661 saveRBank (int bank, iCode * ic, bool pushPsw)
2662 {
2663   int i;
2664   int count = 8 + (pushPsw ? 1 : 0);
2665   asmop *aop = NULL;
2666   regs *r = NULL;
2667
2668   if (options.useXstack)
2669     {
2670       if (!ic)
2671         {
2672           /* Assume r0 is available for use. */
2673           r = REG_WITH_INDEX (R0_IDX);
2674         }
2675       else
2676         {
2677           aop = newAsmop (0);
2678           r = getFreePtr (ic, &aop, FALSE);
2679         }
2680       // allocate space first
2681       emitcode ("mov", "%s,%s", r->name, spname);
2682       MOVA (r->name);
2683       emitcode ("add", "a,#0x%02x", count);
2684       emitcode ("mov", "%s,a", spname);
2685     }
2686
2687   for (i = 0; i < 8; i++)
2688     {
2689       if (options.useXstack)
2690         {
2691           emitcode ("mov", "a,(%s+%d)",
2692                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2693           emitcode ("movx", "@%s,a", r->name);
2694           if (--count)
2695             emitcode ("inc", "%s", r->name);
2696         }
2697       else
2698         emitcode ("push", "(%s+%d)",
2699                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2700     }
2701
2702   if (pushPsw)
2703     {
2704       if (options.useXstack)
2705         {
2706           emitcode ("mov", "a,psw");
2707           emitcode ("movx", "@%s,a", r->name);
2708         }
2709       else
2710         {
2711           emitcode ("push", "psw");
2712         }
2713
2714       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2715     }
2716
2717   if (aop)
2718     {
2719       freeAsmop (NULL, aop, ic, TRUE);
2720     }
2721
2722   if (ic)
2723     {
2724       ic->bankSaved = 1;
2725     }
2726 }
2727
2728 /*-----------------------------------------------------------------*/
2729 /* unsaveRBank - restores the register bank from stack             */
2730 /*-----------------------------------------------------------------*/
2731 static void
2732 unsaveRBank (int bank, iCode * ic, bool popPsw)
2733 {
2734   int i;
2735   asmop *aop = NULL;
2736   regs *r = NULL;
2737
2738   if (options.useXstack)
2739     {
2740       if (!ic)
2741         {
2742           /* Assume r0 is available for use. */
2743           r = REG_WITH_INDEX (R0_IDX);;
2744         }
2745       else
2746         {
2747           aop = newAsmop (0);
2748           r = getFreePtr (ic, &aop, FALSE);
2749         }
2750       emitcode ("mov", "%s,%s", r->name, spname);
2751     }
2752
2753   if (popPsw)
2754     {
2755       if (options.useXstack)
2756         {
2757           emitcode ("dec", "%s", r->name);
2758           emitcode ("movx", "a,@%s", r->name);
2759           emitcode ("mov", "psw,a");
2760         }
2761       else
2762         {
2763           emitcode ("pop", "psw");
2764         }
2765     }
2766
2767   for (i = 7; i >= 0; i--)
2768     {
2769       if (options.useXstack)
2770         {
2771           emitcode ("dec", "%s", r->name);
2772           emitcode ("movx", "a,@%s", r->name);
2773           emitcode ("mov", "(%s+%d),a",
2774                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2775         }
2776       else
2777         {
2778           emitcode ("pop", "(%s+%d)",
2779                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2780         }
2781     }
2782
2783   if (options.useXstack)
2784     {
2785       emitcode ("mov", "%s,%s", spname, r->name);
2786     }
2787
2788   if (aop)
2789     {
2790       freeAsmop (NULL, aop, ic, TRUE);
2791     }
2792 }
2793
2794 /*-----------------------------------------------------------------*/
2795 /* genSend - gen code for SEND                                     */
2796 /*-----------------------------------------------------------------*/
2797 static void genSend(set *sendSet)
2798 {
2799   iCode *sic;
2800   int bit_count = 0;
2801
2802   /* first we do all bit parameters */
2803   for (sic = setFirstItem (sendSet); sic;
2804        sic = setNextItem (sendSet))
2805     {
2806       if (sic->argreg > 12)
2807         {
2808           int bit = sic->argreg-13;
2809
2810           aopOp (IC_LEFT (sic), sic, FALSE);
2811
2812           /* if left is a literal then
2813              we know what the value is */
2814           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2815             {
2816               if (((int) operandLitValue (IC_LEFT (sic))))
2817                   emitcode ("setb", "b[%d]", bit);
2818               else
2819                   emitcode ("clr", "b[%d]", bit);
2820             }
2821           else
2822             {
2823               /* we need to or */
2824               toCarry (IC_LEFT (sic));
2825               emitcode ("mov", "b[%d],c", bit);
2826             }
2827           bit_count++;
2828           BitBankUsed = 1;
2829
2830           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2831         }
2832     }
2833
2834   if (bit_count)
2835     {
2836       saveRegisters (setFirstItem (sendSet));
2837       emitcode ("mov", "bits,b");
2838     }
2839
2840   /* then we do all other parameters */
2841   for (sic = setFirstItem (sendSet); sic;
2842        sic = setNextItem (sendSet))
2843     {
2844       if (sic->argreg <= 12)
2845         {
2846           int size, offset = 0;
2847           aopOp (IC_LEFT (sic), sic, FALSE);
2848           size = AOP_SIZE (IC_LEFT (sic));
2849
2850           if (sic->argreg == 1)
2851             {
2852               while (size--)
2853                 {
2854                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2855                   if (strcmp (l, fReturn[offset]))
2856                     {
2857                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2858                     }
2859                   offset++;
2860                 }
2861             }
2862           else
2863             {
2864               while (size--)
2865                 {
2866                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2867                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2868                   offset++;
2869                 }
2870             }
2871           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2872         }
2873     }
2874 }
2875
2876 /*-----------------------------------------------------------------*/
2877 /* selectRegBank - emit code to select the register bank           */
2878 /*-----------------------------------------------------------------*/
2879 static void
2880 selectRegBank (short bank, bool keepFlags)
2881 {
2882   /* if f.e. result is in carry */
2883   if (keepFlags)
2884     {
2885       emitcode ("anl", "psw,#0xE7");
2886       if (bank)
2887         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2888     }
2889   else
2890     {
2891       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2892     }
2893 }
2894
2895 /*-----------------------------------------------------------------*/
2896 /* genCall - generates a call statement                            */
2897 /*-----------------------------------------------------------------*/
2898 static void
2899 genCall (iCode * ic)
2900 {
2901   sym_link *dtype;
2902   sym_link *etype;
2903 //  bool restoreBank = FALSE;
2904   bool swapBanks = FALSE;
2905   bool accuse = FALSE;
2906   bool accPushed = FALSE;
2907   bool resultInF0 = FALSE;
2908   bool assignResultGenerated = FALSE;
2909
2910   D (emitcode (";", "genCall"));
2911
2912   dtype = operandType (IC_LEFT (ic));
2913   etype = getSpec(dtype);
2914   /* if send set is not empty then assign */
2915   if (_G.sendSet)
2916     {
2917         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2918             genSend(reverseSet(_G.sendSet));
2919         } else {
2920             genSend(_G.sendSet);
2921         }
2922       _G.sendSet = NULL;
2923     }
2924
2925   /* if we are calling a not _naked function that is not using
2926      the same register bank then we need to save the
2927      destination registers on the stack */
2928   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2929       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2930        !IFFUNC_ISISR (dtype))
2931     {
2932       swapBanks = TRUE;
2933     }
2934
2935   /* if caller saves & we have not saved then */
2936   if (!ic->regsSaved)
2937       saveRegisters (ic);
2938
2939   if (swapBanks)
2940     {
2941       emitcode ("mov", "psw,#0x%02x", ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2942     }
2943
2944   /* make the call */
2945   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2946     {
2947       if (IFFUNC_CALLEESAVES(dtype))
2948         {
2949           werror (E_BANKED_WITH_CALLEESAVES);
2950         }
2951       else
2952         {
2953           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2954                      OP_SYMBOL (IC_LEFT (ic))->rname :
2955                      OP_SYMBOL (IC_LEFT (ic))->name);
2956
2957           emitcode ("mov", "r0,#%s", l);
2958           emitcode ("mov", "r1,#(%s >> 8)", l);
2959           emitcode ("mov", "r2,#(%s >> 16)", l);
2960           emitcode ("lcall", "__sdcc_banked_call");
2961         }
2962     }
2963   else
2964     {
2965       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2966                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2967                                 OP_SYMBOL (IC_LEFT (ic))->name));
2968     }
2969
2970   if (swapBanks)
2971     {
2972       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2973     }
2974
2975   /* if we need assign a result value */
2976   if ((IS_ITEMP (IC_RESULT (ic)) &&
2977        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2978        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2979         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2980         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2981       IS_TRUE_SYMOP (IC_RESULT (ic)))
2982     {
2983
2984       _G.accInUse++;
2985       aopOp (IC_RESULT (ic), ic, FALSE);
2986       _G.accInUse--;
2987
2988       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2989       assignResultGenerated = TRUE;
2990
2991       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2992     }
2993
2994   /* adjust the stack for parameters if required */
2995   if (ic->parmBytes)
2996     {
2997       int i;
2998       if (ic->parmBytes > 3)
2999         {
3000           if (accuse)
3001             {
3002               emitcode ("push", "acc");
3003               accPushed = TRUE;
3004             }
3005           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3006               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3007               !assignResultGenerated)
3008             {
3009               emitcode ("mov", "F0,c");
3010               resultInF0 = TRUE;
3011             }
3012
3013           emitcode ("mov", "a,%s", spname);
3014           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3015           emitcode ("mov", "%s,a", spname);
3016
3017           /* unsaveRegisters from xstack needs acc, but */
3018           /* unsaveRegisters from stack needs this popped */
3019           if (accPushed && !options.useXstack)
3020             {
3021               emitcode ("pop", "acc");
3022               accPushed = FALSE;
3023             }
3024         }
3025       else
3026         for (i = 0; i < ic->parmBytes; i++)
3027           emitcode ("dec", "%s", spname);
3028     }
3029
3030   /* if we had saved some registers then unsave them */
3031   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3032     {
3033       if (accuse && !accPushed && options.useXstack)
3034         {
3035           /* xstack needs acc, but doesn't touch normal stack */
3036           emitcode ("push", "acc");
3037           accPushed = TRUE;
3038         }
3039       unsaveRegisters (ic);
3040     }
3041
3042 //  /* if register bank was saved then pop them */
3043 //  if (restoreBank)
3044 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3045
3046   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3047     {
3048       if (resultInF0)
3049           emitcode ("mov", "c,F0");
3050
3051       aopOp (IC_RESULT (ic), ic, FALSE);
3052       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3053       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3054     }
3055
3056   if (accPushed)
3057     emitcode ("pop", "acc");
3058 }
3059
3060 /*-----------------------------------------------------------------*/
3061 /* genPcall - generates a call by pointer statement                */
3062 /*-----------------------------------------------------------------*/
3063 static void
3064 genPcall (iCode * ic)
3065 {
3066   sym_link *dtype;
3067   sym_link *etype;
3068   symbol *rlbl = newiTempLabel (NULL);
3069 //  bool restoreBank=FALSE;
3070   bool swapBanks = FALSE;
3071   bool resultInF0 = FALSE;
3072
3073   D (emitcode (";", "genPcall"));
3074
3075   dtype = operandType (IC_LEFT (ic))->next;
3076   etype = getSpec(dtype);
3077   /* if caller saves & we have not saved then */
3078   if (!ic->regsSaved)
3079     saveRegisters (ic);
3080
3081   /* if we are calling a not _naked function that is not using
3082      the same register bank then we need to save the
3083      destination registers on the stack */
3084   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3085       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3086       !IFFUNC_ISISR (dtype))
3087     {
3088 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3089 //    restoreBank=TRUE;
3090       swapBanks = TRUE;
3091       // need caution message to user here
3092     }
3093
3094   if (IS_LITERAL (etype))
3095     {
3096       /* if send set is not empty then assign */
3097       if (_G.sendSet)
3098         {
3099           genSend(reverseSet(_G.sendSet));
3100           _G.sendSet = NULL;
3101         }
3102
3103       if (swapBanks)
3104         {
3105           emitcode ("mov", "psw,#0x%02x",
3106            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3107         }
3108
3109       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3110         {
3111           if (IFFUNC_CALLEESAVES (dtype))
3112             {
3113               werror (E_BANKED_WITH_CALLEESAVES);
3114             }
3115           else
3116             {
3117               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3118
3119               emitcode ("mov", "r0,#%s", l);
3120               emitcode ("mov", "r1,#(%s >> 8)", l);
3121               emitcode ("mov", "r2,#(%s >> 16)", l);
3122               emitcode ("lcall", "__sdcc_banked_call");
3123             }
3124         }
3125       else
3126         {
3127           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3128         }
3129     }
3130   else
3131     {
3132       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3133         {
3134           if (IFFUNC_CALLEESAVES (dtype))
3135             {
3136               werror (E_BANKED_WITH_CALLEESAVES);
3137             }
3138           else
3139             {
3140               aopOp (IC_LEFT (ic), ic, FALSE);
3141
3142               if (!swapBanks)
3143                 {
3144                   /* what if aopGet needs r0 or r1 ??? */
3145                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3146                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3147                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3148                 }
3149               else
3150                 {
3151                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3152                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3153                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3154                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3155                 }
3156
3157               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3158
3159               /* if send set is not empty then assign */
3160               if (_G.sendSet)
3161                 {
3162                   genSend(reverseSet(_G.sendSet));
3163                   _G.sendSet = NULL;
3164                 }
3165
3166               if (swapBanks)
3167                 {
3168                   emitcode ("mov", "psw,#0x%02x",
3169                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3170                 }
3171
3172               /* make the call */
3173               emitcode ("lcall", "__sdcc_banked_call");
3174             }
3175         }
3176       else if (_G.sendSet)
3177         {
3178           /* push the return address on to the stack */
3179           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3180           emitcode ("push", "acc");
3181           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3182           emitcode ("push", "acc");
3183
3184           /* now push the function address */
3185           pushSide (IC_LEFT (ic), FPTRSIZE, ic);
3186
3187           /* if send set is not empty then assign */
3188           if (_G.sendSet)
3189             {
3190               genSend(reverseSet(_G.sendSet));
3191               _G.sendSet = NULL;
3192             }
3193
3194           if (swapBanks)
3195             {
3196               emitcode ("mov", "psw,#0x%02x",
3197                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3198             }
3199
3200           /* make the call */
3201           emitcode ("ret", "");
3202           emitLabel (rlbl);
3203         }
3204       else /* the send set is empty */
3205         {
3206           char *l;
3207           /* now get the calling address into dptr */
3208           aopOp (IC_LEFT (ic), ic, FALSE);
3209
3210           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3211           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3212             {
3213               emitcode ("mov", "r0,%s", l);
3214               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3215               emitcode ("mov", "dph,%s", l);
3216               emitcode ("mov", "dpl,r0");
3217             }
3218           else
3219             {
3220               emitcode ("mov", "dpl,%s", l);
3221               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3222               emitcode ("mov", "dph,%s", l);
3223             }
3224
3225           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3226
3227           if (swapBanks)
3228             {
3229               emitcode ("mov", "psw,#0x%02x",
3230                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3231             }
3232
3233           /* make the call */
3234           emitcode ("lcall", "__sdcc_call_dptr");
3235         }
3236     }
3237   if (swapBanks)
3238     {
3239       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3240     }
3241
3242   /* if we need assign a result value */
3243   if ((IS_ITEMP (IC_RESULT (ic)) &&
3244        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3245        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3246         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3247       IS_TRUE_SYMOP (IC_RESULT (ic)))
3248     {
3249
3250       _G.accInUse++;
3251       aopOp (IC_RESULT (ic), ic, FALSE);
3252       _G.accInUse--;
3253
3254       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3255
3256       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3257     }
3258
3259   /* adjust the stack for parameters if required */
3260   if (ic->parmBytes)
3261     {
3262       int i;
3263       if (ic->parmBytes > 3)
3264         {
3265           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3266               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3267             {
3268               emitcode ("mov", "F0,c");
3269               resultInF0 = TRUE;
3270             }
3271
3272           emitcode ("mov", "a,%s", spname);
3273           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3274           emitcode ("mov", "%s,a", spname);
3275         }
3276       else
3277         for (i = 0; i < ic->parmBytes; i++)
3278           emitcode ("dec", "%s", spname);
3279     }
3280
3281 //  /* if register bank was saved then unsave them */
3282 //  if (restoreBank)
3283 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3284
3285   /* if we had saved some registers then unsave them */
3286   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3287     unsaveRegisters (ic);
3288
3289   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3290     {
3291       if (resultInF0)
3292           emitcode ("mov", "c,F0");
3293
3294       aopOp (IC_RESULT (ic), ic, FALSE);
3295       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3296       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3297     }
3298 }
3299
3300 /*-----------------------------------------------------------------*/
3301 /* resultRemat - result  is rematerializable                       */
3302 /*-----------------------------------------------------------------*/
3303 static int
3304 resultRemat (iCode * ic)
3305 {
3306   if (SKIP_IC (ic) || ic->op == IFX)
3307     return 0;
3308
3309   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3310     {
3311       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3312       if (sym->remat && !POINTER_SET (ic))
3313         return 1;
3314     }
3315
3316   return 0;
3317 }
3318
3319 /*-----------------------------------------------------------------*/
3320 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3321 /*-----------------------------------------------------------------*/
3322 static int
3323 regsCmp(void *p1, void *p2)
3324 {
3325   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3326 }
3327
3328 static bool
3329 inExcludeList (char *s)
3330 {
3331   const char *p = setFirstItem(options.excludeRegsSet);
3332
3333   if (p == NULL || STRCASECMP(p, "none") == 0)
3334     return FALSE;
3335
3336
3337   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3338 }
3339
3340 /*-----------------------------------------------------------------*/
3341 /* genFunction - generated code for function entry                 */
3342 /*-----------------------------------------------------------------*/
3343 static void
3344 genFunction (iCode * ic)
3345 {
3346   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3347   sym_link *ftype;
3348   bool     switchedPSW = FALSE;
3349   int      calleesaves_saved_register = -1;
3350   int      stackAdjust = sym->stack;
3351   int      accIsFree = sym->recvSize < 4;
3352   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3353   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3354
3355   _G.nRegsSaved = 0;
3356   /* create the function header */
3357   emitcode (";", "-----------------------------------------");
3358   emitcode (";", " function %s", sym->name);
3359   emitcode (";", "-----------------------------------------");
3360
3361   emitcode ("", "%s:", sym->rname);
3362   lineCurr->isLabel = 1;
3363   ftype = operandType (IC_LEFT (ic));
3364   _G.currentFunc = sym;
3365
3366   if (IFFUNC_ISNAKED(ftype))
3367   {
3368       emitcode(";", "naked function: no prologue.");
3369       return;
3370   }
3371
3372   /* here we need to generate the equates for the
3373      register bank if required */
3374   if (FUNC_REGBANK (ftype) != rbank)
3375     {
3376       int i;
3377
3378       rbank = FUNC_REGBANK (ftype);
3379       for (i = 0; i < mcs51_nRegs; i++)
3380         {
3381           if (regs8051[i].type != REG_BIT)
3382             {
3383               if (strcmp (regs8051[i].base, "0") == 0)
3384                 emitcode ("", "%s = 0x%02x",
3385                           regs8051[i].dname,
3386                           8 * rbank + regs8051[i].offset);
3387               else
3388                 emitcode ("", "%s = %s + 0x%02x",
3389                           regs8051[i].dname,
3390                           regs8051[i].base,
3391                           8 * rbank + regs8051[i].offset);
3392             }
3393         }
3394     }
3395
3396   /* if this is an interrupt service routine then
3397      save acc, b, dpl, dph  */
3398   if (IFFUNC_ISISR (sym->type))
3399     {
3400       bitVect *rsavebits;
3401
3402       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3403       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3404         {
3405           emitcode ("push", "bits");
3406           BitBankUsed = 1;
3407         }
3408       freeBitVect (rsavebits);
3409
3410       if (!inExcludeList ("acc"))
3411         emitcode ("push", "acc");
3412       if (!inExcludeList ("b"))
3413         emitcode ("push", "b");
3414       if (!inExcludeList ("dpl"))
3415         emitcode ("push", "dpl");
3416       if (!inExcludeList ("dph"))
3417         emitcode ("push", "dph");
3418       /* if this isr has no bank i.e. is going to
3419          run with bank 0 , then we need to save more
3420          registers :-) */
3421       if (!FUNC_REGBANK (sym->type))
3422         {
3423           int i;
3424
3425           /* if this function does not call any other
3426              function then we can be economical and
3427              save only those registers that are used */
3428           if (!IFFUNC_HASFCALL(sym->type))
3429             {
3430               /* if any registers used */
3431               if (sym->regsUsed)
3432                 {
3433                   /* save the registers used */
3434                   for (i = 0; i < sym->regsUsed->size; i++)
3435                     {
3436                       if (bitVectBitValue (sym->regsUsed, i))
3437                         pushReg (i, TRUE);
3438                     }
3439                 }
3440             }
3441           else
3442             {
3443               /* this function has a function call. We cannot
3444                  determine register usage so we will have to push the
3445                  entire bank */
3446               saveRBank (0, ic, FALSE);
3447               if (options.parms_in_bank1)
3448                 {
3449                   for (i=0; i < 8 ; i++ )
3450                     {
3451                       emitcode ("push","%s",rb1regs[i]);
3452                     }
3453                 }
3454             }
3455         }
3456       else
3457         {
3458             /* This ISR uses a non-zero bank.
3459              *
3460              * We assume that the bank is available for our
3461              * exclusive use.
3462              *
3463              * However, if this ISR calls a function which uses some
3464              * other bank, we must save that bank entirely.
3465              */
3466             unsigned long banksToSave = 0;
3467
3468             if (IFFUNC_HASFCALL(sym->type))
3469             {
3470
3471 #define MAX_REGISTER_BANKS 4
3472
3473                 iCode *i;
3474                 int ix;
3475
3476                 for (i = ic; i; i = i->next)
3477                 {
3478                     if (i->op == ENDFUNCTION)
3479                     {
3480                         /* we got to the end OK. */
3481                         break;
3482                     }
3483
3484                     if (i->op == CALL)
3485                     {
3486                         sym_link *dtype;
3487
3488                         dtype = operandType (IC_LEFT(i));
3489                         if (dtype
3490                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3491                         {
3492                              /* Mark this bank for saving. */
3493                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3494                              {
3495                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3496                              }
3497                              else
3498                              {
3499                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3500                              }
3501
3502                              /* And note that we don't need to do it in
3503                               * genCall.
3504                               */
3505                              i->bankSaved = 1;
3506                         }
3507                     }
3508                     if (i->op == PCALL)
3509                     {
3510                         /* This is a mess; we have no idea what
3511                          * register bank the called function might
3512                          * use.
3513                          *
3514                          * The only thing I can think of to do is
3515                          * throw a warning and hope.
3516                          */
3517                         werror(W_FUNCPTR_IN_USING_ISR);
3518                     }
3519                 }
3520
3521                 if (banksToSave && options.useXstack)
3522                 {
3523                     /* Since we aren't passing it an ic,
3524                      * saveRBank will assume r0 is available to abuse.
3525                      *
3526                      * So switch to our (trashable) bank now, so
3527                      * the caller's R0 isn't trashed.
3528                      */
3529                     emitcode ("push", "psw");
3530                     emitcode ("mov", "psw,#0x%02x",
3531                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3532                     switchedPSW = TRUE;
3533                 }
3534
3535                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3536                 {
3537                      if (banksToSave & (1 << ix))
3538                      {
3539                          saveRBank(ix, NULL, FALSE);
3540                      }
3541                 }
3542             }
3543             // TODO: this needs a closer look
3544             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3545         }
3546
3547       /* Set the register bank to the desired value if nothing else */
3548       /* has done so yet. */
3549       if (!switchedPSW)
3550         {
3551           emitcode ("push", "psw");
3552           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3553         }
3554     }
3555   else
3556     {
3557       /* This is a non-ISR function. The caller has already switched register */
3558       /* banks, if necessary, so just handle the callee-saves option. */
3559
3560       /* if callee-save to be used for this function
3561          then save the registers being used in this function */
3562       if (IFFUNC_CALLEESAVES(sym->type))
3563         {
3564           int i;
3565
3566           /* if any registers used */
3567           if (sym->regsUsed)
3568             {
3569               bool bits_pushed = FALSE;
3570               /* save the registers used */
3571               for (i = 0; i < sym->regsUsed->size; i++)
3572                 {
3573                   if (bitVectBitValue (sym->regsUsed, i))
3574                     {
3575                       /* remember one saved register for later usage */
3576                       if (calleesaves_saved_register < 0)
3577                         calleesaves_saved_register = i;
3578                       bits_pushed = pushReg (i, bits_pushed);
3579                       _G.nRegsSaved++;
3580                     }
3581                 }
3582             }
3583         }
3584     }
3585
3586   if (fReentrant)
3587     {
3588       if (options.useXstack)
3589         {
3590           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3591             {
3592               emitcode ("mov", "r0,%s", spname);
3593               emitcode ("inc", "%s", spname);
3594               emitcode ("xch", "a,_bpx");
3595               emitcode ("movx", "@r0,a");
3596               emitcode ("inc", "r0");
3597               emitcode ("mov", "a,r0");
3598               emitcode ("xch", "a,_bpx");
3599             }
3600           if (sym->stack)
3601             {
3602               emitcode ("push", "_bp");     /* save the callers stack  */
3603               emitcode ("mov", "_bp,sp");
3604             }
3605         }
3606       else
3607         {
3608           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3609             {
3610               /* set up the stack */
3611               emitcode ("push", "_bp");     /* save the callers stack  */
3612               emitcode ("mov", "_bp,sp");
3613             }
3614         }
3615     }
3616
3617   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3618   /* before setting up the stack frame completely. */
3619   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3620     {
3621       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3622
3623       if (rsym->isitmp)
3624         {
3625           if (rsym && rsym->regType == REG_CND)
3626             rsym = NULL;
3627           if (rsym && (rsym->accuse || rsym->ruonly))
3628             rsym = NULL;
3629           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3630             rsym = rsym->usl.spillLoc;
3631         }
3632
3633       /* If the RECEIVE operand immediately spills to the first entry on the */
3634       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3635       /* rather than the usual @r0/r1 machinations. */
3636       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3637         {
3638           int ofs;
3639
3640           _G.current_iCode = ric;
3641           D(emitcode (";", "genReceive"));
3642           for (ofs=0; ofs < sym->recvSize; ofs++)
3643             {
3644               if (!strcmp (fReturn[ofs], "a"))
3645                 emitcode ("push", "acc");
3646               else
3647                 emitcode ("push", fReturn[ofs]);
3648             }
3649           stackAdjust -= sym->recvSize;
3650           if (stackAdjust<0)
3651             {
3652               assert (stackAdjust>=0);
3653               stackAdjust = 0;
3654             }
3655           _G.current_iCode = ic;
3656           ric->generated = 1;
3657           accIsFree = 1;
3658         }
3659       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3660       /* to free up the accumulator. */
3661       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3662         {
3663           int ofs;
3664
3665           _G.current_iCode = ric;
3666           D(emitcode (";", "genReceive"));
3667           for (ofs=0; ofs < sym->recvSize; ofs++)
3668             {
3669               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3670             }
3671           _G.current_iCode = ic;
3672           ric->generated = 1;
3673           accIsFree = 1;
3674         }
3675     }
3676
3677   /* adjust the stack for the function */
3678   if (stackAdjust)
3679     {
3680       int i = stackAdjust;
3681       if (i > 256)
3682         werror (W_STACK_OVERFLOW, sym->name);
3683
3684       if (i > 3 && accIsFree)
3685         {
3686           emitcode ("mov", "a,sp");
3687           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3688           emitcode ("mov", "sp,a");
3689         }
3690       else if (i > 5)
3691         {
3692           /* The accumulator is not free, so we will need another register */
3693           /* to clobber. No need to worry about a possible conflict with */
3694           /* the above early RECEIVE optimizations since they would have */
3695           /* freed the accumulator if they were generated. */
3696
3697           if (IFFUNC_CALLEESAVES(sym->type))
3698             {
3699               /* if it's a callee-saves function we need a saved register */
3700               if (calleesaves_saved_register >= 0)
3701                 {
3702                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3703                   emitcode ("mov", "a,sp");
3704                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3705                   emitcode ("mov", "sp,a");
3706                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3707                 }
3708               else
3709                 /* do it the hard way */
3710                 while (i--)
3711                   emitcode ("inc", "sp");
3712             }
3713           else
3714             {
3715               /* not callee-saves, we can clobber r0 */
3716               emitcode ("mov", "r0,a");
3717               emitcode ("mov", "a,sp");
3718               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3719               emitcode ("mov", "sp,a");
3720               emitcode ("mov", "a,r0");
3721             }
3722         }
3723       else
3724         while (i--)
3725           emitcode ("inc", "sp");
3726     }
3727
3728   if (sym->xstack)
3729     {
3730       char i = ((char) sym->xstack & 0xff);
3731
3732       if (i > 3 && accIsFree)
3733         {
3734           emitcode ("mov", "a,_spx");
3735           emitcode ("add", "a,#0x%02x", i & 0xff);
3736           emitcode ("mov", "_spx,a");
3737         }
3738       else if (i > 5)
3739         {
3740           emitcode ("push", "acc");
3741           emitcode ("mov", "a,_spx");
3742           emitcode ("add", "a,#0x%02x", i & 0xff);
3743           emitcode ("mov", "_spx,a");
3744           emitcode ("pop", "acc");
3745         }
3746       else
3747         {
3748           while (i--)
3749             emitcode ("inc", "_spx");
3750         }
3751     }
3752
3753   /* if critical function then turn interrupts off */
3754   if (IFFUNC_ISCRITICAL (ftype))
3755     {
3756       symbol *tlbl = newiTempLabel (NULL);
3757       emitcode ("setb", "c");
3758       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3759       emitcode ("clr", "c");
3760       emitLabel (tlbl);
3761       emitcode ("push", "psw"); /* save old ea via c in psw */
3762     }
3763 }
3764
3765 /*-----------------------------------------------------------------*/
3766 /* genEndFunction - generates epilogue for functions               */
3767 /*-----------------------------------------------------------------*/
3768 static void
3769 genEndFunction (iCode * ic)
3770 {
3771   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3772   lineNode *lnp = lineCurr;
3773   bitVect  *regsUsed;
3774   bitVect  *regsUsedPrologue;
3775   bitVect  *regsUnneeded;
3776   int      idx;
3777
3778   _G.currentFunc = NULL;
3779   if (IFFUNC_ISNAKED(sym->type))
3780   {
3781       emitcode(";", "naked function: no epilogue.");
3782       if (options.debug && currFunc)
3783         debugFile->writeEndFunction (currFunc, ic, 0);
3784       return;
3785   }
3786
3787   if (IFFUNC_ISCRITICAL (sym->type))
3788     {
3789       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3790         {
3791           emitcode ("rlc", "a");   /* save c in a */
3792           emitcode ("pop", "psw"); /* restore ea via c in psw */
3793           emitcode ("mov", "ea,c");
3794           emitcode ("rrc", "a");   /* restore c from a */
3795         }
3796       else
3797         {
3798           emitcode ("pop", "psw"); /* restore ea via c in psw */
3799           emitcode ("mov", "ea,c");
3800         }
3801     }
3802
3803   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3804     {
3805       if (options.useXstack)
3806         {
3807           if (sym->stack)
3808             {
3809               emitcode ("mov", "sp,_bp");
3810               emitcode ("pop", "_bp");
3811             }
3812           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3813             {
3814               emitcode ("xch", "a,_bpx");
3815               emitcode ("mov", "r0,a");
3816               emitcode ("dec", "r0");
3817               emitcode ("movx", "a,@r0");
3818               emitcode ("xch", "a,_bpx");
3819               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3820             }
3821         }
3822       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3823         {
3824           if (sym->stack)
3825             emitcode ("mov", "sp,_bp");
3826           emitcode ("pop", "_bp");
3827         }
3828     }
3829
3830   /* restore the register bank  */
3831   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3832   {
3833     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3834      || !options.useXstack)
3835     {
3836         /* Special case of ISR using non-zero bank with useXstack
3837          * is handled below.
3838          */
3839         emitcode ("pop", "psw");
3840     }
3841   }
3842
3843   if (IFFUNC_ISISR (sym->type))
3844     {
3845       bitVect *rsavebits;
3846
3847       /* now we need to restore the registers */
3848       /* if this isr has no bank i.e. is going to
3849          run with bank 0 , then we need to save more
3850          registers :-) */
3851       if (!FUNC_REGBANK (sym->type))
3852         {
3853           int i;
3854           /* if this function does not call any other
3855              function then we can be economical and
3856              save only those registers that are used */
3857           if (!IFFUNC_HASFCALL(sym->type))
3858             {
3859               /* if any registers used */
3860               if (sym->regsUsed)
3861                 {
3862                   /* save the registers used */
3863                   for (i = sym->regsUsed->size; i >= 0; i--)
3864                     {
3865                       if (bitVectBitValue (sym->regsUsed, i))
3866                         popReg (i, TRUE);
3867                     }
3868                 }
3869             }
3870           else
3871             {
3872               if (options.parms_in_bank1)
3873                 {
3874                   for (i = 7 ; i >= 0 ; i-- )
3875                     {
3876                       emitcode ("pop","%s",rb1regs[i]);
3877                     }
3878                 }
3879               /* this function has a function call. We cannot
3880                  determine register usage so we will have to pop the
3881                  entire bank */
3882               unsaveRBank (0, ic, FALSE);
3883             }
3884         }
3885       else
3886         {
3887             /* This ISR uses a non-zero bank.
3888              *
3889              * Restore any register banks saved by genFunction
3890              * in reverse order.
3891              */
3892             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3893             int ix;
3894
3895             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3896             {
3897                 if (savedBanks & (1 << ix))
3898                 {
3899                     unsaveRBank(ix, NULL, FALSE);
3900                 }
3901             }
3902
3903             if (options.useXstack)
3904             {
3905                 /* Restore bank AFTER calling unsaveRBank,
3906                  * since it can trash r0.
3907                  */
3908                 emitcode ("pop", "psw");
3909             }
3910         }
3911
3912       if (!inExcludeList ("dph"))
3913         emitcode ("pop", "dph");
3914       if (!inExcludeList ("dpl"))
3915         emitcode ("pop", "dpl");
3916       if (!inExcludeList ("b"))
3917         emitcode ("pop", "b");
3918       if (!inExcludeList ("acc"))
3919         emitcode ("pop", "acc");
3920
3921       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3922       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3923         emitcode ("pop", "bits");
3924       freeBitVect (rsavebits);
3925
3926       /* if debug then send end of function */
3927       if (options.debug && currFunc)
3928         {
3929           debugFile->writeEndFunction (currFunc, ic, 1);
3930         }
3931
3932       emitcode ("reti", "");
3933     }
3934   else
3935     {
3936       if (IFFUNC_CALLEESAVES(sym->type))
3937         {
3938           int i;
3939
3940           /* if any registers used */
3941           if (sym->regsUsed)
3942             {
3943               /* save the registers used */
3944               for (i = sym->regsUsed->size; i >= 0; i--)
3945                 {
3946                   if (bitVectBitValue (sym->regsUsed, i) ||
3947                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3948                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3949                 }
3950             }
3951           else if (mcs51_ptrRegReq)
3952             {
3953               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3954               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3955             }
3956
3957         }
3958
3959       /* if debug then send end of function */
3960       if (options.debug && currFunc)
3961         {
3962           debugFile->writeEndFunction (currFunc, ic, 1);
3963         }
3964
3965       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3966         {
3967           emitcode ("ljmp", "__sdcc_banked_ret");
3968         }
3969       else
3970         {
3971           emitcode ("ret", "");
3972         }
3973     }
3974
3975   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3976     return;
3977
3978   /* If this was an interrupt handler using bank 0 that called another */
3979   /* function, then all registers must be saved; nothing to optimized. */
3980   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3981       && !FUNC_REGBANK(sym->type))
3982     return;
3983
3984   /* There are no push/pops to optimize if not callee-saves or ISR */
3985   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3986     return;
3987
3988   /* If there were stack parameters, we cannot optimize without also    */
3989   /* fixing all of the stack offsets; this is too dificult to consider. */
3990   if (FUNC_HASSTACKPARM(sym->type))
3991     return;
3992
3993   /* Compute the registers actually used */
3994   regsUsed = newBitVect (mcs51_nRegs);
3995   regsUsedPrologue = newBitVect (mcs51_nRegs);
3996   while (lnp)
3997     {
3998       if (lnp->ic && lnp->ic->op == FUNCTION)
3999         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
4000       else
4001         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
4002
4003       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
4004           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
4005         break;
4006       if (!lnp->prev)
4007         break;
4008       lnp = lnp->prev;
4009     }
4010
4011   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
4012       && !bitVectBitValue (regsUsed, CND_IDX))
4013     {
4014       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4015       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
4016           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
4017         bitVectUnSetBit (regsUsed, CND_IDX);
4018     }
4019   else
4020     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4021
4022   /* If this was an interrupt handler that called another function */
4023   /* function, then assume A, B, DPH, & DPL may be modified by it. */
4024   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4025     {
4026       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4027       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4028       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4029       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4030       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4031     }
4032
4033   /* Remove the unneeded push/pops */
4034   regsUnneeded = newBitVect (mcs51_nRegs);
4035   while (lnp)
4036     {
4037       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4038         {
4039           if (!strncmp(lnp->line, "push", 4))
4040             {
4041               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4042               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4043                 {
4044                   connectLine (lnp->prev, lnp->next);
4045                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4046                 }
4047             }
4048           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4049             {
4050               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4051               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4052                 {
4053                   connectLine (lnp->prev, lnp->next);
4054                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4055                 }
4056             }
4057         }
4058       lnp = lnp->next;
4059     }
4060
4061   for (idx = 0; idx < regsUnneeded->size; idx++)
4062     if (bitVectBitValue (regsUnneeded, idx))
4063       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4064
4065   freeBitVect (regsUnneeded);
4066   freeBitVect (regsUsed);
4067   freeBitVect (regsUsedPrologue);
4068 }
4069
4070 /*-----------------------------------------------------------------*/
4071 /* genRet - generate code for return statement                     */
4072 /*-----------------------------------------------------------------*/
4073 static void
4074 genRet (iCode * ic)
4075 {
4076   int size, offset = 0, pushed = 0;
4077
4078   D (emitcode (";", "genRet"));
4079
4080   /* if we have no return value then
4081      just generate the "ret" */
4082   if (!IC_LEFT (ic))
4083     goto jumpret;
4084
4085   /* we have something to return then
4086      move the return value into place */
4087   aopOp (IC_LEFT (ic), ic, FALSE);
4088   size = AOP_SIZE (IC_LEFT (ic));
4089
4090   if (IS_BIT(_G.currentFunc->etype))
4091     {
4092       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4093         toCarry (IC_LEFT (ic));
4094     }
4095   else
4096     {
4097       while (size--)
4098         {
4099           char *l;
4100           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4101             {
4102               /* #NOCHANGE */
4103               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4104               emitcode ("push", "%s", l);
4105               pushed++;
4106             }
4107           else
4108             {
4109               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4110               if (strcmp (fReturn[offset], l))
4111                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4112             }
4113         }
4114
4115       while (pushed)
4116         {
4117           pushed--;
4118           if (strcmp (fReturn[pushed], "a"))
4119             emitcode ("pop", fReturn[pushed]);
4120           else
4121             emitcode ("pop", "acc");
4122         }
4123     }
4124   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4125
4126 jumpret:
4127   /* generate a jump to the return label
4128      if the next is not the return statement */
4129   if (!(ic->next && ic->next->op == LABEL &&
4130         IC_LABEL (ic->next) == returnLabel))
4131
4132     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4133
4134 }
4135
4136 /*-----------------------------------------------------------------*/
4137 /* genLabel - generates a label                                    */
4138 /*-----------------------------------------------------------------*/
4139 static void
4140 genLabel (iCode * ic)
4141 {
4142   /* special case never generate */
4143   if (IC_LABEL (ic) == entryLabel)
4144     return;
4145
4146   emitLabel (IC_LABEL (ic));
4147 }
4148
4149 /*-----------------------------------------------------------------*/
4150 /* genGoto - generates a ljmp                                      */
4151 /*-----------------------------------------------------------------*/
4152 static void
4153 genGoto (iCode * ic)
4154 {
4155   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4156 }
4157
4158 /*-----------------------------------------------------------------*/
4159 /* findLabelBackwards: walks back through the iCode chain looking  */
4160 /* for the given label. Returns number of iCode instructions     */
4161 /* between that label and given ic.          */
4162 /* Returns zero if label not found.          */
4163 /*-----------------------------------------------------------------*/
4164 static int
4165 findLabelBackwards (iCode * ic, int key)
4166 {
4167   int count = 0;
4168
4169   while (ic->prev)
4170     {
4171       ic = ic->prev;
4172       count++;
4173
4174       /* If we have any pushes or pops, we cannot predict the distance.
4175          I don't like this at all, this should be dealt with in the
4176          back-end */
4177       if (ic->op == IPUSH || ic->op == IPOP) {
4178         return 0;
4179       }
4180
4181       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4182         {
4183           return count;
4184         }
4185     }
4186
4187   return 0;
4188 }
4189
4190 /*-----------------------------------------------------------------*/
4191 /* genPlusIncr :- does addition with increment if possible         */
4192 /*-----------------------------------------------------------------*/
4193 static bool
4194 genPlusIncr (iCode * ic)
4195 {
4196   unsigned int icount;
4197   unsigned int size = getDataSize (IC_RESULT (ic));
4198
4199   /* will try to generate an increment */
4200   /* if the right side is not a literal
4201      we cannot */
4202   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4203     return FALSE;
4204
4205   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4206
4207   D(emitcode (";","genPlusIncr"));
4208
4209   /* if increment >=16 bits in register or direct space */
4210   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4211         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4212         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4213       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4214       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4215       (size > 1) &&
4216       (icount == 1))
4217     {
4218       symbol *tlbl;
4219       int emitTlbl;
4220       int labelRange;
4221       char    *l;
4222
4223       /* If the next instruction is a goto and the goto target
4224        * is < 10 instructions previous to this, we can generate
4225        * jumps straight to that target.
4226        */
4227       if (ic->next && ic->next->op == GOTO
4228           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4229           && labelRange <= 10)
4230         {
4231           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4232           tlbl = IC_LABEL (ic->next);
4233           emitTlbl = 0;
4234         }
4235       else
4236         {
4237           tlbl = newiTempLabel (NULL);
4238           emitTlbl = 1;
4239         }
4240       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE);
4241       emitcode ("inc", "%s", l);
4242       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4243           IS_AOP_PREG (IC_RESULT (ic)))
4244         {
4245           emitcode ("cjne", "%s,#0x00,%05d$", l, tlbl->key + 100);
4246         }
4247       else
4248         {
4249           emitcode ("clr", "a");
4250           emitcode ("cjne", "a,%s,%05d$", l, tlbl->key + 100);
4251         }
4252
4253       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE);
4254       emitcode ("inc", "%s", l);
4255       if (size > 2)
4256         {
4257           if (!strcmp(l, "acc"))
4258             {
4259               emitcode("jnz", "!tlabel", tlbl->key + 100);
4260             }
4261           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4262                    IS_AOP_PREG (IC_RESULT (ic)))
4263             {
4264               emitcode ("cjne", "%s,#0x00,%05d$", l, tlbl->key + 100);
4265             }
4266           else
4267             {
4268               emitcode ("cjne", "a,%s,%05d$", l, tlbl->key + 100);
4269             }
4270
4271           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE);
4272           emitcode ("inc", "%s", l);
4273         }
4274       if (size > 3)
4275         {
4276           if (!strcmp(l, "acc"))
4277             {
4278               emitcode("jnz", "!tlabel", tlbl->key + 100);
4279             }
4280           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4281                    IS_AOP_PREG (IC_RESULT (ic)))
4282             {
4283               emitcode ("cjne", "%s,#0x00,%05d$", l, tlbl->key + 100);
4284             }
4285           else
4286             {
4287               emitcode ("cjne", "a,%s,%05d$", l, tlbl->key + 100);
4288             }
4289
4290           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE);
4291           emitcode ("inc", "%s", l);
4292         }
4293
4294       if (emitTlbl)
4295         {
4296           emitLabel (tlbl);
4297         }
4298       return TRUE;
4299     }
4300
4301   /* if result is dptr */
4302   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4303       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4304       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4305       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4306     {
4307       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4308         return FALSE;
4309
4310       if (icount > 9)
4311         return FALSE;
4312
4313       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4314         return FALSE;
4315
4316       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4317       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4318       while (icount--)
4319         emitcode ("inc", "dptr");
4320
4321       return TRUE;
4322     }
4323
4324   /* if the literal value of the right hand side
4325      is greater than 4 then it is not worth it */
4326   if (icount > 4)
4327     return FALSE;
4328
4329   /* if the sizes are greater than 1 then we cannot */
4330   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4331       AOP_SIZE (IC_LEFT (ic)) > 1)
4332     return FALSE;
4333
4334   /* we can if the aops of the left & result match or
4335      if they are in registers and the registers are the
4336      same */
4337   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4338     {
4339       if (icount > 3)
4340         {
4341           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4342           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4343           aopPut (IC_RESULT (ic), "a", 0);
4344         }
4345       else
4346         {
4347           while (icount--)
4348             {
4349               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4350             }
4351         }
4352
4353       return TRUE;
4354     }
4355
4356   if (icount == 1)
4357     {
4358       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4359       emitcode ("inc", "a");
4360       aopPut (IC_RESULT (ic), "a", 0);
4361       return TRUE;
4362     }
4363
4364   return FALSE;
4365 }
4366
4367 /*-----------------------------------------------------------------*/
4368 /* outBitAcc - output a bit in acc                                 */
4369 /*-----------------------------------------------------------------*/
4370 static void
4371 outBitAcc (operand * result)
4372 {
4373   symbol *tlbl = newiTempLabel (NULL);
4374   /* if the result is a bit */
4375   if (AOP_TYPE (result) == AOP_CRY)
4376     {
4377       aopPut (result, "a", 0);
4378     }
4379   else
4380     {
4381       emitcode ("jz", "%05d$", tlbl->key + 100);
4382       emitcode ("mov", "a,%s", one);
4383       emitLabel (tlbl);
4384       outAcc (result);
4385     }
4386 }
4387
4388 /*-----------------------------------------------------------------*/
4389 /* genPlusBits - generates code for addition of two bits           */
4390 /*-----------------------------------------------------------------*/
4391 static void
4392 genPlusBits (iCode * ic)
4393 {
4394   D (emitcode (";", "genPlusBits"));
4395
4396   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4397   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4398     {
4399       symbol *lbl = newiTempLabel (NULL);
4400       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4401       emitcode ("cpl", "c");
4402       emitLabel (lbl);
4403       outBitC (IC_RESULT (ic));
4404     }
4405   else
4406     {
4407       emitcode ("clr", "a");
4408       emitcode ("rlc", "a");
4409       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4410       emitcode ("addc", "a,%s", zero);
4411       outAcc (IC_RESULT (ic));
4412     }
4413 }
4414
4415 #if 0
4416 /* This is the original version of this code.
4417
4418  * This is being kept around for reference,
4419  * because I am not entirely sure I got it right...
4420  */
4421 static void
4422 adjustArithmeticResult (iCode * ic)
4423 {
4424   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4425       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4426       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4427     aopPut (IC_RESULT (ic),
4428             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4429             2);
4430
4431   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4432       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4433       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4434     aopPut (IC_RESULT (ic),
4435             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4436             2);
4437
4438   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4439       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4440       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4441       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4442       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4443     {
4444       char buffer[5];
4445       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4446       aopPut (IC_RESULT (ic), buffer, 2);
4447     }
4448 }
4449 #else
4450 /* This is the pure and virtuous version of this code.
4451  * I'm pretty certain it's right, but not enough to toss the old
4452  * code just yet...
4453  */
4454 static void
4455 adjustArithmeticResult (iCode * ic)
4456 {
4457   if (opIsGptr (IC_RESULT (ic)))
4458     {
4459       char buffer[10];
4460
4461       if (opIsGptr (IC_LEFT (ic)))
4462         {
4463           if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4464             {
4465               aopPut (IC_RESULT (ic),
4466                       aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4467                       GPTRSIZE - 1);
4468             }
4469           return;
4470         }
4471
4472       if (opIsGptr (IC_RIGHT (ic)))
4473         {
4474           if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4475             {
4476               aopPut (IC_RESULT (ic),
4477                       aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4478                       GPTRSIZE - 1);
4479             }
4480           return;
4481         }
4482
4483       if (IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4484           IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4485           !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4486           !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4487         {
4488           SNPRINTF (buffer, sizeof(buffer),
4489                     "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4490           aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4491           return;
4492         }
4493       if (IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4494           !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4495         {
4496           SNPRINTF (buffer, sizeof(buffer),
4497                     "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4498           aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4499           return;
4500         }
4501       if (IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4502           !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4503         {
4504           SNPRINTF (buffer, sizeof(buffer),
4505                     "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_RIGHT (ic)))), NULL, NULL));
4506           aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4507           return;
4508         }
4509     }
4510 }
4511 #endif
4512
4513 /*-----------------------------------------------------------------*/
4514 /* genPlus - generates code for addition                           */
4515 /*-----------------------------------------------------------------*/
4516 static void
4517 genPlus (iCode * ic)
4518 {
4519   int size, offset = 0;
4520   int skip_bytes = 0;
4521   char *add = "add";
4522   bool swappedLR = FALSE;
4523   operand *leftOp, *rightOp;
4524   operand * op;
4525
4526   D (emitcode (";", "genPlus"));
4527
4528   /* special cases :- */
4529
4530   aopOp (IC_LEFT (ic), ic, FALSE);
4531   aopOp (IC_RIGHT (ic), ic, FALSE);
4532   aopOp (IC_RESULT (ic), ic, TRUE);
4533
4534   /* if literal, literal on the right or
4535      if left requires ACC or right is already
4536      in ACC */
4537   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4538       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4539       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4540     {
4541       operand *t = IC_RIGHT (ic);
4542       IC_RIGHT (ic) = IC_LEFT (ic);
4543       IC_LEFT (ic) = t;
4544       swappedLR = TRUE;
4545     }
4546
4547   /* if both left & right are in bit
4548      space */
4549   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4550       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4551     {
4552       genPlusBits (ic);
4553       goto release;
4554     }
4555
4556   /* if left in bit space & right literal */
4557   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4558       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4559     {
4560       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4561       /* if result in bit space */
4562       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4563         {
4564           if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4565             emitcode ("cpl", "c");
4566           outBitC (IC_RESULT (ic));
4567         }
4568       else
4569         {
4570           size = getDataSize (IC_RESULT (ic));
4571           while (size--)
4572             {
4573               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4574               emitcode ("addc", "a,%s", zero);
4575               aopPut (IC_RESULT (ic), "a", offset++);
4576             }
4577         }
4578       goto release;
4579     }
4580
4581   /* if I can do an increment instead
4582      of add then GOOD for ME */
4583   if (genPlusIncr (ic) == TRUE)
4584     goto release;
4585
4586   size = getDataSize (IC_RESULT (ic));
4587   leftOp = IC_LEFT(ic);
4588   rightOp = IC_RIGHT(ic);
4589   op = IC_LEFT(ic);
4590
4591   /* if this is an add for an array access
4592      at a 256 byte boundary */
4593   if ( 2 == size
4594        && AOP_TYPE (op) == AOP_IMMD
4595        && IS_SYMOP (op)
4596        && IS_SPEC (OP_SYM_ETYPE (op))
4597        && SPEC_ABSA (OP_SYM_ETYPE (op))
4598        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4599      )
4600     {
4601       D(emitcode (";", "genPlus aligned array"));
4602       aopPut (IC_RESULT (ic),
4603               aopGet (rightOp, 0, FALSE, FALSE),
4604               0);
4605
4606       if( 1 == getDataSize (IC_RIGHT (ic)) )
4607         {
4608           aopPut (IC_RESULT (ic),
4609                   aopGet (leftOp, 1, FALSE, FALSE),
4610                   1);
4611         }
4612       else
4613         {
4614           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4615           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4616           aopPut (IC_RESULT (ic), "a", 1);
4617         }
4618       goto release;
4619     }
4620
4621   /* if the lower bytes of a literal are zero skip the addition */
4622   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4623     {
4624        while ((0 == ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4625               (skip_bytes+1 < size))
4626          {
4627            skip_bytes++;
4628          }
4629        if (skip_bytes)
4630          D(emitcode (";", "genPlus shortcut"));
4631     }
4632
4633   while (size--)
4634     {
4635       if( offset >= skip_bytes )
4636         {
4637           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4638             {
4639               bool pushedB;
4640               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4641               pushedB = pushB ();
4642               emitcode("xch", "a,b");
4643               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4644               emitcode (add, "a,b");
4645               popB (pushedB);
4646             }
4647           else if (aopGetUsesAcc (leftOp, offset))
4648             {
4649               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4650               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4651             }
4652           else
4653             {
4654               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4655               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4656             }
4657           aopPut (IC_RESULT (ic), "a", offset);
4658           add = "addc";  /* further adds must propagate carry */
4659         }
4660       else
4661         {
4662           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4663               isOperandVolatile (IC_RESULT (ic), FALSE))
4664             {
4665               /* just move */
4666               aopPut (IC_RESULT (ic),
4667                       aopGet (leftOp, offset, FALSE, FALSE),
4668                       offset);
4669             }
4670         }
4671       offset++;
4672     }
4673
4674   adjustArithmeticResult (ic);
4675
4676 release:
4677   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4678   if (!swappedLR)
4679     {
4680       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4681       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4682     }
4683   else
4684     {
4685       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4686       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4687     }
4688 }
4689
4690 /*-----------------------------------------------------------------*/
4691 /* genMinusDec :- does subtraction with decrement if possible      */
4692 /*-----------------------------------------------------------------*/
4693 static bool
4694 genMinusDec (iCode * ic)
4695 {
4696   unsigned int icount;
4697   unsigned int size = getDataSize (IC_RESULT (ic));
4698
4699   /* will try to generate an increment */
4700   /* if the right side is not a literal
4701      we cannot */
4702   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4703     return FALSE;
4704
4705   /* if the literal value of the right hand side
4706      is greater than 4 then it is not worth it */
4707   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4708     return FALSE;
4709
4710   D (emitcode (";", "genMinusDec"));
4711
4712   /* if decrement >=16 bits in register or direct space */
4713   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4714         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4715         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4716       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4717       (size > 1) &&
4718       (icount == 1))
4719     {
4720       symbol *tlbl;
4721       int    emitTlbl;
4722       int    labelRange;
4723       char   *l;
4724
4725       /* If the next instruction is a goto and the goto target
4726        * is <= 10 instructions previous to this, we can generate
4727        * jumps straight to that target.
4728        */
4729       if (ic->next && ic->next->op == GOTO
4730           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4731           && labelRange <= 10)
4732         {
4733           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4734           tlbl = IC_LABEL (ic->next);
4735           emitTlbl = 0;
4736         }
4737       else
4738         {
4739           tlbl = newiTempLabel (NULL);
4740           emitTlbl = 1;
4741         }
4742
4743       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE);
4744       emitcode ("dec", "%s", l);
4745
4746       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4747           IS_AOP_PREG (IC_RESULT (ic)))
4748         {
4749           emitcode ("cjne", "%s,#0xff,%05d$", l, tlbl->key + 100);
4750         }
4751       else
4752         {
4753           emitcode ("mov", "a,#0xff");
4754           emitcode ("cjne", "a,%s,%05d$", l, tlbl->key + 100);
4755         }
4756       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE);
4757       emitcode ("dec", "%s", l);
4758       if (size > 2)
4759         {
4760           if (!strcmp(l, "acc"))
4761             {
4762               emitcode("jnz", "!tlabel", tlbl->key + 100);
4763             }
4764           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4765                    IS_AOP_PREG (IC_RESULT (ic)))
4766             {
4767               emitcode ("cjne", "%s,#0xff,%05d$", l, tlbl->key + 100);
4768             }
4769           else
4770             {
4771               emitcode ("cjne", "a,%s,%05d$", l, tlbl->key + 100);
4772             }
4773           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE);
4774           emitcode ("dec", "%s", l);
4775         }
4776       if (size > 3)
4777         {
4778           if (!strcmp(l, "acc"))
4779             {
4780               emitcode("jnz", "!tlabel", tlbl->key + 100);
4781             }
4782           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4783                    IS_AOP_PREG (IC_RESULT (ic)))
4784             {
4785               emitcode ("cjne", "%s,#0xff,%05d$", l, tlbl->key + 100);
4786             }
4787           else
4788             {
4789               emitcode ("cjne", "a,%s,%05d$", l, tlbl->key + 100);
4790             }
4791           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE);
4792           emitcode ("dec", "%s", l);
4793         }
4794       if (emitTlbl)
4795         {
4796           emitLabel (tlbl);
4797         }
4798       return TRUE;
4799     }
4800
4801   /* if the sizes are greater than 1 then we cannot */
4802   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4803       AOP_SIZE (IC_LEFT (ic)) > 1)
4804     return FALSE;
4805
4806   /* we can if the aops of the left & result match or
4807      if they are in registers and the registers are the
4808      same */
4809   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4810     {
4811       char *l;
4812
4813       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4814         {
4815           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4816           l = "a";
4817         }
4818       else
4819         {
4820           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4821         }
4822
4823       while (icount--)
4824         {
4825           emitcode ("dec", "%s", l);
4826         }
4827
4828       if (AOP_NEEDSACC (IC_RESULT (ic)))
4829         aopPut (IC_RESULT (ic), "a", 0);
4830
4831       return TRUE;
4832     }
4833
4834   if (icount == 1)
4835     {
4836       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4837       emitcode ("dec", "a");
4838       aopPut (IC_RESULT (ic), "a", 0);
4839       return TRUE;
4840     }
4841
4842   return FALSE;
4843 }
4844
4845 /*-----------------------------------------------------------------*/
4846 /* addSign - complete with sign                                    */
4847 /*-----------------------------------------------------------------*/
4848 static void
4849 addSign (operand * result, int offset, int sign)
4850 {
4851   int size = (getDataSize (result) - offset);
4852   if (size > 0)
4853     {
4854       if (sign)
4855         {
4856           emitcode ("rlc", "a");
4857           emitcode ("subb", "a,acc");
4858           while (size--)
4859             {
4860               aopPut (result, "a", offset++);
4861             }
4862         }
4863       else
4864         {
4865           while (size--)
4866             {
4867               aopPut (result, zero, offset++);
4868             }
4869         }
4870     }
4871 }
4872
4873 /*-----------------------------------------------------------------*/
4874 /* genMinusBits - generates code for subtraction  of two bits      */
4875 /*-----------------------------------------------------------------*/
4876 static void
4877 genMinusBits (iCode * ic)
4878 {
4879   symbol *lbl = newiTempLabel (NULL);
4880
4881   D (emitcode (";", "genMinusBits"));
4882
4883   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4884     {
4885       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4886       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4887       emitcode ("cpl", "c");
4888       emitLabel (lbl);
4889       outBitC (IC_RESULT (ic));
4890     }
4891   else
4892     {
4893       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4894       emitcode ("subb", "a,acc");
4895       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4896       emitcode ("inc", "a");
4897       emitLabel (lbl);
4898       aopPut (IC_RESULT (ic), "a", 0);
4899       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4900     }
4901 }
4902
4903 /*-----------------------------------------------------------------*/
4904 /* genMinus - generates code for subtraction                       */
4905 /*-----------------------------------------------------------------*/
4906 static void
4907 genMinus (iCode * ic)
4908 {
4909   int size, offset = 0;
4910
4911   D (emitcode (";", "genMinus"));
4912
4913   aopOp (IC_LEFT (ic), ic, FALSE);
4914   aopOp (IC_RIGHT (ic), ic, FALSE);
4915   aopOp (IC_RESULT (ic), ic, TRUE);
4916
4917   /* special cases :- */
4918   /* if both left & right are in bit space */
4919   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4920       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4921     {
4922       genMinusBits (ic);
4923       goto release;
4924     }
4925
4926   /* if I can do an decrement instead
4927      of subtract then GOOD for ME */
4928   if (genMinusDec (ic) == TRUE)
4929     goto release;
4930
4931   size = getDataSize (IC_RESULT (ic));
4932
4933   /* if literal, add a,#-lit, else normal subb */
4934   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4935     {
4936       unsigned long lit = 0L;
4937       bool useCarry = FALSE;
4938
4939       lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4940       lit = -(long) lit;
4941
4942       while (size--)
4943         {
4944           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4945             {
4946               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4947               if (!offset && !size && lit== (unsigned long) -1)
4948                 {
4949                   emitcode ("dec", "a");
4950                 }
4951               else if (!useCarry)
4952                 {
4953                   /* first add without previous c */
4954                   emitcode ("add", "a,#0x%02x",
4955                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4956                   useCarry = TRUE;
4957                 }
4958               else
4959                 {
4960                   emitcode ("addc", "a,#0x%02x",
4961                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4962                 }
4963               aopPut (IC_RESULT (ic), "a", offset++);
4964             }
4965           else
4966             {
4967               /* no need to add zeroes */
4968               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4969                 {
4970                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4971                           offset);
4972                 }
4973               offset++;
4974             }
4975         }
4976     }
4977   else
4978     {
4979       operand *leftOp, *rightOp;
4980
4981       leftOp = IC_LEFT(ic);
4982       rightOp = IC_RIGHT(ic);
4983
4984       while (size--)
4985         {
4986           if (aopGetUsesAcc(rightOp, offset)) {
4987             if (aopGetUsesAcc(leftOp, offset)) {
4988               bool pushedB;
4989
4990               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4991               pushedB = pushB ();
4992               emitcode ("mov", "b,a");
4993               if (offset == 0)
4994                 CLRC;
4995               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4996               emitcode ("subb", "a,b");
4997               popB (pushedB);
4998             } else {
4999               /* reverse subtraction with 2's complement */
5000               if (offset == 0)
5001                 emitcode( "setb", "c");
5002               else
5003                 emitcode( "cpl", "c");
5004               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
5005               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
5006               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
5007               emitcode("cpl", "a");
5008               if (size) /* skip if last byte */
5009                 emitcode( "cpl", "c");
5010             }
5011           } else {
5012             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
5013             if (offset == 0)
5014               CLRC;
5015             emitcode ("subb", "a,%s",
5016                       aopGet(rightOp, offset, FALSE, TRUE));
5017           }
5018
5019           aopPut (IC_RESULT (ic), "a", offset++);
5020         }
5021     }
5022
5023   adjustArithmeticResult (ic);
5024
5025 release:
5026   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5027   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5028   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5029 }
5030
5031
5032 /*-----------------------------------------------------------------*/
5033 /* genMultbits :- multiplication of bits                           */
5034 /*-----------------------------------------------------------------*/
5035 static void
5036 genMultbits (operand * left,
5037              operand * right,
5038              operand * result)
5039 {
5040   D (emitcode (";", "genMultbits"));
5041
5042   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5043   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5044   outBitC (result);
5045 }
5046
5047 /*-----------------------------------------------------------------*/
5048 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5049 /*-----------------------------------------------------------------*/
5050 static void
5051 genMultOneByte (operand * left,
5052                 operand * right,
5053                 operand * result)
5054 {
5055   symbol *lbl;
5056   int size = AOP_SIZE (result);
5057   bool runtimeSign, compiletimeSign;
5058   bool lUnsigned, rUnsigned, pushedB;
5059
5060   D (emitcode (";", "genMultOneByte"));
5061
5062   if (size < 1 || size > 2)
5063     {
5064       /* this should never happen */
5065       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5066                AOP_SIZE(result), __FILE__, lineno);
5067       exit (1);
5068     }
5069
5070   /* (if two literals: the value is computed before) */
5071   /* if one literal, literal on the right */
5072   if (AOP_TYPE (left) == AOP_LIT)
5073     {
5074       operand *t = right;
5075       right = left;
5076       left = t;
5077       /* emitcode (";", "swapped left and right"); */
5078     }
5079   /* if no literal, unsigned on the right: shorter code */
5080   if (   AOP_TYPE (right) != AOP_LIT
5081       && SPEC_USIGN (getSpec (operandType (left))))
5082     {
5083       operand *t = right;
5084       right = left;
5085       left = t;
5086     }
5087
5088   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5089   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5090
5091   pushedB = pushB ();
5092
5093   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5094                    no need to take care about the signedness! */
5095       || (lUnsigned && rUnsigned))
5096     {
5097       /* just an unsigned 8 * 8 = 8 multiply
5098          or 8u * 8u = 16u */
5099       /* emitcode (";","unsigned"); */
5100       /* TODO: check for accumulator clash between left & right aops? */
5101
5102       if (AOP_TYPE (right) == AOP_LIT)
5103         {
5104           /* moving to accumulator first helps peepholes */
5105           MOVA (aopGet (left, 0, FALSE, FALSE));
5106           MOVB (aopGet (right, 0, FALSE, FALSE));
5107         }
5108       else
5109         {
5110           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5111           MOVA (aopGet (left, 0, FALSE, FALSE));
5112         }
5113
5114       emitcode ("mul", "ab");
5115       aopPut (result, "a", 0);
5116       if (size == 2)
5117         aopPut (result, "b", 1);
5118
5119       popB (pushedB);
5120       return;
5121     }
5122
5123   /* we have to do a signed multiply */
5124   /* emitcode (";", "signed"); */
5125
5126   /* now sign adjust for both left & right */
5127
5128   /* let's see what's needed: */
5129   /* apply negative sign during runtime */
5130   runtimeSign = FALSE;
5131   /* negative sign from literals */
5132   compiletimeSign = FALSE;
5133
5134   if (!lUnsigned)
5135     {
5136       if (AOP_TYPE(left) == AOP_LIT)
5137         {
5138           /* signed literal */
5139           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5140           if (val < 0)
5141             compiletimeSign = TRUE;
5142         }
5143       else
5144         /* signed but not literal */
5145         runtimeSign = TRUE;
5146     }
5147
5148   if (!rUnsigned)
5149     {
5150       if (AOP_TYPE(right) == AOP_LIT)
5151         {
5152           /* signed literal */
5153           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5154           if (val < 0)
5155             compiletimeSign ^= TRUE;
5156         }
5157       else
5158         /* signed but not literal */
5159         runtimeSign = TRUE;
5160     }
5161
5162   /* initialize F0, which stores the runtime sign */
5163   if (runtimeSign)
5164     {
5165       if (compiletimeSign)
5166         emitcode ("setb", "F0"); /* set sign flag */
5167       else
5168         emitcode ("clr", "F0"); /* reset sign flag */
5169     }
5170
5171   /* save the signs of the operands */
5172   if (AOP_TYPE(right) == AOP_LIT)
5173     {
5174       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5175
5176       if (!rUnsigned && val < 0)
5177         emitcode ("mov", "b,#0x%02x", -val);
5178       else
5179         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5180     }
5181   else /* ! literal */
5182     {
5183       if (rUnsigned)  /* emitcode (";", "signed"); */
5184         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5185       else
5186         {
5187           MOVA (aopGet (right, 0, FALSE, FALSE));
5188           lbl = newiTempLabel (NULL);
5189           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5190           emitcode ("cpl", "F0"); /* complement sign flag */
5191           emitcode ("cpl", "a");  /* 2's complement */
5192           emitcode ("inc", "a");
5193           emitLabel (lbl);
5194           emitcode ("mov", "b,a");
5195         }
5196     }
5197
5198   if (AOP_TYPE(left) == AOP_LIT)
5199     {
5200       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5201
5202       if (!lUnsigned && val < 0)
5203         emitcode ("mov", "a,#0x%02x", -val);
5204       else
5205         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5206     }
5207   else /* ! literal */
5208     {
5209       MOVA (aopGet (left, 0, FALSE, FALSE));
5210
5211       if (!lUnsigned)
5212         {
5213           lbl = newiTempLabel (NULL);
5214           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5215           emitcode ("cpl", "F0"); /* complement sign flag */
5216           emitcode ("cpl", "a");  /* 2's complement */
5217           emitcode ("inc", "a");
5218           emitLabel (lbl);
5219         }
5220     }
5221
5222   /* now the multiplication */
5223   emitcode ("mul", "ab");
5224   if (runtimeSign || compiletimeSign)
5225     {
5226       lbl = newiTempLabel (NULL);
5227       if (runtimeSign)
5228         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5229       emitcode ("cpl", "a"); /* lsb 2's complement */
5230       if (size != 2)
5231         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5232       else
5233         {
5234           emitcode ("add", "a,#0x01"); /* this sets carry flag */
5235           emitcode ("xch", "a,b");
5236           emitcode ("cpl", "a"); /* msb 2's complement */
5237           emitcode ("addc", "a,#0x00");
5238           emitcode ("xch", "a,b");
5239         }
5240       emitLabel (lbl);
5241     }
5242   aopPut (result, "a", 0);
5243   if (size == 2)
5244     aopPut (result, "b", 1);
5245
5246   popB (pushedB);
5247 }
5248
5249 /*-----------------------------------------------------------------*/
5250 /* genMult - generates code for multiplication                     */
5251 /*-----------------------------------------------------------------*/
5252 static void
5253 genMult (iCode * ic)
5254 {
5255   operand *left = IC_LEFT (ic);
5256   operand *right = IC_RIGHT (ic);
5257   operand *result = IC_RESULT (ic);
5258
5259   D (emitcode (";", "genMult"));
5260
5261   /* assign the asmops */
5262   aopOp (left, ic, FALSE);
5263   aopOp (right, ic, FALSE);
5264   aopOp (result, ic, TRUE);
5265
5266   /* special cases first */
5267   /* both are bits */
5268   if (AOP_TYPE (left) == AOP_CRY &&
5269       AOP_TYPE (right) == AOP_CRY)
5270     {
5271       genMultbits (left, right, result);
5272       goto release;
5273     }
5274
5275   /* if both are of size == 1 */
5276 #if 0 // one of them can be a sloc shared with the result
5277     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5278 #else
5279   if (getSize(operandType(left)) == 1 &&
5280       getSize(operandType(right)) == 1)
5281 #endif
5282     {
5283       genMultOneByte (left, right, result);
5284       goto release;
5285     }
5286
5287   /* should have been converted to function call */
5288     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5289              getSize(OP_SYMBOL(right)->type));
5290   assert (0);
5291
5292 release:
5293   freeAsmop (result, NULL, ic, TRUE);
5294   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5295   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5296 }
5297
5298 /*-----------------------------------------------------------------*/
5299 /* genDivbits :- division of bits                                  */
5300 /*-----------------------------------------------------------------*/
5301 static void
5302 genDivbits (operand * left,
5303             operand * right,
5304             operand * result)
5305 {
5306   char *l;
5307   bool pushedB;
5308
5309   D(emitcode (";", "genDivbits"));
5310
5311   pushedB = pushB ();
5312
5313   /* the result must be bit */
5314   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5315   l = aopGet (left, 0, FALSE, FALSE);
5316
5317   MOVA (l);
5318
5319   emitcode ("div", "ab");
5320   emitcode ("rrc", "a");
5321
5322   popB (pushedB);
5323
5324   aopPut (result, "c", 0);
5325 }
5326
5327 /*-----------------------------------------------------------------*/
5328 /* genDivOneByte : 8 bit division                                  */
5329 /*-----------------------------------------------------------------*/
5330 static void
5331 genDivOneByte (operand * left,
5332                operand * right,
5333                operand * result)
5334 {
5335   bool lUnsigned, rUnsigned, pushedB;
5336   bool runtimeSign, compiletimeSign;
5337   bool accuse = FALSE;
5338   bool pushedA = FALSE;
5339   symbol *lbl;
5340   int size, offset;
5341
5342   D(emitcode (";", "genDivOneByte"));
5343
5344   /* Why is it necessary that genDivOneByte() can return an int result?
5345      Have a look at:
5346
5347         volatile unsigned char uc;
5348         volatile signed char sc1, sc2;
5349         volatile int i;
5350
5351         uc  = 255;
5352         sc1 = -1;
5353         i = uc / sc1;
5354
5355      Or:
5356
5357         sc1 = -128;
5358         sc2 = -1;
5359         i = sc1 / sc2;
5360
5361      In all cases a one byte result would overflow, the following cast to int
5362      would return the wrong result.
5363
5364      Two possible solution:
5365         a) cast operands to int, if ((unsigned) / (signed)) or
5366            ((signed) / (signed))
5367         b) return an 16 bit signed int; this is what we're doing here!
5368   */
5369
5370   size = AOP_SIZE (result) - 1;
5371   offset = 1;
5372   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5373   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5374
5375   pushedB = pushB ();
5376
5377   /* signed or unsigned */
5378   if (lUnsigned && rUnsigned)
5379     {
5380       /* unsigned is easy */
5381       MOVB (aopGet (right, 0, FALSE, FALSE));
5382       MOVA (aopGet (left, 0, FALSE, FALSE));
5383       emitcode ("div", "ab");
5384       aopPut (result, "a", 0);
5385       while (size--)
5386         aopPut (result, zero, offset++);
5387
5388       popB (pushedB);
5389       return;
5390     }
5391
5392   /* signed is a little bit more difficult */
5393
5394   /* now sign adjust for both left & right */
5395
5396   /* let's see what's needed: */
5397   /* apply negative sign during runtime */
5398   runtimeSign = FALSE;
5399   /* negative sign from literals */
5400   compiletimeSign = FALSE;
5401
5402   if (!lUnsigned)
5403     {
5404       if (AOP_TYPE(left) == AOP_LIT)
5405         {
5406           /* signed literal */
5407           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5408           if (val < 0)
5409             compiletimeSign = TRUE;
5410         }
5411       else
5412         /* signed but not literal */
5413         runtimeSign = TRUE;
5414     }
5415
5416   if (!rUnsigned)
5417     {
5418       if (AOP_TYPE(right) == AOP_LIT)
5419         {
5420           /* signed literal */
5421           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5422           if (val < 0)
5423             compiletimeSign ^= TRUE;
5424         }
5425       else
5426         /* signed but not literal */
5427         runtimeSign = TRUE;
5428     }
5429
5430   /* initialize F0, which stores the runtime sign */
5431   if (runtimeSign)
5432     {
5433       if (compiletimeSign)
5434         emitcode ("setb", "F0"); /* set sign flag */
5435       else
5436         emitcode ("clr", "F0"); /* reset sign flag */
5437     }
5438
5439   /* save the signs of the operands */
5440   if (AOP_TYPE(right) == AOP_LIT)
5441     {
5442       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5443
5444       if (!rUnsigned && val < 0)
5445         emitcode ("mov", "b,#0x%02x", -val);
5446       else
5447         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5448     }
5449   else /* ! literal */
5450     {
5451       if (rUnsigned)
5452         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5453       else
5454         {
5455           MOVA (aopGet (right, 0, FALSE, FALSE));
5456           lbl = newiTempLabel (NULL);
5457           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5458           emitcode ("cpl", "F0"); /* complement sign flag */
5459           emitcode ("cpl", "a");  /* 2's complement */
5460           emitcode ("inc", "a");
5461           emitLabel (lbl);
5462           emitcode ("mov", "b,a");
5463         }
5464     }
5465
5466   if (AOP_TYPE(left) == AOP_LIT)
5467     {
5468       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5469
5470       if (!lUnsigned && val < 0)
5471         emitcode ("mov", "a,#0x%02x", -val);
5472       else
5473         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5474     }
5475   else /* ! literal */
5476     {
5477       MOVA (aopGet (left, 0, FALSE, FALSE));
5478
5479       if (!lUnsigned)
5480         {
5481           lbl = newiTempLabel (NULL);
5482           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5483           emitcode ("cpl", "F0"); /* complement sign flag */
5484           emitcode ("cpl", "a");  /* 2's complement */
5485           emitcode ("inc", "a");
5486           emitLabel (lbl);
5487         }
5488     }
5489
5490   /* now the division */
5491   emitcode ("div", "ab");
5492
5493   if (runtimeSign || compiletimeSign)
5494     {
5495       lbl = newiTempLabel (NULL);
5496       if (runtimeSign)
5497         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5498       emitcode ("cpl", "a"); /* lsb 2's complement */
5499       emitcode ("inc", "a");
5500       emitLabel (lbl);
5501
5502       accuse = aopPut (result, "a", 0);
5503       if (size > 0)
5504         {
5505           /* msb is 0x00 or 0xff depending on the sign */
5506           if (runtimeSign)
5507             {
5508               if (accuse)
5509                 {
5510                   emitcode ("push", "acc");
5511                   pushedA = TRUE;
5512                 }
5513               emitcode ("mov", "c,F0");
5514               emitcode ("subb", "a,acc");
5515               while (size--)
5516                 aopPut (result, "a", offset++);
5517             }
5518           else /* compiletimeSign */
5519             {
5520               if (aopPutUsesAcc (result, "#0xff", offset))
5521                 {
5522                   emitcode ("push", "acc");
5523                   pushedA = TRUE;
5524                 }
5525               while (size--)
5526                 aopPut (result, "#0xff", offset++);
5527             }
5528         }
5529     }
5530   else
5531     {
5532       aopPut (result, "a", 0);
5533       while (size--)
5534         aopPut (result, zero, offset++);
5535     }
5536
5537   if (pushedA)
5538     emitcode ("pop", "acc");
5539   popB (pushedB);
5540 }
5541
5542 /*-----------------------------------------------------------------*/
5543 /* genDiv - generates code for division                            */
5544 /*-----------------------------------------------------------------*/
5545 static void
5546 genDiv (iCode * ic)
5547 {
5548   operand *left = IC_LEFT (ic);
5549   operand *right = IC_RIGHT (ic);
5550   operand *result = IC_RESULT (ic);
5551
5552   D (emitcode (";", "genDiv"));
5553
5554   /* assign the asmops */
5555   aopOp (left, ic, FALSE);
5556   aopOp (right, ic, FALSE);
5557   aopOp (result, ic, TRUE);
5558
5559   /* special cases first */
5560   /* both are bits */
5561   if (AOP_TYPE (left) == AOP_CRY &&
5562       AOP_TYPE (right) == AOP_CRY)
5563     {
5564       genDivbits (left, right, result);
5565       goto release;
5566     }
5567
5568   /* if both are of size == 1 */
5569   if (AOP_SIZE (left) == 1 &&
5570       AOP_SIZE (right) == 1)
5571     {
5572       genDivOneByte (left, right, result);
5573       goto release;
5574     }
5575
5576   /* should have been converted to function call */
5577   assert (0);
5578 release:
5579   freeAsmop (result, NULL, ic, TRUE);
5580   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5581   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5582 }
5583
5584 /*-----------------------------------------------------------------*/
5585 /* genModbits :- modulus of bits                                   */
5586 /*-----------------------------------------------------------------*/
5587 static void
5588 genModbits (operand * left,
5589             operand * right,
5590             operand * result)
5591 {
5592   char *l;
5593   bool pushedB;
5594
5595   D (emitcode (";", "genModbits"));
5596
5597   pushedB = pushB ();
5598
5599   /* the result must be bit */
5600   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5601   l = aopGet (left, 0, FALSE, FALSE);
5602
5603   MOVA (l);
5604
5605   emitcode ("div", "ab");
5606   emitcode ("mov", "a,b");
5607   emitcode ("rrc", "a");
5608
5609   popB (pushedB);
5610
5611   aopPut (result, "c", 0);
5612 }
5613
5614 /*-----------------------------------------------------------------*/
5615 /* genModOneByte : 8 bit modulus                                   */
5616 /*-----------------------------------------------------------------*/
5617 static void
5618 genModOneByte (operand * left,
5619                operand * right,
5620                operand * result)
5621 {
5622   bool lUnsigned, rUnsigned, pushedB;
5623   bool runtimeSign, compiletimeSign;
5624   symbol *lbl;
5625   int size, offset;
5626
5627   D (emitcode (";", "genModOneByte"));
5628
5629   size = AOP_SIZE (result) - 1;
5630   offset = 1;
5631   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5632   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5633
5634   /* if right is a literal, check it for 2^n */
5635   if (AOP_TYPE(right) == AOP_LIT)
5636     {
5637       unsigned char val = abs((int) operandLitValue(right));
5638       symbol *lbl2 = NULL;
5639
5640       switch (val)
5641         {
5642           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5643           case 2:
5644           case 4:
5645           case 8:
5646           case 16:
5647           case 32:
5648           case 64:
5649           case 128:
5650             if (lUnsigned)
5651               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5652                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5653               /* because iCode should have been changed to genAnd  */
5654               /* see file "SDCCopt.c", function "convertToFcall()" */
5655
5656             MOVA (aopGet (left, 0, FALSE, FALSE));
5657             emitcode ("mov", "c,acc.7");
5658             emitcode ("anl", "a,#0x%02x", val - 1);
5659             lbl = newiTempLabel (NULL);
5660             emitcode ("jz", "%05d$", (lbl->key + 100));
5661             emitcode ("jnc", "%05d$", (lbl->key + 100));
5662             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5663             if (size)
5664               {
5665                 int size2 = size;
5666                 int offs2 = offset;
5667
5668                 aopPut (result, "a", 0);
5669                 while (size2--)
5670                   aopPut (result, "#0xff", offs2++);
5671                 lbl2 = newiTempLabel (NULL);
5672                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5673               }
5674             emitLabel (lbl);
5675             aopPut (result, "a", 0);
5676             while (size--)
5677               aopPut (result, zero, offset++);
5678             if (lbl2)
5679               {
5680                 emitLabel (lbl2);
5681               }
5682             return;
5683
5684           default:
5685             break;
5686         }
5687     }
5688
5689   pushedB = pushB ();
5690
5691   /* signed or unsigned */
5692   if (lUnsigned && rUnsigned)
5693     {
5694       /* unsigned is easy */
5695       MOVB (aopGet (right, 0, FALSE, FALSE));
5696       MOVA (aopGet (left, 0, FALSE, FALSE));
5697       emitcode ("div", "ab");
5698       aopPut (result, "b", 0);
5699       while (size--)
5700         aopPut (result, zero, offset++);
5701
5702       popB (pushedB);
5703       return;
5704     }
5705
5706   /* signed is a little bit more difficult */
5707
5708   /* now sign adjust for both left & right */
5709
5710   /* modulus: sign of the right operand has no influence on the result! */
5711   if (AOP_TYPE(right) == AOP_LIT)
5712     {
5713       signed char val = (char) operandLitValue(right);
5714
5715       if (!rUnsigned && val < 0)
5716         emitcode ("mov", "b,#0x%02x", -val);
5717       else
5718         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5719     }
5720   else /* not literal */
5721     {
5722       if (rUnsigned)
5723         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5724       else
5725         {
5726           MOVA (aopGet (right, 0, FALSE, FALSE));
5727           lbl = newiTempLabel (NULL);
5728           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5729           emitcode ("cpl", "a"); /* 2's complement */
5730           emitcode ("inc", "a");
5731           emitLabel (lbl);
5732           emitcode ("mov", "b,a");
5733         }
5734     }
5735
5736   /* let's see what's needed: */
5737   /* apply negative sign during runtime */
5738   runtimeSign = FALSE;
5739   /* negative sign from literals */
5740   compiletimeSign = FALSE;
5741
5742   /* sign adjust left side */
5743   if (AOP_TYPE(left) == AOP_LIT)
5744     {
5745       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5746
5747       if (!lUnsigned && val < 0)
5748         {
5749           compiletimeSign = TRUE; /* set sign flag */
5750           emitcode ("mov", "a,#0x%02x", -val);
5751         }
5752       else
5753         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5754     }
5755   else /* ! literal */
5756     {
5757       MOVA (aopGet (left, 0, FALSE, FALSE));
5758
5759       if (!lUnsigned)
5760         {
5761           runtimeSign = TRUE;
5762           emitcode ("clr", "F0"); /* clear sign flag */
5763
5764           lbl = newiTempLabel (NULL);
5765           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5766           emitcode ("setb", "F0"); /* set sign flag */
5767           emitcode ("cpl", "a");   /* 2's complement */
5768           emitcode ("inc", "a");
5769           emitLabel (lbl);
5770         }
5771     }
5772
5773   /* now the modulus */
5774   emitcode ("div", "ab");
5775
5776   if (runtimeSign || compiletimeSign)
5777     {
5778       emitcode ("mov", "a,b");
5779       lbl = newiTempLabel (NULL);
5780       if (runtimeSign)
5781         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5782       emitcode ("cpl", "a"); /* 2's complement */
5783       emitcode ("inc", "a");
5784       emitLabel (lbl);
5785
5786       aopPut (result, "a", 0);
5787       if (size > 0)
5788         {
5789           /* msb is 0x00 or 0xff depending on the sign */
5790           if (runtimeSign)
5791             {
5792               emitcode ("mov",  "c,F0");
5793               emitcode ("subb", "a,acc");
5794               while (size--)
5795                 aopPut (result, "a", offset++);
5796             }
5797           else /* compiletimeSign */
5798             while (size--)
5799               aopPut (result, "#0xff", offset++);
5800         }
5801     }
5802   else
5803     {
5804       aopPut (result, "b", 0);
5805       while (size--)
5806         aopPut (result, zero, offset++);
5807     }
5808
5809   popB (pushedB);
5810 }
5811
5812 /*-----------------------------------------------------------------*/
5813 /* genMod - generates code for division                            */
5814 /*-----------------------------------------------------------------*/
5815 static void
5816 genMod (iCode * ic)
5817 {
5818   operand *left = IC_LEFT (ic);
5819   operand *right = IC_RIGHT (ic);
5820   operand *result = IC_RESULT (ic);
5821
5822   D (emitcode (";", "genMod"));
5823
5824   /* assign the asmops */
5825   aopOp (left, ic, FALSE);
5826   aopOp (right, ic, FALSE);
5827   aopOp (result, ic, TRUE);
5828
5829   /* special cases first */
5830   /* both are bits */
5831   if (AOP_TYPE (left) == AOP_CRY &&
5832       AOP_TYPE (right) == AOP_CRY)
5833     {
5834       genModbits (left, right, result);
5835       goto release;
5836     }
5837
5838   /* if both are of size == 1 */
5839   if (AOP_SIZE (left) == 1 &&
5840       AOP_SIZE (right) == 1)
5841     {
5842       genModOneByte (left, right, result);
5843       goto release;
5844     }
5845
5846   /* should have been converted to function call */
5847   assert (0);
5848
5849 release:
5850   freeAsmop (result, NULL, ic, TRUE);
5851   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5852   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5853 }
5854
5855 /*-----------------------------------------------------------------*/
5856 /* genIfxJump :- will create a jump depending on the ifx           */
5857 /*-----------------------------------------------------------------*/
5858 static void
5859 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result, iCode *popIc)
5860 {
5861   symbol *jlbl;
5862   symbol *tlbl = newiTempLabel (NULL);
5863   char *inst;
5864
5865   /* if there is something to be popped then do it first */
5866   popForBranch (popIc, TRUE);
5867
5868   D (emitcode (";", "genIfxJump"));
5869
5870   /* if true label then we jump if condition
5871      supplied is true */
5872   if (IC_TRUE (ic))
5873     {
5874       jlbl = IC_TRUE (ic);
5875       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5876                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5877     }
5878   else
5879     {
5880       /* false label is present */
5881       jlbl = IC_FALSE (ic);
5882       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5883                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5884     }
5885   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5886     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5887   else
5888     emitcode (inst, "%05d$", tlbl->key + 100);
5889   freeForBranchAsmop (result);
5890   freeForBranchAsmop (right);
5891   freeForBranchAsmop (left);
5892   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5893   emitLabel (tlbl);
5894
5895   /* mark the icode as generated */
5896   ic->generated = 1;
5897 }
5898
5899 /*-----------------------------------------------------------------*/
5900 /* genCmp :- greater or less than comparison                       */
5901 /*-----------------------------------------------------------------*/
5902 static void
5903 genCmp (operand * left, operand * right,
5904         operand * result, iCode * ifx, int sign, iCode *ic)
5905 {
5906   int size, offset = 0;
5907   unsigned long lit = 0L;
5908   bool rightInB;
5909
5910   D (emitcode (";", "genCmp"));
5911
5912   /* if left & right are bit variables */
5913   if (AOP_TYPE (left) == AOP_CRY &&
5914       AOP_TYPE (right) == AOP_CRY)
5915     {
5916       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5917       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5918     }
5919   else
5920     {
5921       /* subtract right from left if at the
5922          end the carry flag is set then we know that
5923          left is greater than right */
5924       size = max (AOP_SIZE (left), AOP_SIZE (right));
5925
5926       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5927       if ((size == 1) && !sign &&
5928           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5929         {
5930           symbol *lbl = newiTempLabel (NULL);
5931           emitcode ("cjne", "%s,%s,%05d$",
5932                     aopGet (left, offset, FALSE, FALSE),
5933                     aopGet (right, offset, FALSE, FALSE),
5934                     lbl->key + 100);
5935           emitLabel (lbl);
5936         }
5937       else
5938         {
5939           if (AOP_TYPE (right) == AOP_LIT)
5940             {
5941               lit = ulFromVal (AOP (right)->aopu.aop_lit);
5942               /* optimize if(x < 0) or if(x >= 0) */
5943               if (lit == 0L)
5944                 {
5945                   if (!sign)
5946                     {
5947                       CLRC;
5948                     }
5949                   else
5950                     {
5951                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5952                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5953                         {
5954                           genIfxJump (ifx, "acc.7", left, right, result, ic->next);
5955                           freeAsmop (right, NULL, ic, TRUE);
5956                           freeAsmop (left, NULL, ic, TRUE);
5957
5958                           return;
5959                         }
5960                       else
5961                         {
5962                           emitcode ("rlc", "a");
5963                         }
5964                     }
5965                   goto release;
5966                 }
5967               else
5968                 {//nonzero literal
5969                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5970                   while (size && (bytelit == 0))
5971                     {
5972                       offset++;
5973                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5974                       size--;
5975                     }
5976                   CLRC;
5977                   while (size--)
5978                     {
5979                       MOVA (aopGet (left, offset, FALSE, FALSE));
5980                       if (sign && size == 0)
5981                         {
5982                           emitcode ("xrl", "a,#0x80");
5983                           emitcode ("subb", "a,#0x%02x",
5984                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5985                         }
5986                       else
5987                         {
5988                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5989                         }
5990                       offset++;
5991                     }
5992                   goto release;
5993                 }
5994             }
5995           CLRC;
5996           while (size--)
5997             {
5998               bool pushedB = FALSE;
5999               rightInB = aopGetUsesAcc(right, offset);
6000               if (rightInB)
6001                 {
6002                   pushedB = pushB ();
6003                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
6004                 }
6005               MOVA (aopGet (left, offset, FALSE, FALSE));
6006               if (sign && size == 0)
6007                 {
6008                   emitcode ("xrl", "a,#0x80");
6009                   if (!rightInB)
6010                     {
6011                       pushedB = pushB ();
6012                       rightInB++;
6013                       MOVB (aopGet (right, offset, FALSE, FALSE));
6014                     }
6015                   emitcode ("xrl", "b,#0x80");
6016                   emitcode ("subb", "a,b");
6017                 }
6018               else
6019                 {
6020                   if (rightInB)
6021                     emitcode ("subb", "a,b");
6022                   else
6023                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
6024                 }
6025               if (rightInB)
6026                 popB (pushedB);
6027               offset++;
6028             }
6029         }
6030     }
6031
6032 release:
6033   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6034   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6035   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6036     {
6037       outBitC (result);
6038     }
6039   else
6040     {
6041       /* if the result is used in the next
6042          ifx conditional branch then generate
6043          code a little differently */
6044       if (ifx)
6045         {
6046           genIfxJump (ifx, "c", NULL, NULL, result, ic->next);
6047         }
6048       else
6049         {
6050           outBitC (result);
6051         }
6052       /* leave the result in acc */
6053     }
6054 }
6055
6056 /*-----------------------------------------------------------------*/
6057 /* genCmpGt :- greater than comparison                             */
6058 /*-----------------------------------------------------------------*/
6059 static void
6060 genCmpGt (iCode * ic, iCode * ifx)
6061 {
6062   operand *left, *right, *result;
6063   sym_link *letype, *retype;
6064   int sign;
6065
6066   D (emitcode (";", "genCmpGt"));
6067
6068   left = IC_LEFT (ic);
6069   right = IC_RIGHT (ic);
6070   result = IC_RESULT (ic);
6071
6072   letype = getSpec (operandType (left));
6073   retype = getSpec (operandType (right));
6074   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6075            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6076   /* assign the asmops */
6077   aopOp (result, ic, TRUE);
6078   aopOp (left, ic, FALSE);
6079   aopOp (right, ic, FALSE);
6080
6081   genCmp (right, left, result, ifx, sign, ic);
6082
6083   freeAsmop (result, NULL, ic, TRUE);
6084 }
6085
6086 /*-----------------------------------------------------------------*/
6087 /* genCmpLt - less than comparisons                                */
6088 /*-----------------------------------------------------------------*/
6089 static void
6090 genCmpLt (iCode * ic, iCode * ifx)
6091 {
6092   operand *left, *right, *result;
6093   sym_link *letype, *retype;
6094   int sign;
6095
6096   D (emitcode (";", "genCmpLt"));
6097
6098   left = IC_LEFT (ic);
6099   right = IC_RIGHT (ic);
6100   result = IC_RESULT (ic);
6101
6102   letype = getSpec (operandType (left));
6103   retype = getSpec (operandType (right));
6104   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6105            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6106   /* assign the asmops */
6107   aopOp (result, ic, TRUE);
6108   aopOp (left, ic, FALSE);
6109   aopOp (right, ic, FALSE);
6110
6111   genCmp (left, right, result, ifx, sign, ic);
6112
6113   freeAsmop (result, NULL, ic, TRUE);
6114 }
6115
6116 /*-----------------------------------------------------------------*/
6117 /* gencjneshort - compare and jump if not equal                    */
6118 /*-----------------------------------------------------------------*/
6119 static void
6120 gencjneshort (operand * left, operand * right, symbol * lbl)
6121 {
6122   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6123   int offset = 0;
6124   unsigned long lit = 0L;
6125
6126   D (emitcode (";", "gencjneshort"));
6127
6128   /* if the left side is a literal or
6129      if the right is in a pointer register and left
6130      is not */
6131   if ((AOP_TYPE (left) == AOP_LIT)  ||
6132       (AOP_TYPE (left) == AOP_IMMD) ||
6133       (AOP_TYPE (left) == AOP_DIR)  ||
6134       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6135     {
6136       operand *t = right;
6137       right = left;
6138       left = t;
6139     }
6140
6141   if (AOP_TYPE (right) == AOP_LIT)
6142     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6143
6144   /* if the right side is a literal then anything goes */
6145   if (AOP_TYPE (right) == AOP_LIT &&
6146       AOP_TYPE (left) != AOP_DIR  &&
6147       AOP_TYPE (left) != AOP_IMMD)
6148     {
6149       while (size--)
6150         {
6151           emitcode ("cjne", "%s,%s,%05d$",
6152                     aopGet (left, offset, FALSE, FALSE),
6153                     aopGet (right, offset, FALSE, FALSE),
6154                     lbl->key + 100);
6155           offset++;
6156         }
6157     }
6158
6159   /* if the right side is in a register or in direct space or
6160      if the left is a pointer register & right is not */
6161   else if (AOP_TYPE (right) == AOP_REG ||
6162            AOP_TYPE (right) == AOP_DIR ||
6163            AOP_TYPE (right) == AOP_LIT ||
6164            AOP_TYPE (right) == AOP_IMMD ||
6165            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6166            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6167     {
6168       while (size--)
6169         {
6170           MOVA (aopGet (left, offset, FALSE, FALSE));
6171           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6172               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6173             emitcode ("jnz", "%05d$", lbl->key + 100);
6174           else
6175             emitcode ("cjne", "a,%s,%05d$",
6176                       aopGet (right, offset, FALSE, TRUE),
6177                       lbl->key + 100);
6178           offset++;
6179         }
6180     }
6181   else
6182     {
6183       /* right is a pointer reg need both a & b */
6184       while (size--)
6185         {
6186           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6187           wassertl(!BINUSE, "B was in use");
6188           MOVB (aopGet (left, offset, FALSE, FALSE));
6189           MOVA (aopGet (right, offset, FALSE, FALSE));
6190           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6191           offset++;
6192         }
6193     }
6194 }
6195
6196 /*-----------------------------------------------------------------*/
6197 /* gencjne - compare and jump if not equal                         */
6198 /*-----------------------------------------------------------------*/
6199 static void
6200 gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
6201 {
6202   symbol *tlbl = newiTempLabel (NULL);
6203
6204   D (emitcode (";", "gencjne"));
6205
6206   gencjneshort (left, right, lbl);
6207
6208   if (useCarry)
6209       SETC;
6210   else
6211       MOVA (one);
6212   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6213   emitLabel (lbl);
6214   if (useCarry)
6215       CLRC;
6216   else
6217       MOVA (zero);
6218   emitLabel (tlbl);
6219 }
6220
6221 /*-----------------------------------------------------------------*/
6222 /* genCmpEq - generates code for equal to                          */
6223 /*-----------------------------------------------------------------*/
6224 static void
6225 genCmpEq (iCode * ic, iCode * ifx)
6226 {
6227   bool swappedLR = FALSE;
6228   operand *left, *right, *result;
6229   iCode * popIc = ic->next;
6230
6231   D (emitcode (";", "genCmpEq"));
6232
6233   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6234   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6235   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6236
6237   /* if literal, literal on the right or
6238      if the right is in a pointer register and left
6239      is not */
6240   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6241       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6242     {
6243       operand *t = IC_RIGHT (ic);
6244       IC_RIGHT (ic) = IC_LEFT (ic);
6245       IC_LEFT (ic) = t;
6246       swappedLR = TRUE;
6247     }
6248
6249   if (ifx && !AOP_SIZE (result))
6250     {
6251       symbol *tlbl;
6252       /* if they are both bit variables */
6253       if (AOP_TYPE (left) == AOP_CRY &&
6254           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6255         {
6256           if (AOP_TYPE (right) == AOP_LIT)
6257             {
6258               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6259               if (lit == 0L)
6260                 {
6261                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6262                   emitcode ("cpl", "c");
6263                 }
6264               else if (lit == 1L)
6265                 {
6266                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6267                 }
6268               else
6269                 {
6270                   emitcode ("clr", "c");
6271                 }
6272               /* AOP_TYPE(right) == AOP_CRY */
6273             }
6274           else
6275             {
6276               symbol *lbl = newiTempLabel (NULL);
6277               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6278               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6279               emitcode ("cpl", "c");
6280               emitLabel (lbl);
6281             }
6282           /* if true label then we jump if condition
6283              supplied is true */
6284           tlbl = newiTempLabel (NULL);
6285           if (IC_TRUE (ifx))
6286             {
6287               emitcode ("jnc", "%05d$", tlbl->key + 100);
6288               freeForBranchAsmop (result);
6289               freeForBranchAsmop (right);
6290               freeForBranchAsmop (left);
6291               popForBranch (popIc, FALSE);
6292               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6293             }
6294           else
6295             {
6296               emitcode ("jc", "%05d$", tlbl->key + 100);
6297               freeForBranchAsmop (result);
6298               freeForBranchAsmop (right);
6299               freeForBranchAsmop (left);
6300               popForBranch (popIc, FALSE);
6301               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6302             }
6303           emitLabel (tlbl);
6304         }
6305       else
6306         {
6307           tlbl = newiTempLabel (NULL);
6308           gencjneshort (left, right, tlbl);
6309           if (IC_TRUE (ifx))
6310             {
6311               freeForBranchAsmop (result);
6312               freeForBranchAsmop (right);
6313               freeForBranchAsmop (left);
6314               popForBranch (popIc, FALSE);
6315               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6316               emitLabel (tlbl);
6317             }
6318           else
6319             {
6320               symbol *lbl = newiTempLabel (NULL);
6321               emitcode ("sjmp", "%05d$", lbl->key + 100);
6322               emitLabel (tlbl);
6323               freeForBranchAsmop (result);
6324               freeForBranchAsmop (right);
6325               freeForBranchAsmop (left);
6326               popForBranch (popIc, FALSE);
6327               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6328               emitLabel (lbl);
6329             }
6330         }
6331       /* mark the icode as generated */
6332       ifx->generated = 1;
6333       goto release;
6334     }
6335
6336   /* if they are both bit variables */
6337   if (AOP_TYPE (left) == AOP_CRY &&
6338       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6339     {
6340       if (AOP_TYPE (right) == AOP_LIT)
6341         {
6342           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6343           if (lit == 0L)
6344             {
6345               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6346               emitcode ("cpl", "c");
6347             }
6348           else if (lit == 1L)
6349             {
6350               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6351             }
6352           else
6353             {
6354               emitcode ("clr", "c");
6355             }
6356           /* AOP_TYPE(right) == AOP_CRY */
6357         }
6358       else
6359         {
6360           symbol *lbl = newiTempLabel (NULL);
6361           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6362           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6363           emitcode ("cpl", "c");
6364           emitLabel (lbl);
6365         }
6366       /* c = 1 if egal */
6367       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6368         {
6369           outBitC (result);
6370           goto release;
6371         }
6372       if (ifx)
6373         {
6374           genIfxJump (ifx, "c", left, right, result, popIc);
6375           goto release;
6376         }
6377       /* if the result is used in an arithmetic operation
6378          then put the result in place */
6379       outBitC (result);
6380     }
6381   else
6382     {
6383       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6384         {
6385           gencjne (left, right, newiTempLabel (NULL), TRUE);
6386           aopPut (result, "c", 0);
6387           goto release;
6388         }
6389       gencjne (left, right, newiTempLabel (NULL), FALSE);
6390       if (ifx)
6391         {
6392           genIfxJump (ifx, "a", left, right, result, popIc);
6393           goto release;
6394         }
6395       /* if the result is used in an arithmetic operation
6396          then put the result in place */
6397       if (AOP_TYPE (result) != AOP_CRY)
6398         outAcc (result);
6399       /* leave the result in acc */
6400     }
6401
6402 release:
6403   freeAsmop (result, NULL, ic, TRUE);
6404   if (!swappedLR)
6405     {
6406       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6407       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6408     }
6409   else
6410     {
6411       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6412       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6413     }
6414 }
6415
6416 /*-----------------------------------------------------------------*/
6417 /* ifxForOp - returns the icode containing the ifx for operand     */
6418 /*-----------------------------------------------------------------*/
6419 static iCode *
6420 ifxForOp (operand * op, iCode * ic)
6421 {
6422   iCode *ifxIc;
6423
6424   /* if true symbol then needs to be assigned */
6425   if (IS_TRUE_SYMOP (op))
6426     return NULL;
6427
6428   /* if this has register type condition and
6429      while skipping ipop's (see bug 1509084),
6430      the next instruction is ifx with the same operand
6431      and live to of the operand is upto the ifx only then */
6432   for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next);
6433   if (ifxIc && ifxIc->op == IFX &&
6434       IC_COND (ifxIc)->key == op->key &&
6435       OP_SYMBOL (op)->liveTo <= ifxIc->seq)
6436     return ifxIc;
6437
6438   return NULL;
6439 }
6440
6441 /*-----------------------------------------------------------------*/
6442 /* hasInc - operand is incremented before any other use            */
6443 /*-----------------------------------------------------------------*/
6444 static iCode *
6445 hasInc (operand *op, iCode *ic, int osize)
6446 {
6447   sym_link *type = operandType(op);
6448   sym_link *retype = getSpec (type);
6449   iCode *lic = ic->next;
6450   int isize ;
6451
6452   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6453   if (!IS_SYMOP(op)) return NULL;
6454
6455   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6456   if (IS_AGGREGATE(type->next)) return NULL;
6457   if (osize != (isize = getSize(type->next))) return NULL;
6458
6459   while (lic)
6460     {
6461       /* if operand of the form op = op + <sizeof *op> */
6462       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6463           isOperandEqual(IC_RESULT(lic),op) &&
6464           isOperandLiteral(IC_RIGHT(lic)) &&
6465           operandLitValue(IC_RIGHT(lic)) == isize)
6466         {
6467           return lic;
6468         }
6469       /* if the operand used or deffed */
6470       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key)
6471         {
6472           return NULL;
6473         }
6474       /* if GOTO or IFX */
6475       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6476       lic = lic->next;
6477     }
6478   return NULL;
6479 }
6480
6481 /*-----------------------------------------------------------------*/
6482 /* genAndOp - for && operation                                     */
6483 /*-----------------------------------------------------------------*/
6484 static void
6485 genAndOp (iCode * ic)
6486 {
6487   operand *left, *right, *result;
6488   symbol *tlbl;
6489
6490   D (emitcode (";", "genAndOp"));
6491
6492   /* note here that && operations that are in an
6493      if statement are taken away by backPatchLabels
6494      only those used in arthmetic operations remain */
6495   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6496   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6497   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6498
6499   /* if both are bit variables */
6500   if (AOP_TYPE (left) == AOP_CRY &&
6501       AOP_TYPE (right) == AOP_CRY)
6502     {
6503       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6504       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6505       outBitC (result);
6506     }
6507   else
6508     {
6509       tlbl = newiTempLabel (NULL);
6510       toBoolean (left);
6511       emitcode ("jz", "%05d$", tlbl->key + 100);
6512       toBoolean (right);
6513       emitLabel (tlbl);
6514       outBitAcc (result);
6515     }
6516
6517   freeAsmop (result, NULL, ic, TRUE);
6518   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6519   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6520 }
6521
6522
6523 /*-----------------------------------------------------------------*/
6524 /* genOrOp - for || operation                                      */
6525 /*-----------------------------------------------------------------*/
6526 static void
6527 genOrOp (iCode * ic)
6528 {
6529   operand *left, *right, *result;
6530   symbol *tlbl;
6531
6532   D (emitcode (";", "genOrOp"));
6533
6534   /* note here that || operations that are in an
6535      if statement are taken away by backPatchLabels
6536      only those used in arthmetic operations remain */
6537   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6538   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6539   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6540
6541   /* if both are bit variables */
6542   if (AOP_TYPE (left) == AOP_CRY &&
6543       AOP_TYPE (right) == AOP_CRY)
6544     {
6545       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6546       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6547       outBitC (result);
6548     }
6549   else
6550     {
6551       tlbl = newiTempLabel (NULL);
6552       toBoolean (left);
6553       emitcode ("jnz", "%05d$", tlbl->key + 100);
6554       toBoolean (right);
6555       emitLabel (tlbl);
6556       outBitAcc (result);
6557     }
6558
6559   freeAsmop (result, NULL, ic, TRUE);
6560   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6561   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6562 }
6563
6564 /*-----------------------------------------------------------------*/
6565 /* isLiteralBit - test if lit == 2^n                               */
6566 /*-----------------------------------------------------------------*/
6567 static int
6568 isLiteralBit (unsigned long lit)
6569 {
6570   unsigned long pw[32] =
6571   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6572    0x100L, 0x200L, 0x400L, 0x800L,
6573    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6574    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6575    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6576    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6577    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6578   int idx;
6579
6580   for (idx = 0; idx < 32; idx++)
6581     if (lit == pw[idx])
6582       return idx + 1;
6583   return 0;
6584 }
6585
6586 /*-----------------------------------------------------------------*/
6587 /* continueIfTrue -                                                */
6588 /*-----------------------------------------------------------------*/
6589 static void
6590 continueIfTrue (iCode * ic)
6591 {
6592   if (IC_TRUE (ic))
6593     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6594   ic->generated = 1;
6595 }
6596
6597 /*-----------------------------------------------------------------*/
6598 /* jmpIfTrue -                                                     */
6599 /*-----------------------------------------------------------------*/
6600 static void
6601 jumpIfTrue (iCode * ic)
6602 {
6603   if (!IC_TRUE (ic))
6604     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6605   ic->generated = 1;
6606 }
6607
6608 /*-----------------------------------------------------------------*/
6609 /* jmpTrueOrFalse -                                                */
6610 /*-----------------------------------------------------------------*/
6611 static void
6612 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6613 {
6614   // ugly but optimized by peephole
6615   if (IC_TRUE (ic))
6616     {
6617       symbol *nlbl = newiTempLabel (NULL);
6618       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6619       emitLabel (tlbl);
6620       freeForBranchAsmop (result);
6621       freeForBranchAsmop (right);
6622       freeForBranchAsmop (left);
6623       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6624       emitLabel (nlbl);
6625     }
6626   else
6627     {
6628       freeForBranchAsmop (result);
6629       freeForBranchAsmop (right);
6630       freeForBranchAsmop (left);
6631       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6632       emitLabel (tlbl);
6633     }
6634   ic->generated = 1;
6635 }
6636
6637 /*-----------------------------------------------------------------*/
6638 /* genAnd  - code for and                                          */
6639 /*-----------------------------------------------------------------*/
6640 static void
6641 genAnd (iCode * ic, iCode * ifx)
6642 {
6643   operand *left, *right, *result;
6644   int size, offset = 0;
6645   unsigned long lit = 0L;
6646   int bytelit = 0;
6647   char buffer[10];
6648
6649   D (emitcode (";", "genAnd"));
6650
6651   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6652   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6653   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6654
6655 #ifdef DEBUG_TYPE
6656   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6657             AOP_TYPE (result),
6658             AOP_TYPE (left), AOP_TYPE (right));
6659   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6660             AOP_SIZE (result),
6661             AOP_SIZE (left), AOP_SIZE (right));
6662 #endif
6663
6664   /* if left is a literal & right is not then exchange them */
6665   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6666       AOP_NEEDSACC (left))
6667     {
6668       operand *tmp = right;
6669       right = left;
6670       left = tmp;
6671     }
6672
6673   /* if result = right then exchange left and right */
6674   if (sameRegs (AOP (result), AOP (right)))
6675     {
6676       operand *tmp = right;
6677       right = left;
6678       left = tmp;
6679     }
6680
6681   /* if right is bit then exchange them */
6682   if (AOP_TYPE (right) == AOP_CRY &&
6683       AOP_TYPE (left) != AOP_CRY)
6684     {
6685       operand *tmp = right;
6686       right = left;
6687       left = tmp;
6688     }
6689   if (AOP_TYPE (right) == AOP_LIT)
6690     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6691
6692   size = AOP_SIZE (result);
6693
6694   // if(bit & yy)
6695   // result = bit & yy;
6696   if (AOP_TYPE (left) == AOP_CRY)
6697     {
6698       // c = bit & literal;
6699       if (AOP_TYPE (right) == AOP_LIT)
6700         {
6701           if (lit & 1)
6702             {
6703               if (size && sameRegs (AOP (result), AOP (left)))
6704                 // no change
6705                 goto release;
6706               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6707             }
6708           else
6709             {
6710               // bit(result) = 0;
6711               if (size && (AOP_TYPE (result) == AOP_CRY))
6712                 {
6713                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6714                   goto release;
6715                 }
6716               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6717                 {
6718                   jumpIfTrue (ifx);
6719                   goto release;
6720                 }
6721               emitcode ("clr", "c");
6722             }
6723         }
6724       else
6725         {
6726           if (AOP_TYPE (right) == AOP_CRY)
6727             {
6728               // c = bit & bit;
6729               if (IS_OP_ACCUSE (left))
6730                 {
6731                   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6732                 }
6733               else
6734                 {
6735                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6736                   emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6737                 }
6738             }
6739           else
6740             {
6741               // c = bit & val;
6742               MOVA (aopGet (right, 0, FALSE, FALSE));
6743               // c = lsb
6744               emitcode ("rrc", "a");
6745               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6746             }
6747         }
6748       // bit = c
6749       // val = c
6750       if (size)
6751         outBitC (result);
6752       // if(bit & ...)
6753       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6754         genIfxJump (ifx, "c", left, right, result, ic->next);
6755       goto release;
6756     }
6757
6758   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6759   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6760   if ((AOP_TYPE (right) == AOP_LIT) &&
6761       (AOP_TYPE (result) == AOP_CRY) &&
6762       (AOP_TYPE (left) != AOP_CRY))
6763     {
6764       int posbit = isLiteralBit (lit);
6765       /* left &  2^n */
6766       if (posbit)
6767         {
6768           posbit--;
6769           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6770           // bit = left & 2^n
6771           if (size)
6772             {
6773               switch (posbit & 0x07)
6774                 {
6775                   case 0: emitcode ("rrc", "a");
6776                           break;
6777                   case 7: emitcode ("rlc", "a");
6778                           break;
6779                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6780                           break;
6781                 }
6782             }
6783           // if(left &  2^n)
6784           else
6785             {
6786               if (ifx)
6787                 {
6788                   SNPRINTF (buffer, sizeof(buffer),
6789                             "acc.%d", posbit & 0x07);
6790                   genIfxJump (ifx, buffer, left, right, result, ic->next);
6791                 }
6792               else
6793                 {// what is this case? just found it in ds390/gen.c
6794                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6795                 }
6796               goto release;
6797             }
6798         }
6799       else
6800         {
6801           symbol *tlbl = newiTempLabel (NULL);
6802           int sizel = AOP_SIZE (left);
6803           if (size)
6804             emitcode ("setb", "c");
6805           while (sizel--)
6806             {
6807               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6808                 {
6809                   MOVA (aopGet (left, offset, FALSE, FALSE));
6810                   // byte ==  2^n ?
6811                   if ((posbit = isLiteralBit (bytelit)) != 0)
6812                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6813                   else
6814                     {
6815                       if (bytelit != 0x0FFL)
6816                         emitcode ("anl", "a,%s",
6817                                   aopGet (right, offset, FALSE, TRUE));
6818                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6819                     }
6820                 }
6821               offset++;
6822             }
6823           // bit = left & literal
6824           if (size)
6825             {
6826               emitcode ("clr", "c");
6827               emitLabel (tlbl);
6828             }
6829           // if(left & literal)
6830           else
6831             {
6832               if (ifx)
6833                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6834               else
6835                 emitLabel (tlbl);
6836               goto release;
6837             }
6838         }
6839       outBitC (result);
6840       goto release;
6841     }
6842
6843   /* if left is same as result */
6844   if (sameRegs (AOP (result), AOP (left)))
6845     {
6846       for (; size--; offset++)
6847         {
6848           if (AOP_TYPE (right) == AOP_LIT)
6849             {
6850               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6851               if (bytelit == 0x0FF)
6852                 {
6853                   /* dummy read of volatile operand */
6854                   if (isOperandVolatile (left, FALSE))
6855                     MOVA (aopGet (left, offset, FALSE, FALSE));
6856                   else
6857                     continue;
6858                 }
6859               else if (bytelit == 0)
6860                 {
6861                   aopPut (result, zero, offset);
6862                 }
6863               else if (IS_AOP_PREG (result))
6864                 {
6865                   MOVA (aopGet (left, offset, FALSE, TRUE));
6866                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6867                   aopPut (result, "a", offset);
6868                 }
6869               else
6870                 emitcode ("anl", "%s,%s",
6871                           aopGet (left, offset, FALSE, TRUE),
6872                           aopGet (right, offset, FALSE, FALSE));
6873             }
6874           else
6875             {
6876               if (AOP_TYPE (left) == AOP_ACC)
6877                 {
6878                   if (offset)
6879                     emitcode("mov", "a,b");
6880                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6881                 }
6882               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6883                 {
6884                   MOVB (aopGet (left, offset, FALSE, FALSE));
6885                   MOVA (aopGet (right, offset, FALSE, FALSE));
6886                   emitcode ("anl", "a,b");
6887                   aopPut (result, "a", offset);
6888                 }
6889               else if (aopGetUsesAcc (left, offset))
6890                 {
6891                   MOVA (aopGet (left, offset, FALSE, FALSE));
6892                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6893                   aopPut (result, "a", offset);
6894                 }
6895               else
6896                 {
6897                   MOVA (aopGet (right, offset, FALSE, FALSE));
6898                   if (IS_AOP_PREG (result))
6899                     {
6900                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6901                       aopPut (result, "a", offset);
6902                     }
6903                   else
6904                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6905                 }
6906             }
6907         }
6908     }
6909   else
6910     {
6911       // left & result in different registers
6912       if (AOP_TYPE (result) == AOP_CRY)
6913         {
6914           // result = bit
6915           // if(size), result in bit
6916           // if(!size && ifx), conditional oper: if(left & right)
6917           symbol *tlbl = newiTempLabel (NULL);
6918           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6919           if (size)
6920             emitcode ("setb", "c");
6921           while (sizer--)
6922             {
6923               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6924                   && AOP_TYPE(left)==AOP_ACC)
6925                 {
6926                   if (offset)
6927                     emitcode("mov", "a,b");
6928                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6929                 }
6930               else if (AOP_TYPE(left)==AOP_ACC)
6931                 {
6932                   if (!offset)
6933                     {
6934                       bool pushedB = pushB ();
6935                       emitcode("mov", "b,a");
6936                       MOVA (aopGet (right, offset, FALSE, FALSE));
6937                       emitcode("anl", "a,b");
6938                       popB (pushedB);
6939                     }
6940                   else
6941                     {
6942                       MOVA (aopGet (right, offset, FALSE, FALSE));
6943                       emitcode("anl", "a,b");
6944                     }
6945                 }
6946               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6947                 {
6948                   MOVB (aopGet (left, offset, FALSE, FALSE));
6949                   MOVA (aopGet (right, offset, FALSE, FALSE));
6950                   emitcode ("anl", "a,b");
6951                 }
6952               else if (aopGetUsesAcc (left, offset))
6953                 {
6954                   MOVA (aopGet (left, offset, FALSE, FALSE));
6955                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6956                 }
6957               else
6958                 {
6959                   MOVA (aopGet (right, offset, FALSE, FALSE));
6960                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6961                 }
6962
6963               emitcode ("jnz", "%05d$", tlbl->key + 100);
6964               offset++;
6965             }
6966           if (size)
6967             {
6968               CLRC;
6969               emitLabel (tlbl);
6970               outBitC (result);
6971             }
6972           else if (ifx)
6973             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6974           else
6975             emitLabel (tlbl);
6976         }
6977       else
6978         {
6979           for (; (size--); offset++)
6980             {
6981               // normal case
6982               // result = left & right
6983               if (AOP_TYPE (right) == AOP_LIT)
6984                 {
6985                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6986                   if (bytelit == 0x0FF)
6987                     {
6988                       aopPut (result,
6989                               aopGet (left, offset, FALSE, FALSE),
6990                               offset);
6991                       continue;
6992                     }
6993                   else if (bytelit == 0)
6994                     {
6995                       /* dummy read of volatile operand */
6996                       if (isOperandVolatile (left, FALSE))
6997                         MOVA (aopGet (left, offset, FALSE, FALSE));
6998                       aopPut (result, zero, offset);
6999                       continue;
7000                     }
7001                   else if (AOP_TYPE (left) == AOP_ACC)
7002                     {
7003                       if (!offset)
7004                         {
7005                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7006                           aopPut (result, "a", offset);
7007                           continue;
7008                         }
7009                       else
7010                         {
7011                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
7012                           aopPut (result, "b", offset);
7013                           continue;
7014                         }
7015                     }
7016                 }
7017               // faster than result <- left, anl result,right
7018               // and better if result is SFR
7019               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7020                   && AOP_TYPE(left)==AOP_ACC)
7021                 {
7022                   if (offset)
7023                     emitcode("mov", "a,b");
7024                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7025                 }
7026               else if (AOP_TYPE(left)==AOP_ACC)
7027                 {
7028                   if (!offset)
7029                     {
7030                       bool pushedB = pushB ();
7031                       emitcode("mov", "b,a");
7032                       MOVA (aopGet (right, offset, FALSE, FALSE));
7033                       emitcode("anl", "a,b");
7034                       popB (pushedB);
7035                     }
7036                   else
7037                     {
7038                       MOVA (aopGet (right, offset, FALSE, FALSE));
7039                       emitcode("anl", "a,b");
7040                     }
7041                 }
7042               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7043                 {
7044                   MOVB (aopGet (left, offset, FALSE, FALSE));
7045                   MOVA (aopGet (right, offset, FALSE, FALSE));
7046                   emitcode ("anl", "a,b");
7047                 }
7048               else if (aopGetUsesAcc (left, offset))
7049                 {
7050                   MOVA (aopGet (left, offset, FALSE, FALSE));
7051                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7052                 }
7053               else
7054                 {
7055                   MOVA (aopGet (right, offset, FALSE, FALSE));
7056                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7057                 }
7058               aopPut (result, "a", offset);
7059             }
7060         }
7061     }
7062
7063 release:
7064   freeAsmop (result, NULL, ic, TRUE);
7065   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7066   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7067 }
7068
7069 /*-----------------------------------------------------------------*/
7070 /* genOr  - code for or                                            */
7071 /*-----------------------------------------------------------------*/
7072 static void
7073 genOr (iCode * ic, iCode * ifx)
7074 {
7075   operand *left, *right, *result;
7076   int size, offset = 0;
7077   unsigned long lit = 0L;
7078   int bytelit = 0;
7079
7080   D (emitcode (";", "genOr"));
7081
7082   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7083   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7084   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7085
7086 #ifdef DEBUG_TYPE
7087   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7088             AOP_TYPE (result),
7089             AOP_TYPE (left), AOP_TYPE (right));
7090   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7091             AOP_SIZE (result),
7092             AOP_SIZE (left), AOP_SIZE (right));
7093 #endif
7094
7095   /* if left is a literal & right is not then exchange them */
7096   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7097       AOP_NEEDSACC (left))
7098     {
7099       operand *tmp = right;
7100       right = left;
7101       left = tmp;
7102     }
7103
7104   /* if result = right then exchange them */
7105   if (sameRegs (AOP (result), AOP (right)))
7106     {
7107       operand *tmp = right;
7108       right = left;
7109       left = tmp;
7110     }
7111
7112   /* if right is bit then exchange them */
7113   if (AOP_TYPE (right) == AOP_CRY &&
7114       AOP_TYPE (left) != AOP_CRY)
7115     {
7116       operand *tmp = right;
7117       right = left;
7118       left = tmp;
7119     }
7120   if (AOP_TYPE (right) == AOP_LIT)
7121     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7122
7123   size = AOP_SIZE (result);
7124
7125   // if(bit | yy)
7126   // xx = bit | yy;
7127   if (AOP_TYPE (left) == AOP_CRY)
7128     {
7129       if (AOP_TYPE (right) == AOP_LIT)
7130         {
7131           // c = bit | literal;
7132           if (lit)
7133             {
7134               // lit != 0 => result = 1
7135               if (AOP_TYPE (result) == AOP_CRY)
7136                 {
7137                   if (size)
7138                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7139                   else if (ifx)
7140                     continueIfTrue (ifx);
7141                   goto release;
7142                 }
7143               emitcode ("setb", "c");
7144             }
7145           else
7146             {
7147               // lit == 0 => result = left
7148               if (size && sameRegs (AOP (result), AOP (left)))
7149                 goto release;
7150               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7151             }
7152         }
7153       else
7154         {
7155           if (AOP_TYPE (right) == AOP_CRY)
7156             {
7157               // c = bit | bit;
7158               if (IS_OP_ACCUSE (left))
7159                 {
7160                   emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7161                 }
7162               else
7163                 {
7164                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7165                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7166                 }
7167             }
7168           else
7169             {
7170               // c = bit | val;
7171               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7172                 {
7173                   symbol *tlbl = newiTempLabel (NULL);
7174                   emitcode ("jb", "%s,%05d$",
7175                             AOP (left)->aopu.aop_dir, tlbl->key + 100);
7176                   toBoolean (right);
7177                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7178                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7179                   goto release;
7180                 }
7181               else
7182                 {
7183                   toCarry (right);
7184                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7185                 }
7186             }
7187         }
7188       // bit = c
7189       // val = c
7190       if (size)
7191         outBitC (result);
7192       // if(bit | ...)
7193       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7194         genIfxJump (ifx, "c", left, right, result, ic->next);
7195       goto release;
7196     }
7197
7198   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7199   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7200   if ((AOP_TYPE (right) == AOP_LIT) &&
7201       (AOP_TYPE (result) == AOP_CRY) &&
7202       (AOP_TYPE (left) != AOP_CRY))
7203     {
7204       if (lit)
7205         {
7206           // result = 1
7207           if (size)
7208             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7209           else
7210             continueIfTrue (ifx);
7211           goto release;
7212         }
7213       else
7214         {
7215           // lit = 0, result = boolean(left)
7216           if (size)
7217             emitcode ("setb", "c");
7218           toBoolean (right);
7219           if (size)
7220             {
7221               symbol *tlbl = newiTempLabel (NULL);
7222               emitcode ("jnz", "%05d$", tlbl->key + 100);
7223               CLRC;
7224               emitLabel (tlbl);
7225             }
7226           else
7227             {
7228               genIfxJump (ifx, "a", left, right, result, ic->next);
7229               goto release;
7230             }
7231         }
7232       outBitC (result);
7233       goto release;
7234     }
7235
7236   /* if left is same as result */
7237   if (sameRegs (AOP (result), AOP (left)))
7238     {
7239       for (; size--; offset++)
7240         {
7241           if (AOP_TYPE (right) == AOP_LIT)
7242             {
7243               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7244               if (bytelit == 0)
7245                 {
7246                   /* dummy read of volatile operand */
7247                   if (isOperandVolatile (left, FALSE))
7248                     MOVA (aopGet (left, offset, FALSE, FALSE));
7249                   else
7250                     continue;
7251                 }
7252               else if (bytelit == 0x0FF)
7253                 {
7254                   aopPut (result, "#0xff", offset);
7255                 }
7256               else if (IS_AOP_PREG (left))
7257                 {
7258                   MOVA (aopGet (left, offset, FALSE, TRUE));
7259                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7260                   aopPut (result, "a", offset);
7261                 }
7262               else
7263                 {
7264                   emitcode ("orl", "%s,%s",
7265                             aopGet (left, offset, FALSE, TRUE),
7266                             aopGet (right, offset, FALSE, FALSE));
7267                 }
7268             }
7269           else
7270             {
7271               if (AOP_TYPE (left) == AOP_ACC)
7272                 {
7273                   if (offset)
7274                     emitcode("mov", "a,b");
7275                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7276                 }
7277               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7278                 {
7279                   MOVB (aopGet (left, offset, FALSE, FALSE));
7280                   MOVA (aopGet (right, offset, FALSE, FALSE));
7281                   emitcode ("orl", "a,b");
7282                   aopPut (result, "a", offset);
7283                 }
7284               else if (aopGetUsesAcc (left, offset))
7285                 {
7286                   MOVA (aopGet (left, offset, FALSE, FALSE));
7287                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7288                   aopPut (result, "a", offset);
7289                 }
7290               else
7291                 {
7292                   MOVA (aopGet (right, offset, FALSE, FALSE));
7293                   if (IS_AOP_PREG (left))
7294                     {
7295                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7296                       aopPut (result, "a", offset);
7297                     }
7298                   else
7299                     {
7300                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7301                     }
7302                 }
7303             }
7304         }
7305     }
7306   else
7307     {
7308       // left & result in different registers
7309       if (AOP_TYPE (result) == AOP_CRY)
7310         {
7311           // result = bit
7312           // if(size), result in bit
7313           // if(!size && ifx), conditional oper: if(left | right)
7314           symbol *tlbl = newiTempLabel (NULL);
7315           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7316           if (size)
7317             emitcode ("setb", "c");
7318           while (sizer--)
7319             {
7320               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7321                   && AOP_TYPE(left)==AOP_ACC)
7322                 {
7323                   if (offset)
7324                     emitcode("mov", "a,b");
7325                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7326                 }
7327               else if (AOP_TYPE(left)==AOP_ACC)
7328                 {
7329                   if (!offset)
7330                     {
7331                       bool pushedB = pushB ();
7332                       emitcode("mov", "b,a");
7333                       MOVA (aopGet (right, offset, FALSE, FALSE));
7334                       emitcode("orl", "a,b");
7335                       popB (pushedB);
7336                     }
7337                   else
7338                     {
7339                       MOVA (aopGet (right, offset, FALSE, FALSE));
7340                       emitcode("orl", "a,b");
7341                     }
7342                 }
7343               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7344                 {
7345                   MOVB (aopGet (left, offset, FALSE, FALSE));
7346                   MOVA (aopGet (right, offset, FALSE, FALSE));
7347                   emitcode ("orl", "a,b");
7348                 }
7349               else if (aopGetUsesAcc (left, offset))
7350                 {
7351                   MOVA (aopGet (left, offset, FALSE, FALSE));
7352                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7353                 }
7354               else
7355                 {
7356                   MOVA (aopGet (right, offset, FALSE, FALSE));
7357                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7358               }
7359
7360               emitcode ("jnz", "%05d$", tlbl->key + 100);
7361               offset++;
7362             }
7363           if (size)
7364             {
7365               CLRC;
7366               emitLabel (tlbl);
7367               outBitC (result);
7368             }
7369           else if (ifx)
7370             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7371           else
7372             emitLabel (tlbl);
7373         }
7374       else
7375         {
7376           for (; (size--); offset++)
7377             {
7378               // normal case
7379               // result = left | right
7380               if (AOP_TYPE (right) == AOP_LIT)
7381                 {
7382                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7383                   if (bytelit == 0)
7384                     {
7385                       aopPut (result,
7386                               aopGet (left, offset, FALSE, FALSE),
7387                               offset);
7388                       continue;
7389                     }
7390                   else if (bytelit == 0x0FF)
7391                     {
7392                       /* dummy read of volatile operand */
7393                       if (isOperandVolatile (left, FALSE))
7394                         MOVA (aopGet (left, offset, FALSE, FALSE));
7395                       aopPut (result, "#0xff", offset);
7396                       continue;
7397                     }
7398                 }
7399               // faster than result <- left, orl result,right
7400               // and better if result is SFR
7401               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7402                   && AOP_TYPE(left)==AOP_ACC)
7403                 {
7404                   if (offset)
7405                     emitcode("mov", "a,b");
7406                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7407                 }
7408               else if (AOP_TYPE(left)==AOP_ACC)
7409                 {
7410                   if (!offset)
7411                     {
7412                       bool pushedB = pushB ();
7413                       emitcode("mov", "b,a");
7414                       MOVA (aopGet (right, offset, FALSE, FALSE));
7415                       emitcode("orl", "a,b");
7416                       popB (pushedB);
7417                     }
7418                   else
7419                     {
7420                       MOVA (aopGet (right, offset, FALSE, FALSE));
7421                       emitcode("orl", "a,b");
7422                     }
7423                 }
7424               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7425                 {
7426                   MOVB (aopGet (left, offset, FALSE, FALSE));
7427                   MOVA (aopGet (right, offset, FALSE, FALSE));
7428                   emitcode ("orl", "a,b");
7429                 }
7430               else if (aopGetUsesAcc (left, offset))
7431                 {
7432                   MOVA (aopGet (left, offset, FALSE, FALSE));
7433                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7434                 }
7435               else
7436                 {
7437                   MOVA (aopGet (right, offset, FALSE, FALSE));
7438                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7439                 }
7440               aopPut (result, "a", offset);
7441             }
7442         }
7443     }
7444
7445 release:
7446   freeAsmop (result, NULL, ic, TRUE);
7447   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7448   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7449 }
7450
7451 /*-----------------------------------------------------------------*/
7452 /* genXor - code for xclusive or                                   */
7453 /*-----------------------------------------------------------------*/
7454 static void
7455 genXor (iCode * ic, iCode * ifx)
7456 {
7457   operand *left, *right, *result;
7458   int size, offset = 0;
7459   unsigned long lit = 0L;
7460   int bytelit = 0;
7461
7462   D (emitcode (";", "genXor"));
7463
7464   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7465   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7466   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7467
7468 #ifdef DEBUG_TYPE
7469   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7470             AOP_TYPE (result),
7471             AOP_TYPE (left), AOP_TYPE (right));
7472   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7473             AOP_SIZE (result),
7474             AOP_SIZE (left), AOP_SIZE (right));
7475 #endif
7476
7477   /* if left is a literal & right is not ||
7478      if left needs acc & right does not */
7479   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7480       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7481     {
7482       operand *tmp = right;
7483       right = left;
7484       left = tmp;
7485     }
7486
7487   /* if result = right then exchange them */
7488   if (sameRegs (AOP (result), AOP (right)))
7489     {
7490       operand *tmp = right;
7491       right = left;
7492       left = tmp;
7493     }
7494
7495   /* if right is bit then exchange them */
7496   if (AOP_TYPE (right) == AOP_CRY &&
7497       AOP_TYPE (left) != AOP_CRY)
7498     {
7499       operand *tmp = right;
7500       right = left;
7501       left = tmp;
7502     }
7503
7504   if (AOP_TYPE (right) == AOP_LIT)
7505     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7506
7507   size = AOP_SIZE (result);
7508
7509   // if(bit ^ yy)
7510   // xx = bit ^ yy;
7511   if (AOP_TYPE (left) == AOP_CRY)
7512     {
7513       if (AOP_TYPE (right) == AOP_LIT)
7514         {
7515           // c = bit & literal;
7516           if (lit >> 1)
7517             {
7518               // lit>>1  != 0 => result = 1
7519               if (AOP_TYPE (result) == AOP_CRY)
7520                 {
7521                   if (size)
7522                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7523                   else if (ifx)
7524                     continueIfTrue (ifx);
7525                   goto release;
7526                 }
7527               emitcode ("setb", "c");
7528             }
7529           else
7530             {
7531               // lit == (0 or 1)
7532               if (lit == 0)
7533                 {
7534                   // lit == 0, result = left
7535                   if (size && sameRegs (AOP (result), AOP (left)))
7536                     goto release;
7537                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7538                 }
7539               else
7540                 {
7541                   // lit == 1, result = not(left)
7542                   if (size && sameRegs (AOP (result), AOP (left)))
7543                     {
7544                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7545                       goto release;
7546                     }
7547                   else
7548                     {
7549                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7550                       emitcode ("cpl", "c");
7551                     }
7552                 }
7553             }
7554         }
7555       else
7556         {
7557           // right != literal
7558           symbol *tlbl = newiTempLabel (NULL);
7559           if (AOP_TYPE (right) == AOP_CRY)
7560             {
7561               // c = bit ^ bit;
7562               if (IS_OP_ACCUSE (left))
7563                 {// left already is in the carry
7564                   operand *tmp = right;
7565                   right = left;
7566                   left = tmp;
7567                 }
7568               else
7569                 {
7570                   toCarry (right);
7571                 }
7572             }
7573           else
7574             {
7575               // c = bit ^ val
7576               toCarry (right);
7577             }
7578           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7579           emitcode ("cpl", "c");
7580           emitLabel (tlbl);
7581         }
7582       // bit = c
7583       // val = c
7584       if (size)
7585         outBitC (result);
7586       // if(bit ^ ...)
7587       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7588         genIfxJump (ifx, "c", left, right, result, ic->next);
7589       goto release;
7590     }
7591
7592   /* if left is same as result */
7593   if (sameRegs (AOP (result), AOP (left)))
7594     {
7595       for (; size--; offset++)
7596         {
7597           if (AOP_TYPE (right) == AOP_LIT)
7598             {
7599               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7600               if (bytelit == 0)
7601                 {
7602                   /* dummy read of volatile operand */
7603                   if (isOperandVolatile (left, FALSE))
7604                     MOVA (aopGet (left, offset, FALSE, FALSE));
7605                   else
7606                     continue;
7607                 }
7608               else if (IS_AOP_PREG (left))
7609                 {
7610                   MOVA (aopGet (left, offset, FALSE, TRUE));
7611                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7612                   aopPut (result, "a", offset);
7613                 }
7614               else
7615                 {
7616                   emitcode ("xrl", "%s,%s",
7617                             aopGet (left, offset, FALSE, TRUE),
7618                             aopGet (right, offset, FALSE, FALSE));
7619                 }
7620             }
7621           else
7622             {
7623               if (AOP_TYPE (left) == AOP_ACC)
7624                 {
7625                   if (offset)
7626                     emitcode("mov", "a,b");
7627                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7628                 }
7629               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7630                 {
7631                   MOVB (aopGet (left, offset, FALSE, FALSE));
7632                   MOVA (aopGet (right, offset, FALSE, FALSE));
7633                   emitcode ("xrl", "a,b");
7634                   aopPut (result, "a", offset);
7635                 }
7636               else if (aopGetUsesAcc (left, offset))
7637                 {
7638                   MOVA (aopGet (left, offset, FALSE, FALSE));
7639                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7640                   aopPut (result, "a", offset);
7641                 }
7642               else
7643                 {
7644                   MOVA (aopGet (right, offset, FALSE, FALSE));
7645                   if (IS_AOP_PREG (left))
7646                     {
7647                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7648                       aopPut (result, "a", offset);
7649                     }
7650                   else
7651                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7652                 }
7653             }
7654         }
7655     }
7656   else
7657     {
7658       // left & result in different registers
7659       if (AOP_TYPE (result) == AOP_CRY)
7660         {
7661           // result = bit
7662           // if(size), result in bit
7663           // if(!size && ifx), conditional oper: if(left ^ right)
7664           symbol *tlbl = newiTempLabel (NULL);
7665           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7666
7667           if (size)
7668             emitcode ("setb", "c");
7669           while (sizer--)
7670             {
7671               if ((AOP_TYPE (right) == AOP_LIT) &&
7672                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7673                 {
7674                   MOVA (aopGet (left, offset, FALSE, FALSE));
7675                 }
7676               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7677                   && AOP_TYPE(left)==AOP_ACC)
7678                 {
7679                   if (offset)
7680                     emitcode("mov", "a,b");
7681                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7682                 }
7683               else if (AOP_TYPE(left)==AOP_ACC)
7684                 {
7685                   if (!offset)
7686                     {
7687                       bool pushedB = pushB ();
7688                       emitcode("mov", "b,a");
7689                       MOVA (aopGet (right, offset, FALSE, FALSE));
7690                       emitcode("xrl", "a,b");
7691                       popB (pushedB);
7692                     }
7693                   else
7694                     {
7695                       MOVA (aopGet (right, offset, FALSE, FALSE));
7696                       emitcode("xrl", "a,b");
7697                     }
7698                 }
7699               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7700                 {
7701                   MOVB (aopGet (left, offset, FALSE, FALSE));
7702                   MOVA (aopGet (right, offset, FALSE, FALSE));
7703                   emitcode ("xrl", "a,b");
7704                 }
7705               else if (aopGetUsesAcc (left, offset))
7706                 {
7707                   MOVA (aopGet (left, offset, FALSE, FALSE));
7708                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7709                 }
7710               else
7711                 {
7712                   MOVA (aopGet (right, offset, FALSE, FALSE));
7713                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7714                 }
7715
7716               emitcode ("jnz", "%05d$", tlbl->key + 100);
7717               offset++;
7718             }
7719           if (size)
7720             {
7721               CLRC;
7722               emitLabel (tlbl);
7723               outBitC (result);
7724             }
7725           else if (ifx)
7726             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7727         }
7728       else
7729         {
7730           for (; (size--); offset++)
7731             {
7732               // normal case
7733               // result = left ^ right
7734               if (AOP_TYPE (right) == AOP_LIT)
7735                 {
7736                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7737                   if (bytelit == 0)
7738                     {
7739                       aopPut (result,
7740                               aopGet (left, offset, FALSE, FALSE),
7741                               offset);
7742                       continue;
7743                     }
7744                 }
7745               // faster than result <- left, xrl result,right
7746               // and better if result is SFR
7747               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7748                   && AOP_TYPE(left)==AOP_ACC)
7749                 {
7750                   if (offset)
7751                     emitcode("mov", "a,b");
7752                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7753                 }
7754               else if (AOP_TYPE(left)==AOP_ACC)
7755                 {
7756                   if (!offset)
7757                     {
7758                       bool pushedB = pushB ();
7759                       emitcode("mov", "b,a");
7760                       MOVA (aopGet (right, offset, FALSE, FALSE));
7761                       emitcode("xrl", "a,b");
7762                       popB (pushedB);
7763                     }
7764                   else
7765                     {
7766                       MOVA (aopGet (right, offset, FALSE, FALSE));
7767                       emitcode("xrl", "a,b");
7768                     }
7769                 }
7770               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7771                 {
7772                   MOVB (aopGet (left, offset, FALSE, FALSE));
7773                   MOVA (aopGet (right, offset, FALSE, FALSE));
7774                   emitcode ("xrl", "a,b");
7775                 }
7776               else if (aopGetUsesAcc (left, offset))
7777                 {
7778                   MOVA (aopGet (left, offset, FALSE, FALSE));
7779                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7780                 }
7781               else
7782                 {
7783                   MOVA (aopGet (right, offset, FALSE, FALSE));
7784                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7785                 }
7786               aopPut (result, "a", offset);
7787             }
7788         }
7789     }
7790
7791 release:
7792   freeAsmop (result, NULL, ic, TRUE);
7793   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7794   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7795 }
7796
7797 /*-----------------------------------------------------------------*/
7798 /* genInline - write the inline code out                           */
7799 /*-----------------------------------------------------------------*/
7800 static void
7801 genInline (iCode * ic)
7802 {
7803   char *buffer, *bp, *bp1;
7804   bool inComment = FALSE;
7805
7806   D (emitcode (";", "genInline"));
7807
7808   _G.inLine += (!options.asmpeep);
7809
7810   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7811
7812   /* emit each line as a code */
7813   while (*bp)
7814     {
7815       switch (*bp)
7816         {
7817         case ';':
7818           inComment = TRUE;
7819           ++bp;
7820           break;
7821
7822         case '\n':
7823           inComment = FALSE;
7824           *bp++ = '\0';
7825           emitcode (bp1, "");
7826           bp1 = bp;
7827           break;
7828
7829         default:
7830           /* Add \n for labels, not dirs such as c:\mydir */
7831           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7832             {
7833               ++bp;
7834               *bp = '\0';
7835               ++bp;
7836               emitcode (bp1, "");
7837               bp1 = bp;
7838             }
7839           else
7840             ++bp;
7841           break;
7842         }
7843     }
7844   if (bp1 != bp)
7845     emitcode (bp1, "");
7846
7847   Safe_free (buffer);
7848
7849   _G.inLine -= (!options.asmpeep);
7850 }
7851
7852 /*-----------------------------------------------------------------*/
7853 /* genRRC - rotate right with carry                                */
7854 /*-----------------------------------------------------------------*/
7855 static void
7856 genRRC (iCode * ic)
7857 {
7858   operand *left, *result;
7859   int     size, offset;
7860   char    *l;
7861
7862   D (emitcode (";", "genRRC"));
7863
7864   /* rotate right with carry */
7865   left = IC_LEFT (ic);
7866   result = IC_RESULT (ic);
7867   aopOp (left, ic, FALSE);
7868   aopOp (result, ic, FALSE);
7869
7870   /* move it to the result */
7871   size = AOP_SIZE (result);
7872   offset = size - 1;
7873   if (size == 1) { /* special case for 1 byte */
7874       l = aopGet (left, offset, FALSE, FALSE);
7875       MOVA (l);
7876       emitcode ("rr", "a");
7877       goto release;
7878   }
7879   /* no need to clear carry, bit7 will be written later */
7880   while (size--)
7881     {
7882       l = aopGet (left, offset, FALSE, FALSE);
7883       MOVA (l);
7884       emitcode ("rrc", "a");
7885       if (AOP_SIZE (result) > 1)
7886         aopPut (result, "a", offset--);
7887     }
7888   /* now we need to put the carry into the
7889      highest order byte of the result */
7890   if (AOP_SIZE (result) > 1)
7891     {
7892       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7893       MOVA (l);
7894     }
7895   emitcode ("mov", "acc.7,c");
7896  release:
7897   aopPut (result, "a", AOP_SIZE (result) - 1);
7898   freeAsmop (result, NULL, ic, TRUE);
7899   freeAsmop (left, NULL, ic, TRUE);
7900 }
7901
7902 /*-----------------------------------------------------------------*/
7903 /* genRLC - generate code for rotate left with carry               */
7904 /*-----------------------------------------------------------------*/
7905 static void
7906 genRLC (iCode * ic)
7907 {
7908   operand *left, *result;
7909   int size, offset;
7910   char *l;
7911
7912   D (emitcode (";", "genRLC"));
7913
7914   /* rotate right with carry */
7915   left = IC_LEFT (ic);
7916   result = IC_RESULT (ic);
7917   aopOp (left, ic, FALSE);
7918   aopOp (result, ic, FALSE);
7919
7920   /* move it to the result */
7921   size = AOP_SIZE (result);
7922   offset = 0;
7923   if (size--)
7924     {
7925       l = aopGet (left, offset, FALSE, FALSE);
7926       MOVA (l);
7927       if (size == 0) { /* special case for 1 byte */
7928               emitcode("rl","a");
7929               goto release;
7930       }
7931       emitcode("rlc","a"); /* bit0 will be written later */
7932       if (AOP_SIZE (result) > 1)
7933         {
7934           aopPut (result, "a", offset++);
7935         }
7936
7937       while (size--)
7938         {
7939           l = aopGet (left, offset, FALSE, FALSE);
7940           MOVA (l);
7941           emitcode ("rlc", "a");
7942           if (AOP_SIZE (result) > 1)
7943             aopPut (result, "a", offset++);
7944         }
7945     }
7946   /* now we need to put the carry into the
7947      highest order byte of the result */
7948   if (AOP_SIZE (result) > 1)
7949     {
7950       l = aopGet (result, 0, FALSE, FALSE);
7951       MOVA (l);
7952     }
7953   emitcode ("mov", "acc.0,c");
7954  release:
7955   aopPut (result, "a", 0);
7956   freeAsmop (result, NULL, ic, TRUE);
7957   freeAsmop (left, NULL, ic, TRUE);
7958 }
7959
7960 /*-----------------------------------------------------------------*/
7961 /* genGetHbit - generates code get highest order bit               */
7962 /*-----------------------------------------------------------------*/
7963 static void
7964 genGetHbit (iCode * ic)
7965 {
7966   operand *left, *result;
7967
7968   D (emitcode (";", "genGetHbit"));
7969
7970   left = IC_LEFT (ic);
7971   result = IC_RESULT (ic);
7972   aopOp (left, ic, FALSE);
7973   aopOp (result, ic, FALSE);
7974
7975   /* get the highest order byte into a */
7976   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7977   if (AOP_TYPE (result) == AOP_CRY)
7978     {
7979       emitcode ("rlc", "a");
7980       outBitC (result);
7981     }
7982   else
7983     {
7984       emitcode ("rl", "a");
7985       emitcode ("anl", "a,#0x01");
7986       outAcc (result);
7987     }
7988
7989   freeAsmop (result, NULL, ic, TRUE);
7990   freeAsmop (left, NULL, ic, TRUE);
7991 }
7992
7993 /*-----------------------------------------------------------------*/
7994 /* genGetAbit - generates code get a single bit                    */
7995 /*-----------------------------------------------------------------*/
7996 static void
7997 genGetAbit (iCode * ic)
7998 {
7999   operand *left, *right, *result;
8000   int shCount;
8001
8002   D (emitcode (";", "genGetAbit"));
8003
8004   left = IC_LEFT (ic);
8005   right = IC_RIGHT (ic);
8006   result = IC_RESULT (ic);
8007   aopOp (left, ic, FALSE);
8008   aopOp (right, ic, FALSE);
8009   aopOp (result, ic, FALSE);
8010
8011   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
8012
8013   /* get the needed byte into a */
8014   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
8015   shCount %= 8;
8016   if (AOP_TYPE (result) == AOP_CRY)
8017     {
8018       if ((shCount) == 7)
8019           emitcode ("rlc", "a");
8020       else if ((shCount) == 0)
8021           emitcode ("rrc", "a");
8022       else
8023           emitcode ("mov", "c,acc[%d]", shCount);
8024       outBitC (result);
8025     }
8026   else
8027     {
8028       switch (shCount)
8029         {
8030         case 2:
8031           emitcode ("rr", "a");
8032           //fallthrough
8033         case 1:
8034           emitcode ("rr", "a");
8035           //fallthrough
8036         case 0:
8037           emitcode ("anl", "a,#0x01");
8038           break;
8039         case 3:
8040         case 5:
8041           emitcode ("mov", "c,acc[%d]", shCount);
8042           emitcode ("clr", "a");
8043           emitcode ("rlc", "a");
8044           break;
8045         case 4:
8046           emitcode ("swap", "a");
8047           emitcode ("anl", "a,#0x01");
8048           break;
8049         case 6:
8050           emitcode ("rl", "a");
8051           //fallthrough
8052         case 7:
8053           emitcode ("rl", "a");
8054           emitcode ("anl", "a,#0x01");
8055           break;
8056         }
8057       outAcc (result);
8058     }
8059
8060   freeAsmop (result, NULL, ic, TRUE);
8061   freeAsmop (right, NULL, ic, TRUE);
8062   freeAsmop (left, NULL, ic, TRUE);
8063 }
8064
8065 /*-----------------------------------------------------------------*/
8066 /* genGetByte - generates code get a single byte                   */
8067 /*-----------------------------------------------------------------*/
8068 static void
8069 genGetByte (iCode * ic)
8070 {
8071   operand *left, *right, *result;
8072   int offset;
8073
8074   D (emitcode (";", "genGetByte"));
8075
8076   left = IC_LEFT (ic);
8077   right = IC_RIGHT (ic);
8078   result = IC_RESULT (ic);
8079   aopOp (left, ic, FALSE);
8080   aopOp (right, ic, FALSE);
8081   aopOp (result, ic, FALSE);
8082
8083   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8084   aopPut (result,
8085           aopGet (left, offset, FALSE, FALSE),
8086           0);
8087
8088   freeAsmop (result, NULL, ic, TRUE);
8089   freeAsmop (right, NULL, ic, TRUE);
8090   freeAsmop (left, NULL, ic, TRUE);
8091 }
8092
8093 /*-----------------------------------------------------------------*/
8094 /* genGetWord - generates code get two bytes                       */
8095 /*-----------------------------------------------------------------*/
8096 static void
8097 genGetWord (iCode * ic)
8098 {
8099   operand *left, *right, *result;
8100   int offset;
8101
8102   D (emitcode (";", "genGetWord"));
8103
8104   left = IC_LEFT (ic);
8105   right = IC_RIGHT (ic);
8106   result = IC_RESULT (ic);
8107   aopOp (left, ic, FALSE);
8108   aopOp (right, ic, FALSE);
8109   aopOp (result, ic, FALSE);
8110
8111   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8112   aopPut (result,
8113           aopGet (left, offset, FALSE, FALSE),
8114           0);
8115   aopPut (result,
8116           aopGet (left, offset+1, FALSE, FALSE),
8117           1);
8118
8119   freeAsmop (result, NULL, ic, TRUE);
8120   freeAsmop (right, NULL, ic, TRUE);
8121   freeAsmop (left, NULL, ic, TRUE);
8122 }
8123
8124 /*-----------------------------------------------------------------*/
8125 /* genSwap - generates code to swap nibbles or bytes               */
8126 /*-----------------------------------------------------------------*/
8127 static void
8128 genSwap (iCode * ic)
8129 {
8130   operand *left, *result;
8131
8132   D(emitcode (";", "genSwap"));
8133
8134   left = IC_LEFT (ic);
8135   result = IC_RESULT (ic);
8136   aopOp (left, ic, FALSE);
8137   aopOp (result, ic, FALSE);
8138
8139   switch (AOP_SIZE (left))
8140     {
8141     case 1: /* swap nibbles in byte */
8142       MOVA (aopGet (left, 0, FALSE, FALSE));
8143       emitcode ("swap", "a");
8144       aopPut (result, "a", 0);
8145       break;
8146     case 2: /* swap bytes in word */
8147       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8148         {
8149           MOVA (aopGet (left, 0, FALSE, FALSE));
8150           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8151           aopPut (result, "a", 1);
8152         }
8153       else if (operandsEqu (left, result))
8154         {
8155           char * reg = "a";
8156           bool pushedB = FALSE, leftInB = FALSE;
8157
8158           MOVA (aopGet (left, 0, FALSE, FALSE));
8159           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8160             {
8161               pushedB = pushB ();
8162               emitcode ("mov", "b,a");
8163               reg = "b";
8164               leftInB = TRUE;
8165             }
8166           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8167           aopPut (result, reg, 1);
8168
8169           if (leftInB)
8170             popB (pushedB);
8171         }
8172       else
8173         {
8174           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8175           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8176         }
8177       break;
8178     default:
8179       wassertl(FALSE, "unsupported SWAP operand size");
8180     }
8181
8182   freeAsmop (result, NULL, ic, TRUE);
8183   freeAsmop (left, NULL, ic, TRUE);
8184 }
8185
8186 /*-----------------------------------------------------------------*/
8187 /* AccRol - rotate left accumulator by known count                 */
8188 /*-----------------------------------------------------------------*/
8189 static void
8190 AccRol (int shCount)
8191 {
8192   shCount &= 0x0007;            // shCount : 0..7
8193
8194   switch (shCount)
8195     {
8196     case 0:
8197       break;
8198     case 1:
8199       emitcode ("rl", "a");
8200       break;
8201     case 2:
8202       emitcode ("rl", "a");
8203       emitcode ("rl", "a");
8204       break;
8205     case 3:
8206       emitcode ("swap", "a");
8207       emitcode ("rr", "a");
8208       break;
8209     case 4:
8210       emitcode ("swap", "a");
8211       break;
8212     case 5:
8213       emitcode ("swap", "a");
8214       emitcode ("rl", "a");
8215       break;
8216     case 6:
8217       emitcode ("rr", "a");
8218       emitcode ("rr", "a");
8219       break;
8220     case 7:
8221       emitcode ("rr", "a");
8222       break;
8223     }
8224 }
8225
8226 /*-----------------------------------------------------------------*/
8227 /* AccLsh - left shift accumulator by known count                  */
8228 /*-----------------------------------------------------------------*/
8229 static void
8230 AccLsh (int shCount)
8231 {
8232   if (shCount != 0)
8233     {
8234       if (shCount == 1)
8235         emitcode ("add", "a,acc");
8236       else if (shCount == 2)
8237         {
8238           emitcode ("add", "a,acc");
8239           emitcode ("add", "a,acc");
8240         }
8241       else
8242         {
8243           /* rotate left accumulator */
8244           AccRol (shCount);
8245           /* and kill the lower order bits */
8246           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8247         }
8248     }
8249 }
8250
8251 /*-----------------------------------------------------------------*/
8252 /* AccRsh - right shift accumulator by known count                 */
8253 /*-----------------------------------------------------------------*/
8254 static void
8255 AccRsh (int shCount)
8256 {
8257   if (shCount != 0)
8258     {
8259       if (shCount == 1)
8260         {
8261           CLRC;
8262           emitcode ("rrc", "a");
8263         }
8264       else
8265         {
8266           /* rotate right accumulator */
8267           AccRol (8 - shCount);
8268           /* and kill the higher order bits */
8269           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8270         }
8271     }
8272 }
8273
8274 /*-----------------------------------------------------------------*/
8275 /* AccSRsh - signed right shift accumulator by known count                 */
8276 /*-----------------------------------------------------------------*/
8277 static void
8278 AccSRsh (int shCount)
8279 {
8280   symbol *tlbl;
8281   if (shCount != 0)
8282     {
8283       if (shCount == 1)
8284         {
8285           emitcode ("mov", "c,acc.7");
8286           emitcode ("rrc", "a");
8287         }
8288       else if (shCount == 2)
8289         {
8290           emitcode ("mov", "c,acc.7");
8291           emitcode ("rrc", "a");
8292           emitcode ("mov", "c,acc.7");
8293           emitcode ("rrc", "a");
8294         }
8295       else
8296         {
8297           tlbl = newiTempLabel (NULL);
8298           /* rotate right accumulator */
8299           AccRol (8 - shCount);
8300           /* and kill the higher order bits */
8301           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8302           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8303           emitcode ("orl", "a,#0x%02x",
8304                     (unsigned char) ~SRMask[shCount]);
8305           emitLabel (tlbl);
8306         }
8307     }
8308 }
8309
8310 /*-----------------------------------------------------------------*/
8311 /* shiftR1Left2Result - shift right one byte from left to result   */
8312 /*-----------------------------------------------------------------*/
8313 static void
8314 shiftR1Left2Result (operand * left, int offl,
8315                     operand * result, int offr,
8316                     int shCount, int sign)
8317 {
8318   MOVA (aopGet (left, offl, FALSE, FALSE));
8319   /* shift right accumulator */
8320   if (sign)
8321     AccSRsh (shCount);
8322   else
8323     AccRsh (shCount);
8324   aopPut (result, "a", offr);
8325 }
8326
8327 /*-----------------------------------------------------------------*/
8328 /* shiftL1Left2Result - shift left one byte from left to result    */
8329 /*-----------------------------------------------------------------*/
8330 static void
8331 shiftL1Left2Result (operand * left, int offl,
8332                     operand * result, int offr, int shCount)
8333 {
8334   char *l;
8335   l = aopGet (left, offl, FALSE, FALSE);
8336   MOVA (l);
8337   /* shift left accumulator */
8338   AccLsh (shCount);
8339   aopPut (result, "a", offr);
8340 }
8341
8342 /*-----------------------------------------------------------------*/
8343 /* movLeft2Result - move byte from left to result                  */
8344 /*-----------------------------------------------------------------*/
8345 static void
8346 movLeft2Result (operand * left, int offl,
8347                 operand * result, int offr, int sign)
8348 {
8349   char *l;
8350   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8351     {
8352       l = aopGet (left, offl, FALSE, FALSE);
8353
8354       if (*l == '@' && (IS_AOP_PREG (result)))
8355         {
8356           emitcode ("mov", "a,%s", l);
8357           aopPut (result, "a", offr);
8358         }
8359       else
8360         {
8361           if (!sign)
8362             {
8363               aopPut (result, l, offr);
8364             }
8365           else
8366             {
8367               /* MSB sign in acc.7 ! */
8368               if (getDataSize (left) == offl + 1)
8369                 {
8370                   MOVA (l);
8371                   aopPut (result, "a", offr);
8372                 }
8373             }
8374         }
8375     }
8376 }
8377
8378 /*-----------------------------------------------------------------*/
8379 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8380 /*-----------------------------------------------------------------*/
8381 static void
8382 AccAXRrl1 (char *x)
8383 {
8384   emitcode ("rrc", "a");
8385   emitcode ("xch", "a,%s", x);
8386   emitcode ("rrc", "a");
8387   emitcode ("xch", "a,%s", x);
8388 }
8389
8390 /*-----------------------------------------------------------------*/
8391 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8392 /*-----------------------------------------------------------------*/
8393 static void
8394 AccAXLrl1 (char *x)
8395 {
8396   emitcode ("xch", "a,%s", x);
8397   emitcode ("rlc", "a");
8398   emitcode ("xch", "a,%s", x);
8399   emitcode ("rlc", "a");
8400 }
8401
8402 /*-----------------------------------------------------------------*/
8403 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8404 /*-----------------------------------------------------------------*/
8405 static void
8406 AccAXLsh1 (char *x)
8407 {
8408   emitcode ("xch", "a,%s", x);
8409   emitcode ("add", "a,acc");
8410   emitcode ("xch", "a,%s", x);
8411   emitcode ("rlc", "a");
8412 }
8413
8414 /*-----------------------------------------------------------------*/
8415 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8416 /*-----------------------------------------------------------------*/
8417 static void
8418 AccAXLsh (char *x, int shCount)
8419 {
8420   switch (shCount)
8421     {
8422     case 0:
8423       break;
8424     case 1:
8425       AccAXLsh1 (x);
8426       break;
8427     case 2:
8428       AccAXLsh1 (x);
8429       AccAXLsh1 (x);
8430       break;
8431     case 3:
8432     case 4:
8433     case 5:                             // AAAAABBB:CCCCCDDD
8434
8435       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8436
8437       emitcode ("anl", "a,#0x%02x",
8438                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8439
8440       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8441
8442       AccRol (shCount);                 // DDDCCCCC:BBB00000
8443
8444       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8445
8446       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8447
8448       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8449
8450       emitcode ("anl", "a,#0x%02x",
8451                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8452
8453       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8454
8455       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8456
8457       break;
8458     case 6:                             // AAAAAABB:CCCCCCDD
8459       emitcode ("anl", "a,#0x%02x",
8460                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8461       emitcode ("mov", "c,acc.0");      // c = B
8462       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8463 #if 0 // REMOVE ME
8464       AccAXRrl1 (x);                    // BCCCCCCD:D000000B
8465       AccAXRrl1 (x);                    // BBCCCCCC:DD000000
8466 #else
8467       emitcode("rrc","a");
8468       emitcode("xch","a,%s", x);
8469       emitcode("rrc","a");
8470       emitcode("mov","c,acc.0"); //<< get correct bit
8471       emitcode("xch","a,%s", x);
8472
8473       emitcode("rrc","a");
8474       emitcode("xch","a,%s", x);
8475       emitcode("rrc","a");
8476       emitcode("xch","a,%s", x);
8477 #endif
8478       break;
8479     case 7:                             // a:x <<= 7
8480
8481       emitcode ("anl", "a,#0x%02x",
8482                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8483
8484       emitcode ("mov", "c,acc.0");      // c = B
8485
8486       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8487
8488       AccAXRrl1 (x);                    // BCCCCCCC:D0000000
8489
8490       break;
8491     default:
8492       break;
8493     }
8494 }
8495
8496 /*-----------------------------------------------------------------*/
8497 /* AccAXRsh - right shift a:x known count (0..7)                   */
8498 /*-----------------------------------------------------------------*/
8499 static void
8500 AccAXRsh (char *x, int shCount)
8501 {
8502   switch (shCount)
8503     {
8504     case 0:
8505       break;
8506     case 1:
8507       CLRC;
8508       AccAXRrl1 (x);                    // 0->a:x
8509
8510       break;
8511     case 2:
8512       CLRC;
8513       AccAXRrl1 (x);                    // 0->a:x
8514
8515       CLRC;
8516       AccAXRrl1 (x);                    // 0->a:x
8517
8518       break;
8519     case 3:
8520     case 4:
8521     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8522
8523       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8524
8525       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8526
8527       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8528
8529       emitcode ("anl", "a,#0x%02x",
8530                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8531
8532       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8533
8534       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8535
8536       emitcode ("anl", "a,#0x%02x",
8537                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8538
8539       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8540
8541       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8542
8543       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8544
8545       break;
8546     case 6:                             // AABBBBBB:CCDDDDDD
8547
8548       emitcode ("mov", "c,acc.7");
8549       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
8550
8551       emitcode ("mov", "c,acc.7");
8552       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8553
8554       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8555
8556       emitcode ("anl", "a,#0x%02x",
8557                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8558
8559       break;
8560     case 7:                             // ABBBBBBB:CDDDDDDD
8561
8562       emitcode ("mov", "c,acc.7");      // c = A
8563
8564       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8565
8566       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8567
8568       emitcode ("anl", "a,#0x%02x",
8569                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8570
8571       break;
8572     default:
8573       break;
8574     }
8575 }
8576
8577 /*-----------------------------------------------------------------*/
8578 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8579 /*-----------------------------------------------------------------*/
8580 static void
8581 AccAXRshS (char *x, int shCount)
8582 {
8583   symbol *tlbl;
8584   switch (shCount)
8585     {
8586     case 0:
8587       break;
8588     case 1:
8589       emitcode ("mov", "c,acc.7");
8590       AccAXRrl1 (x);                    // s->a:x
8591
8592       break;
8593     case 2:
8594       emitcode ("mov", "c,acc.7");
8595       AccAXRrl1 (x);                    // s->a:x
8596
8597       emitcode ("mov", "c,acc.7");
8598       AccAXRrl1 (x);                    // s->a:x
8599
8600       break;
8601     case 3:
8602     case 4:
8603     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8604
8605       tlbl = newiTempLabel (NULL);
8606       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
8607
8608       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8609
8610       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8611
8612       emitcode ("anl", "a,#0x%02x",
8613                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8614
8615       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8616
8617       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8618
8619       emitcode ("anl", "a,#0x%02x",
8620                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8621
8622       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8623
8624       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8625
8626       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8627
8628       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8629       emitcode ("orl", "a,#0x%02x",
8630                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8631
8632       emitLabel (tlbl);
8633       break;                            // SSSSAAAA:BBBCCCCC
8634
8635     case 6:                             // AABBBBBB:CCDDDDDD
8636
8637       tlbl = newiTempLabel (NULL);
8638       emitcode ("mov", "c,acc.7");
8639       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
8640
8641       emitcode ("mov", "c,acc.7");
8642       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8643
8644       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8645
8646       emitcode ("anl", "a,#0x%02x",
8647                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8648
8649       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8650       emitcode ("orl", "a,#0x%02x",
8651                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8652
8653       emitLabel (tlbl);
8654       break;
8655     case 7:                             // ABBBBBBB:CDDDDDDD
8656
8657       tlbl = newiTempLabel (NULL);
8658       emitcode ("mov", "c,acc.7");      // c = A
8659
8660       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8661
8662       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8663
8664       emitcode ("anl", "a,#0x%02x",
8665                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8666
8667       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8668       emitcode ("orl", "a,#0x%02x",
8669                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8670
8671       emitLabel (tlbl);
8672       break;
8673     default:
8674       break;
8675     }
8676 }
8677
8678 /*-----------------------------------------------------------------*/
8679 /* shiftL2Left2Result - shift left two bytes from left to result   */
8680 /*-----------------------------------------------------------------*/
8681 static void
8682 shiftL2Left2Result (operand * left, int offl,
8683                     operand * result, int offr, int shCount)
8684 {
8685   char * x;
8686   bool pushedB = FALSE;
8687   bool usedB = FALSE;
8688
8689   if (sameRegs (AOP (result), AOP (left)) &&
8690       ((offl + MSB16) == offr))
8691     {
8692       /* don't crash result[offr] */
8693       MOVA (aopGet (left, offl, FALSE, FALSE));
8694       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8695       usedB = !strncmp(x, "b", 1);
8696     }
8697   else if (aopGetUsesAcc (result, offr))
8698     {
8699       movLeft2Result (left, offl, result, offr, 0);
8700       pushedB = pushB ();
8701       usedB = TRUE;
8702       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8703       MOVA (aopGet (result, offr, FALSE, FALSE));
8704       emitcode ("xch", "a,b");
8705       x = "b";
8706     }
8707   else
8708     {
8709       movLeft2Result (left, offl, result, offr, 0);
8710       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8711       x = aopGet (result, offr, FALSE, FALSE);
8712     }
8713   /* ax << shCount (x = lsb(result)) */
8714   AccAXLsh (x, shCount);
8715   if (usedB)
8716     {
8717       emitcode ("xch", "a,b");
8718       aopPut (result, "a", offr);
8719       aopPut (result, "b", offr + MSB16);
8720       popB (pushedB);
8721     }
8722   else
8723     {
8724       aopPut (result, "a", offr + MSB16);
8725     }
8726 }
8727
8728
8729 /*-----------------------------------------------------------------*/
8730 /* shiftR2Left2Result - shift right two bytes from left to result  */
8731 /*-----------------------------------------------------------------*/
8732 static void
8733 shiftR2Left2Result (operand * left, int offl,
8734                     operand * result, int offr,
8735                     int shCount, int sign)
8736 {
8737   char * x;
8738   bool pushedB = FALSE;
8739   bool usedB = FALSE;
8740
8741   if (sameRegs (AOP (result), AOP (left)) &&
8742       ((offl + MSB16) == offr))
8743     {
8744       /* don't crash result[offr] */
8745       MOVA (aopGet (left, offl, FALSE, FALSE));
8746       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8747       usedB = !strncmp(x, "b", 1);
8748     }
8749   else if (aopGetUsesAcc (result, offr))
8750     {
8751       movLeft2Result (left, offl, result, offr, 0);
8752       pushedB = pushB ();
8753       usedB = TRUE;
8754       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8755       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8756       x = "b";
8757     }
8758   else
8759     {
8760       movLeft2Result (left, offl, result, offr, 0);
8761       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8762       x = aopGet (result, offr, FALSE, FALSE);
8763     }
8764   /* a:x >> shCount (x = lsb(result)) */
8765   if (sign)
8766     AccAXRshS (x, shCount);
8767   else
8768     AccAXRsh (x, shCount);
8769   if (usedB)
8770     {
8771       emitcode ("xch", "a,b");
8772       aopPut (result, "a", offr);
8773       emitcode ("xch", "a,b");
8774       popB (pushedB);
8775     }
8776   if (getDataSize (result) > 1)
8777     aopPut (result, "a", offr + MSB16);
8778 }
8779
8780 /*-----------------------------------------------------------------*/
8781 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8782 /*-----------------------------------------------------------------*/
8783 static void
8784 shiftLLeftOrResult (operand * left, int offl,
8785                     operand * result, int offr, int shCount)
8786 {
8787   MOVA (aopGet (left, offl, FALSE, FALSE));
8788   /* shift left accumulator */
8789   AccLsh (shCount);
8790   /* or with result */
8791   if (aopGetUsesAcc (result, offr))
8792     {
8793       emitcode ("xch", "a,b");
8794       MOVA (aopGet (result, offr, FALSE, FALSE));
8795       emitcode ("orl", "a,b");
8796     }
8797   else
8798     {
8799       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8800     }
8801   /* back to result */
8802   aopPut (result, "a", offr);
8803 }
8804
8805 /*-----------------------------------------------------------------*/
8806 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8807 /*-----------------------------------------------------------------*/
8808 static void
8809 shiftRLeftOrResult (operand * left, int offl,
8810                     operand * result, int offr, int shCount)
8811 {
8812   MOVA (aopGet (left, offl, FALSE, FALSE));
8813   /* shift right accumulator */
8814   AccRsh (shCount);
8815   /* or with result */
8816   if (aopGetUsesAcc(result, offr))
8817     {
8818       emitcode ("xch", "a,b");
8819       MOVA (aopGet (result, offr, FALSE, FALSE));
8820       emitcode ("orl", "a,b");
8821     }
8822   else
8823     {
8824       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8825     }
8826   /* back to result */
8827   aopPut (result, "a", offr);
8828 }
8829
8830 /*-----------------------------------------------------------------*/
8831 /* genlshOne - left shift a one byte quantity by known count       */
8832 /*-----------------------------------------------------------------*/
8833 static void
8834 genlshOne (operand * result, operand * left, int shCount)
8835 {
8836   D (emitcode (";", "genlshOne"));
8837
8838   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8839 }
8840
8841 /*-----------------------------------------------------------------*/
8842 /* genlshTwo - left shift two bytes by known amount != 0           */
8843 /*-----------------------------------------------------------------*/
8844 static void
8845 genlshTwo (operand * result, operand * left, int shCount)
8846 {
8847   int size;
8848
8849   D (emitcode (";", "genlshTwo"));
8850
8851   size = getDataSize (result);
8852
8853   /* if shCount >= 8 */
8854   if (shCount >= 8)
8855     {
8856       shCount -= 8;
8857
8858       if (size > 1)
8859         {
8860           if (shCount)
8861             {
8862               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8863             }
8864           else
8865             {
8866               movLeft2Result (left, LSB, result, MSB16, 0);
8867             }
8868         }
8869       aopPut (result, zero, LSB);
8870     }
8871
8872   /*  1 <= shCount <= 7 */
8873   else
8874     {
8875       if (size == 1)
8876         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8877       else
8878         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8879     }
8880 }
8881
8882 /*-----------------------------------------------------------------*/
8883 /* shiftLLong - shift left one long from left to result            */
8884 /* offl = LSB or MSB16                                             */
8885 /*-----------------------------------------------------------------*/
8886 static void
8887 shiftLLong (operand * left, operand * result, int offr)
8888 {
8889   char *l;
8890   int size = AOP_SIZE (result);
8891
8892   if (size >= LSB + offr)
8893     {
8894       l = aopGet (left, LSB, FALSE, FALSE);
8895       MOVA (l);
8896       emitcode ("add", "a,acc");
8897       if (sameRegs (AOP (left), AOP (result)) &&
8898           size >= MSB16 + offr && offr != LSB)
8899         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8900       else
8901         aopPut (result, "a", LSB + offr);
8902     }
8903
8904   if (size >= MSB16 + offr)
8905     {
8906       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8907         {
8908           l = aopGet (left, MSB16, FALSE, FALSE);
8909           MOVA (l);
8910         }
8911       emitcode ("rlc", "a");
8912       if (sameRegs (AOP (left), AOP (result)) &&
8913           size >= MSB24 + offr && offr != LSB)
8914         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8915       else
8916         aopPut (result, "a", MSB16 + offr);
8917     }
8918
8919   if (size >= MSB24 + offr)
8920     {
8921       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8922         {
8923           l = aopGet (left, MSB24, FALSE, FALSE);
8924           MOVA (l);
8925         }
8926       emitcode ("rlc", "a");
8927       if (sameRegs (AOP (left), AOP (result)) &&
8928           size >= MSB32 + offr && offr != LSB)
8929         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8930       else
8931         aopPut (result, "a", MSB24 + offr);
8932     }
8933
8934   if (size > MSB32 + offr)
8935     {
8936       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8937         {
8938           l = aopGet (left, MSB32, FALSE, FALSE);
8939           MOVA (l);
8940         }
8941       emitcode ("rlc", "a");
8942       aopPut (result, "a", MSB32 + offr);
8943     }
8944   if (offr != LSB)
8945     aopPut (result, zero, LSB);
8946 }
8947
8948 /*-----------------------------------------------------------------*/
8949 /* genlshFour - shift four byte by a known amount != 0             */
8950 /*-----------------------------------------------------------------*/
8951 static void
8952 genlshFour (operand * result, operand * left, int shCount)
8953 {
8954   int size;
8955
8956   D (emitcode (";", "genlshFour"));
8957
8958   size = AOP_SIZE (result);
8959
8960   /* if shifting more that 3 bytes */
8961   if (shCount >= 24)
8962     {
8963       shCount -= 24;
8964       if (shCount)
8965         /* lowest order of left goes to the highest
8966            order of the destination */
8967         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8968       else
8969         movLeft2Result (left, LSB, result, MSB32, 0);
8970       aopPut (result, zero, LSB);
8971       aopPut (result, zero, MSB16);
8972       aopPut (result, zero, MSB24);
8973       return;
8974     }
8975
8976   /* more than two bytes */
8977   else if (shCount >= 16)
8978     {
8979       /* lower order two bytes goes to higher order two bytes */
8980       shCount -= 16;
8981       /* if some more remaining */
8982       if (shCount)
8983         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8984       else
8985         {
8986           movLeft2Result (left, MSB16, result, MSB32, 0);
8987           movLeft2Result (left, LSB, result, MSB24, 0);
8988         }
8989       aopPut (result, zero, MSB16);
8990       aopPut (result, zero, LSB);
8991       return;
8992     }
8993
8994   /* if more than 1 byte */
8995   else if (shCount >= 8)
8996     {
8997       /* lower order three bytes goes to higher order  three bytes */
8998       shCount -= 8;
8999       if (size == 2)
9000         {
9001           if (shCount)
9002             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9003           else
9004             movLeft2Result (left, LSB, result, MSB16, 0);
9005         }
9006       else
9007         {                       /* size = 4 */
9008           if (shCount == 0)
9009             {
9010               movLeft2Result (left, MSB24, result, MSB32, 0);
9011               movLeft2Result (left, MSB16, result, MSB24, 0);
9012               movLeft2Result (left, LSB, result, MSB16, 0);
9013               aopPut (result, zero, LSB);
9014             }
9015           else if (shCount == 1)
9016             shiftLLong (left, result, MSB16);
9017           else
9018             {
9019               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9020               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9021               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9022               aopPut (result, zero, LSB);
9023             }
9024         }
9025     }
9026
9027   /* 1 <= shCount <= 7 */
9028   else if (shCount <= 2)
9029     {
9030       shiftLLong (left, result, LSB);
9031       if (shCount == 2)
9032         shiftLLong (result, result, LSB);
9033     }
9034   /* 3 <= shCount <= 7, optimize */
9035   else
9036     {
9037       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9038       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9039       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9040     }
9041 }
9042
9043 /*-----------------------------------------------------------------*/
9044 /* genLeftShiftLiteral - left shifting by known count              */
9045 /*-----------------------------------------------------------------*/
9046 static void
9047 genLeftShiftLiteral (operand * left,
9048                      operand * right,
9049                      operand * result,
9050                      iCode * ic)
9051 {
9052   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9053   int size;
9054
9055   D (emitcode (";", "genLeftShiftLiteral"));
9056
9057   freeAsmop (right, NULL, ic, TRUE);
9058
9059   aopOp (left, ic, FALSE);
9060   aopOp (result, ic, FALSE);
9061
9062   size = getSize (operandType (result));
9063
9064 #if VIEW_SIZE
9065   emitcode ("; shift left ", "result %d, left %d", size,
9066             AOP_SIZE (left));
9067 #endif
9068
9069   /* I suppose that the left size >= result size */
9070   if (shCount == 0)
9071     {
9072       while (size--)
9073         {
9074           movLeft2Result (left, size, result, size, 0);
9075         }
9076     }
9077   else if (shCount >= (size * 8))
9078     {
9079       while (size--)
9080         {
9081           aopPut (result, zero, size);
9082         }
9083     }
9084   else
9085     {
9086       switch (size)
9087         {
9088         case 1:
9089           genlshOne (result, left, shCount);
9090           break;
9091
9092         case 2:
9093           genlshTwo (result, left, shCount);
9094           break;
9095
9096         case 4:
9097           genlshFour (result, left, shCount);
9098           break;
9099         default:
9100           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9101                   "*** ack! mystery literal shift!\n");
9102           break;
9103         }
9104     }
9105   freeAsmop (result, NULL, ic, TRUE);
9106   freeAsmop (left, NULL, ic, TRUE);
9107 }
9108
9109 /*-----------------------------------------------------------------*/
9110 /* genLeftShift - generates code for left shifting                 */
9111 /*-----------------------------------------------------------------*/
9112 static void
9113 genLeftShift (iCode * ic)
9114 {
9115   operand *left, *right, *result;
9116   int size, offset;
9117   char *l;
9118   symbol *tlbl, *tlbl1;
9119   bool pushedB;
9120
9121   D (emitcode (";", "genLeftShift"));
9122
9123   right = IC_RIGHT (ic);
9124   left = IC_LEFT (ic);
9125   result = IC_RESULT (ic);
9126
9127   aopOp (right, ic, FALSE);
9128
9129   /* if the shift count is known then do it
9130      as efficiently as possible */
9131   if (AOP_TYPE (right) == AOP_LIT)
9132     {
9133       genLeftShiftLiteral (left, right, result, ic);
9134       return;
9135     }
9136
9137   /* shift count is unknown then we have to form
9138      a loop get the loop count in B : Note: we take
9139      only the lower order byte since shifting
9140      more that 32 bits make no sense anyway, ( the
9141      largest size of an object can be only 32 bits ) */
9142
9143   pushedB = pushB ();
9144   MOVB (aopGet (right, 0, FALSE, FALSE));
9145   emitcode ("inc", "b");
9146   freeAsmop (right, NULL, ic, TRUE);
9147   aopOp (left, ic, FALSE);
9148   aopOp (result, ic, FALSE);
9149
9150   /* now move the left to the result if they are not the same */
9151   if (!sameRegs (AOP (left), AOP (result)) &&
9152       AOP_SIZE (result) > 1)
9153     {
9154
9155       size = AOP_SIZE (result);
9156       offset = 0;
9157       while (size--)
9158         {
9159           l = aopGet (left, offset, FALSE, TRUE);
9160           if (*l == '@' && (IS_AOP_PREG (result)))
9161             {
9162
9163               emitcode ("mov", "a,%s", l);
9164               aopPut (result, "a", offset);
9165             }
9166           else
9167             aopPut (result, l, offset);
9168           offset++;
9169         }
9170     }
9171
9172   tlbl = newiTempLabel (NULL);
9173   size = AOP_SIZE (result);
9174   offset = 0;
9175   tlbl1 = newiTempLabel (NULL);
9176
9177   /* if it is only one byte then */
9178   if (size == 1)
9179     {
9180       symbol *tlbl1 = newiTempLabel (NULL);
9181
9182       l = aopGet (left, 0, FALSE, FALSE);
9183       MOVA (l);
9184       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9185       emitLabel (tlbl);
9186       emitcode ("add", "a,acc");
9187       emitLabel (tlbl1);
9188       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9189       popB (pushedB);
9190       aopPut (result, "a", 0);
9191       goto release;
9192     }
9193
9194   reAdjustPreg (AOP (result));
9195
9196   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9197   emitLabel (tlbl);
9198   l = aopGet (result, offset, FALSE, FALSE);
9199   MOVA (l);
9200   emitcode ("add", "a,acc");
9201   aopPut (result, "a", offset++);
9202   while (--size)
9203     {
9204       l = aopGet (result, offset, FALSE, FALSE);
9205       MOVA (l);
9206       emitcode ("rlc", "a");
9207       aopPut (result, "a", offset++);
9208     }
9209   reAdjustPreg (AOP (result));
9210
9211   emitLabel (tlbl1);
9212   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9213   popB (pushedB);
9214 release:
9215   freeAsmop (result, NULL, ic, TRUE);
9216   freeAsmop (left, NULL, ic, TRUE);
9217 }
9218
9219 /*-----------------------------------------------------------------*/
9220 /* genrshOne - right shift a one byte quantity by known count      */
9221 /*-----------------------------------------------------------------*/
9222 static void
9223 genrshOne (operand * result, operand * left,
9224            int shCount, int sign)
9225 {
9226   D (emitcode (";", "genrshOne"));
9227
9228   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9229 }
9230
9231 /*-----------------------------------------------------------------*/
9232 /* genrshTwo - right shift two bytes by known amount != 0          */
9233 /*-----------------------------------------------------------------*/
9234 static void
9235 genrshTwo (operand * result, operand * left,
9236            int shCount, int sign)
9237 {
9238   D (emitcode (";", "genrshTwo"));
9239
9240   /* if shCount >= 8 */
9241   if (shCount >= 8)
9242     {
9243       shCount -= 8;
9244       if (shCount)
9245         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9246       else
9247         movLeft2Result (left, MSB16, result, LSB, sign);
9248       addSign (result, MSB16, sign);
9249     }
9250
9251   /*  1 <= shCount <= 7 */
9252   else
9253     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9254 }
9255
9256 /*-----------------------------------------------------------------*/
9257 /* shiftRLong - shift right one long from left to result           */
9258 /* offl = LSB or MSB16                                             */
9259 /*-----------------------------------------------------------------*/
9260 static void
9261 shiftRLong (operand * left, int offl,
9262             operand * result, int sign)
9263 {
9264   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9265
9266   if (overlapping && offl>1)
9267     {
9268       // we are in big trouble, but this shouldn't happen
9269       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9270     }
9271
9272   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9273
9274   if (offl==MSB16)
9275     {
9276       // shift is > 8
9277       if (sign)
9278         {
9279           emitcode ("rlc", "a");
9280           emitcode ("subb", "a,acc");
9281           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9282             {
9283               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9284             }
9285           else
9286             {
9287               aopPut (result, "a", MSB32);
9288               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9289             }
9290         }
9291       else
9292         {
9293           if (aopPutUsesAcc (result, zero, MSB32))
9294             {
9295               emitcode("xch", "a,b");
9296               aopPut (result, zero, MSB32);
9297               emitcode("xch", "a,b");
9298             }
9299           else
9300             {
9301               aopPut (result, zero, MSB32);
9302             }
9303         }
9304     }
9305
9306   if (!sign)
9307     {
9308       emitcode ("clr", "c");
9309     }
9310   else
9311     {
9312       emitcode ("mov", "c,acc.7");
9313     }
9314
9315   emitcode ("rrc", "a");
9316
9317   if (overlapping && offl==MSB16 &&
9318       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9319     {
9320       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9321     }
9322   else
9323     {
9324       aopPut (result, "a", MSB32 - offl);
9325       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9326     }
9327
9328   emitcode ("rrc", "a");
9329   if (overlapping && offl==MSB16 &&
9330       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9331     {
9332       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9333     }
9334   else
9335     {
9336       aopPut (result, "a", MSB24 - offl);
9337       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9338     }
9339
9340   emitcode ("rrc", "a");
9341   if (offl != LSB)
9342     {
9343       aopPut (result, "a", MSB16 - offl);
9344     }
9345   else
9346     {
9347       if (overlapping &&
9348           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9349         {
9350           xch_a_aopGet (left, LSB, FALSE, FALSE);
9351         }
9352       else
9353         {
9354           aopPut (result, "a", MSB16 - offl);
9355           MOVA (aopGet (left, LSB, FALSE, FALSE));
9356         }
9357       emitcode ("rrc", "a");
9358       aopPut (result, "a", LSB);
9359     }
9360 }
9361
9362 /*-----------------------------------------------------------------*/
9363 /* genrshFour - shift four byte by a known amount != 0             */
9364 /*-----------------------------------------------------------------*/
9365 static void
9366 genrshFour (operand * result, operand * left,
9367             int shCount, int sign)
9368 {
9369   D (emitcode (";", "genrshFour"));
9370
9371   /* if shifting more that 3 bytes */
9372   if (shCount >= 24)
9373     {
9374       shCount -= 24;
9375       if (shCount)
9376         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9377       else
9378         movLeft2Result (left, MSB32, result, LSB, sign);
9379       addSign (result, MSB16, sign);
9380     }
9381   else if (shCount >= 16)
9382     {
9383       shCount -= 16;
9384       if (shCount)
9385         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9386       else
9387         {
9388           movLeft2Result (left, MSB24, result, LSB, 0);
9389           movLeft2Result (left, MSB32, result, MSB16, sign);
9390         }
9391       addSign (result, MSB24, sign);
9392     }
9393   else if (shCount >= 8)
9394     {
9395       shCount -= 8;
9396       if (shCount == 1)
9397         {
9398           shiftRLong (left, MSB16, result, sign);
9399         }
9400       else if (shCount == 0)
9401         {
9402           movLeft2Result (left, MSB16, result, LSB, 0);
9403           movLeft2Result (left, MSB24, result, MSB16, 0);
9404           movLeft2Result (left, MSB32, result, MSB24, sign);
9405           addSign (result, MSB32, sign);
9406         }
9407       else
9408         {
9409           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9410           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9411           /* the last shift is signed */
9412           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9413           addSign (result, MSB32, sign);
9414         }
9415     }
9416   else
9417     {
9418       /* 1 <= shCount <= 7 */
9419       if (shCount <= 2)
9420         {
9421           shiftRLong (left, LSB, result, sign);
9422           if (shCount == 2)
9423             shiftRLong (result, LSB, result, sign);
9424         }
9425       else
9426         {
9427           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9428           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9429           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9430         }
9431     }
9432 }
9433
9434 /*-----------------------------------------------------------------*/
9435 /* genRightShiftLiteral - right shifting by known count            */
9436 /*-----------------------------------------------------------------*/
9437 static void
9438 genRightShiftLiteral (operand * left,
9439                       operand * right,
9440                       operand * result,
9441                       iCode * ic,
9442                       int sign)
9443 {
9444   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9445   int size;
9446
9447   D (emitcode (";", "genRightShiftLiteral"));
9448
9449   freeAsmop (right, NULL, ic, TRUE);
9450
9451   aopOp (left, ic, FALSE);
9452   aopOp (result, ic, FALSE);
9453
9454 #if VIEW_SIZE
9455   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9456             AOP_SIZE (left));
9457 #endif
9458
9459   size = getDataSize (left);
9460   /* test the LEFT size !!! */
9461
9462   /* I suppose that the left size >= result size */
9463   if (shCount == 0)
9464     {
9465       size = getDataSize (result);
9466       while (size--)
9467         movLeft2Result (left, size, result, size, 0);
9468     }
9469   else if (shCount >= (size * 8))
9470     {
9471       if (sign)
9472         {
9473           /* get sign in acc.7 */
9474           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9475         }
9476       addSign (result, LSB, sign);
9477     }
9478   else
9479     {
9480       switch (size)
9481         {
9482         case 1:
9483           genrshOne (result, left, shCount, sign);
9484           break;
9485
9486         case 2:
9487           genrshTwo (result, left, shCount, sign);
9488           break;
9489
9490         case 4:
9491           genrshFour (result, left, shCount, sign);
9492           break;
9493         default:
9494           break;
9495         }
9496     }
9497   freeAsmop (result, NULL, ic, TRUE);
9498   freeAsmop (left, NULL, ic, TRUE);
9499 }
9500
9501 /*-----------------------------------------------------------------*/
9502 /* genSignedRightShift - right shift of signed number              */
9503 /*-----------------------------------------------------------------*/
9504 static void
9505 genSignedRightShift (iCode * ic)
9506 {
9507   operand *right, *left, *result;
9508   int size, offset;
9509   char *l;
9510   symbol *tlbl, *tlbl1;
9511   bool pushedB;
9512
9513   D (emitcode (";", "genSignedRightShift"));
9514
9515   /* we do it the hard way put the shift count in b
9516      and loop thru preserving the sign */
9517
9518   right = IC_RIGHT (ic);
9519   left = IC_LEFT (ic);
9520   result = IC_RESULT (ic);
9521
9522   aopOp (right, ic, FALSE);
9523
9524
9525   if (AOP_TYPE (right) == AOP_LIT)
9526     {
9527       genRightShiftLiteral (left, right, result, ic, 1);
9528       return;
9529     }
9530   /* shift count is unknown then we have to form
9531      a loop get the loop count in B : Note: we take
9532      only the lower order byte since shifting
9533      more that 32 bits make no sense anyway, ( the
9534      largest size of an object can be only 32 bits ) */
9535
9536   pushedB = pushB ();
9537   MOVB (aopGet (right, 0, FALSE, FALSE));
9538   emitcode ("inc", "b");
9539   freeAsmop (right, NULL, ic, TRUE);
9540   aopOp (left, ic, FALSE);
9541   aopOp (result, ic, FALSE);
9542
9543   /* now move the left to the result if they are not the
9544      same */
9545   if (!sameRegs (AOP (left), AOP (result)) &&
9546       AOP_SIZE (result) > 1)
9547     {
9548
9549       size = AOP_SIZE (result);
9550       offset = 0;
9551       while (size--)
9552         {
9553           l = aopGet (left, offset, FALSE, TRUE);
9554           if (*l == '@' && IS_AOP_PREG (result))
9555             {
9556
9557               emitcode ("mov", "a,%s", l);
9558               aopPut (result, "a", offset);
9559             }
9560           else
9561             aopPut (result, l, offset);
9562           offset++;
9563         }
9564     }
9565
9566   /* mov the highest order bit to OVR */
9567   tlbl = newiTempLabel (NULL);
9568   tlbl1 = newiTempLabel (NULL);
9569
9570   size = AOP_SIZE (result);
9571   offset = size - 1;
9572   MOVA (aopGet (left, offset, FALSE, FALSE));
9573   emitcode ("rlc", "a");
9574   emitcode ("mov", "ov,c");
9575   /* if it is only one byte then */
9576   if (size == 1)
9577     {
9578       l = aopGet (left, 0, FALSE, FALSE);
9579       MOVA (l);
9580       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9581       emitLabel (tlbl);
9582       emitcode ("mov", "c,ov");
9583       emitcode ("rrc", "a");
9584       emitLabel (tlbl1);
9585       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9586       popB (pushedB);
9587       aopPut (result, "a", 0);
9588       goto release;
9589     }
9590
9591   reAdjustPreg (AOP (result));
9592   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9593   emitLabel (tlbl);
9594   emitcode ("mov", "c,ov");
9595   while (size--)
9596     {
9597       l = aopGet (result, offset, FALSE, FALSE);
9598       MOVA (l);
9599       emitcode ("rrc", "a");
9600       aopPut (result, "a", offset--);
9601     }
9602   reAdjustPreg (AOP (result));
9603   emitLabel (tlbl1);
9604   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9605   popB (pushedB);
9606
9607 release:
9608   freeAsmop (result, NULL, ic, TRUE);
9609   freeAsmop (left, NULL, ic, TRUE);
9610 }
9611
9612 /*-----------------------------------------------------------------*/
9613 /* genRightShift - generate code for right shifting                */
9614 /*-----------------------------------------------------------------*/
9615 static void
9616 genRightShift (iCode * ic)
9617 {
9618   operand *right, *left, *result;
9619   sym_link *letype;
9620   int size, offset;
9621   char *l;
9622   symbol *tlbl, *tlbl1;
9623   bool pushedB;
9624
9625   D (emitcode (";", "genRightShift"));
9626
9627   /* if signed then we do it the hard way preserve the
9628      sign bit moving it inwards */
9629   letype = getSpec (operandType (IC_LEFT (ic)));
9630
9631   if (!SPEC_USIGN (letype))
9632     {
9633       genSignedRightShift (ic);
9634       return;
9635     }
9636
9637   /* signed & unsigned types are treated the same : i.e. the
9638      signed is NOT propagated inwards : quoting from the
9639      ANSI - standard : "for E1 >> E2, is equivalent to division
9640      by 2**E2 if unsigned or if it has a non-negative value,
9641      otherwise the result is implementation defined ", MY definition
9642      is that the sign does not get propagated */
9643
9644   right = IC_RIGHT (ic);
9645   left = IC_LEFT (ic);
9646   result = IC_RESULT (ic);
9647
9648   aopOp (right, ic, FALSE);
9649
9650   /* if the shift count is known then do it
9651      as efficiently as possible */
9652   if (AOP_TYPE (right) == AOP_LIT)
9653     {
9654       genRightShiftLiteral (left, right, result, ic, 0);
9655       return;
9656     }
9657
9658   /* shift count is unknown then we have to form
9659      a loop get the loop count in B : Note: we take
9660      only the lower order byte since shifting
9661      more that 32 bits make no sense anyway, ( the
9662      largest size of an object can be only 32 bits ) */
9663
9664   pushedB = pushB ();
9665   MOVB (aopGet (right, 0, FALSE, FALSE));
9666   emitcode ("inc", "b");
9667   freeAsmop (right, NULL, ic, TRUE);
9668   aopOp (left, ic, FALSE);
9669   aopOp (result, ic, FALSE);
9670
9671   /* now move the left to the result if they are not the
9672      same */
9673   if (!sameRegs (AOP (left), AOP (result)) &&
9674       AOP_SIZE (result) > 1)
9675     {
9676       size = AOP_SIZE (result);
9677       offset = 0;
9678       while (size--)
9679         {
9680           l = aopGet (left, offset, FALSE, TRUE);
9681           if (*l == '@' && IS_AOP_PREG (result))
9682             {
9683
9684               emitcode ("mov", "a,%s", l);
9685               aopPut (result, "a", offset);
9686             }
9687           else
9688             aopPut (result, l, offset);
9689           offset++;
9690         }
9691     }
9692
9693   tlbl = newiTempLabel (NULL);
9694   tlbl1 = newiTempLabel (NULL);
9695   size = AOP_SIZE (result);
9696   offset = size - 1;
9697
9698   /* if it is only one byte then */
9699   if (size == 1)
9700     {
9701       l = aopGet (left, 0, FALSE, FALSE);
9702       MOVA (l);
9703       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9704       emitLabel (tlbl);
9705       CLRC;
9706       emitcode ("rrc", "a");
9707       emitLabel (tlbl1);
9708       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9709       popB (pushedB);
9710       aopPut (result, "a", 0);
9711       goto release;
9712     }
9713
9714   reAdjustPreg (AOP (result));
9715   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9716   emitLabel (tlbl);
9717   CLRC;
9718   while (size--)
9719     {
9720       l = aopGet (result, offset, FALSE, FALSE);
9721       MOVA (l);
9722       emitcode ("rrc", "a");
9723       aopPut (result, "a", offset--);
9724     }
9725   reAdjustPreg (AOP (result));
9726
9727   emitLabel (tlbl1);
9728   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9729   popB (pushedB);
9730
9731 release:
9732   freeAsmop (result, NULL, ic, TRUE);
9733   freeAsmop (left, NULL, ic, TRUE);
9734 }
9735
9736 /*-----------------------------------------------------------------*/
9737 /* emitPtrByteGet - emits code to get a byte into A through a      */
9738 /*                  pointer register (R0, R1, or DPTR). The        */
9739 /*                  original value of A can be preserved in B.     */
9740 /*-----------------------------------------------------------------*/
9741 static void
9742 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9743 {
9744   switch (p_type)
9745     {
9746     case IPOINTER:
9747     case POINTER:
9748       if (preserveAinB)
9749         emitcode ("mov", "b,a");
9750       emitcode ("mov", "a,@%s", rname);
9751       break;
9752
9753     case PPOINTER:
9754       if (preserveAinB)
9755         emitcode ("mov", "b,a");
9756       emitcode ("movx", "a,@%s", rname);
9757       break;
9758
9759     case FPOINTER:
9760       if (preserveAinB)
9761         emitcode ("mov", "b,a");
9762       emitcode ("movx", "a,@dptr");
9763       break;
9764
9765     case CPOINTER:
9766       if (preserveAinB)
9767         emitcode ("mov", "b,a");
9768       emitcode ("clr", "a");
9769       emitcode ("movc", "a,@a+dptr");
9770       break;
9771
9772     case GPOINTER:
9773       if (preserveAinB)
9774         {
9775           emitcode ("push", "b");
9776           emitcode ("push", "acc");
9777         }
9778       emitcode ("lcall", "__gptrget");
9779       if (preserveAinB)
9780         emitcode ("pop", "b");
9781       break;
9782     }
9783 }
9784
9785 /*-----------------------------------------------------------------*/
9786 /* emitPtrByteSet - emits code to set a byte from src through a    */
9787 /*                  pointer register (R0, R1, or DPTR).            */
9788 /*-----------------------------------------------------------------*/
9789 static void
9790 emitPtrByteSet (char *rname, int p_type, char *src)
9791 {
9792   switch (p_type)
9793     {
9794     case IPOINTER:
9795     case POINTER:
9796       if (*src=='@')
9797         {
9798           MOVA (src);
9799           emitcode ("mov", "@%s,a", rname);
9800         }
9801       else
9802         emitcode ("mov", "@%s,%s", rname, src);
9803       break;
9804
9805     case PPOINTER:
9806       MOVA (src);
9807       emitcode ("movx", "@%s,a", rname);
9808       break;
9809
9810     case FPOINTER:
9811       MOVA (src);
9812       emitcode ("movx", "@dptr,a");
9813       break;
9814
9815     case GPOINTER:
9816       MOVA (src);
9817       emitcode ("lcall", "__gptrput");
9818       break;
9819     }
9820 }
9821
9822 /*-----------------------------------------------------------------*/
9823 /* genUnpackBits - generates code for unpacking bits               */
9824 /*-----------------------------------------------------------------*/
9825 static char*
9826 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9827 {
9828   int offset = 0;       /* result byte offset */
9829   int rsize;            /* result size */
9830   int rlen = 0;         /* remaining bitfield length */
9831   sym_link *etype;      /* bitfield type information */
9832   int blen;             /* bitfield length */
9833   int bstr;             /* bitfield starting bit within byte */
9834   static char* const accBits[] = {"acc.0", "acc.1", "acc.2", "acc.3",
9835                                   "acc.4", "acc.5", "acc.6", "acc.7"};
9836
9837   D(emitcode (";", "genUnpackBits"));
9838
9839   etype = getSpec (operandType (result));
9840   rsize = getSize (operandType (result));
9841   blen = SPEC_BLEN (etype);
9842   bstr = SPEC_BSTR (etype);
9843
9844   if (ifx && blen <= 8)
9845     {
9846       emitPtrByteGet (rname, ptype, FALSE);
9847       if (blen == 1)
9848         {
9849           return accBits[bstr];;
9850         }
9851       else
9852         {
9853           if (blen < 8)
9854             emitcode ("anl", "a,#0x%02x",
9855                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9856           return "a";
9857         }
9858     }
9859   wassert (!ifx);
9860
9861   /* If the bitfield length is less than a byte */
9862   if (blen < 8)
9863     {
9864       emitPtrByteGet (rname, ptype, FALSE);
9865       AccRol (8 - bstr);
9866       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9867       if (!SPEC_USIGN (etype))
9868         {
9869           /* signed bitfield */
9870           symbol *tlbl = newiTempLabel (NULL);
9871
9872           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9873           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9874           emitLabel (tlbl);
9875         }
9876       aopPut (result, "a", offset++);
9877       goto finish;
9878     }
9879
9880   /* Bit field did not fit in a byte. Copy all
9881      but the partial byte at the end.  */
9882   for (rlen=blen;rlen>=8;rlen-=8)
9883     {
9884       emitPtrByteGet (rname, ptype, FALSE);
9885       aopPut (result, "a", offset++);
9886       if (rlen>8)
9887         emitcode ("inc", "%s", rname);
9888     }
9889
9890   /* Handle the partial byte at the end */
9891   if (rlen)
9892     {
9893       emitPtrByteGet (rname, ptype, FALSE);
9894       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9895       if (!SPEC_USIGN (etype))
9896         {
9897           /* signed bitfield */
9898           symbol *tlbl = newiTempLabel (NULL);
9899
9900           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9901           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9902           emitLabel (tlbl);
9903         }
9904       aopPut (result, "a", offset++);
9905     }
9906
9907 finish:
9908   if (offset < rsize)
9909     {
9910       char *source;
9911
9912       if (SPEC_USIGN (etype))
9913         source = zero;
9914       else
9915         {
9916           /* signed bitfield: sign extension with 0x00 or 0xff */
9917           emitcode ("rlc", "a");
9918           emitcode ("subb", "a,acc");
9919
9920           source = "a";
9921         }
9922       rsize -= offset;
9923       while (rsize--)
9924         aopPut (result, source, offset++);
9925     }
9926   return NULL;
9927 }
9928
9929
9930 /*-----------------------------------------------------------------*/
9931 /* genDataPointerGet - generates code when ptr offset is known     */
9932 /*-----------------------------------------------------------------*/
9933 static void
9934 genDataPointerGet (operand * left,
9935                    operand * result,
9936                    iCode * ic)
9937 {
9938   char *l;
9939   char buffer[256];
9940   int size, offset = 0;
9941
9942   D (emitcode (";", "genDataPointerGet"));
9943
9944   aopOp (result, ic, TRUE);
9945
9946   /* get the string representation of the name */
9947   l = aopGet (left, 0, FALSE, TRUE);
9948   l++; // remove #
9949   size = AOP_SIZE (result);
9950   while (size--)
9951     {
9952       if (offset)
9953         {
9954           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9955         }
9956       else
9957         {
9958           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9959         }
9960       aopPut (result, buffer, offset++);
9961     }
9962
9963   freeAsmop (result, NULL, ic, TRUE);
9964   freeAsmop (left, NULL, ic, TRUE);
9965 }
9966
9967 /*-----------------------------------------------------------------*/
9968 /* genNearPointerGet - emitcode for near pointer fetch             */
9969 /*-----------------------------------------------------------------*/
9970 static void
9971 genNearPointerGet (operand * left,
9972                    operand * result,
9973                    iCode * ic,
9974                    iCode * pi,
9975                    iCode * ifx)
9976 {
9977   asmop *aop = NULL;
9978   regs *preg = NULL;
9979   char *rname;
9980   char *ifxCond = "a";
9981   sym_link *rtype, *retype;
9982   sym_link *ltype = operandType (left);
9983
9984   D (emitcode (";", "genNearPointerGet"));
9985
9986   rtype = operandType (result);
9987   retype = getSpec (rtype);
9988
9989   aopOp (left, ic, FALSE);
9990
9991   /* if left is rematerialisable and
9992      result is not bitfield variable type and
9993      the left is pointer to data space i.e
9994      lower 128 bytes of space */
9995   if (AOP_TYPE (left) == AOP_IMMD &&
9996       !IS_BITFIELD (retype) &&
9997       DCL_TYPE (ltype) == POINTER)
9998     {
9999       genDataPointerGet (left, result, ic);
10000       return;
10001     }
10002
10003   //aopOp (result, ic, FALSE);
10004   aopOp (result, ic, result?TRUE:FALSE);
10005
10006  /* if the value is already in a pointer register
10007      then don't need anything more */
10008   if (!AOP_INPREG (AOP (left)))
10009     {
10010       if (IS_AOP_PREG (left))
10011         {
10012           // Aha, it is a pointer, just in disguise.
10013           rname = aopGet (left, 0, FALSE, FALSE);
10014           if (*rname != '@')
10015             {
10016               fprintf(stderr, "probable internal error: unexpected rname '%s' @ %s:%d\n",
10017                       rname, __FILE__, __LINE__);
10018             }
10019           else
10020             {
10021               // Expected case.
10022               emitcode ("mov", "a%s,%s", rname + 1, rname);
10023               rname++;  // skip the '@'.
10024             }
10025         }
10026       else
10027         {
10028           /* otherwise get a free pointer register */
10029           aop = newAsmop (0);
10030           preg = getFreePtr (ic, &aop, FALSE);
10031           emitcode ("mov", "%s,%s",
10032                     preg->name,
10033                     aopGet (left, 0, FALSE, TRUE));
10034           rname = preg->name;
10035         }
10036     }
10037   else
10038     rname = aopGet (left, 0, FALSE, FALSE);
10039
10040   /* if bitfield then unpack the bits */
10041   if (IS_BITFIELD (retype))
10042     ifxCond = genUnpackBits (result, rname, POINTER, ifx);
10043   else
10044     {
10045       /* we have can just get the values */
10046       int size = AOP_SIZE (result);
10047       int offset = 0;
10048
10049       while (size--)
10050         {
10051           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10052             {
10053
10054               emitcode ("mov", "a,@%s", rname);
10055               if (!ifx)
10056                 aopPut (result, "a", offset);
10057             }
10058           else
10059             {
10060               char buffer[80];
10061
10062               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10063               aopPut (result, buffer, offset);
10064             }
10065           offset++;
10066           if (size || pi)
10067             emitcode ("inc", "%s", rname);
10068         }
10069     }
10070
10071   /* now some housekeeping stuff */
10072   if (aop)      /* we had to allocate for this iCode */
10073     {
10074       if (pi) { /* post increment present */
10075         aopPut (left, rname, 0);
10076       }
10077       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10078     }
10079   else
10080     {
10081       /* we did not allocate which means left
10082          already in a pointer register, then
10083          if size > 0 && this could be used again
10084          we have to point it back to where it
10085          belongs */
10086       if ((AOP_SIZE (result) > 1 &&
10087            !OP_SYMBOL (left)->remat &&
10088            (OP_SYMBOL (left)->liveTo > ic->seq ||
10089             ic->depth)) &&
10090           !pi)
10091         {
10092           int size = AOP_SIZE (result) - 1;
10093           while (size--)
10094             emitcode ("dec", "%s", rname);
10095         }
10096     }
10097
10098   if (ifx && !ifx->generated)
10099     {
10100       genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
10101     }
10102
10103   /* done */
10104   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10105   freeAsmop (left, NULL, ic, TRUE);
10106   if (pi) pi->generated = 1;
10107 }
10108
10109 /*-----------------------------------------------------------------*/
10110 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10111 /*-----------------------------------------------------------------*/
10112 static void
10113 genPagedPointerGet (operand * left,
10114                     operand * result,
10115                     iCode * ic,
10116                     iCode *pi,
10117                     iCode *ifx)
10118 {
10119   asmop *aop = NULL;
10120   regs *preg = NULL;
10121   char *rname;
10122   char *ifxCond = "a";
10123   sym_link *rtype, *retype;
10124
10125   D (emitcode (";", "genPagedPointerGet"));
10126
10127   rtype = operandType (result);
10128   retype = getSpec (rtype);
10129
10130   aopOp (left, ic, FALSE);
10131
10132   aopOp (result, ic, FALSE);
10133
10134   /* if the value is already in a pointer register
10135      then don't need anything more */
10136   if (!AOP_INPREG (AOP (left)))
10137     {
10138       /* otherwise get a free pointer register */
10139       aop = newAsmop (0);
10140       preg = getFreePtr (ic, &aop, FALSE);
10141       emitcode ("mov", "%s,%s",
10142                 preg->name,
10143                 aopGet (left, 0, FALSE, TRUE));
10144       rname = preg->name;
10145     }
10146   else
10147     rname = aopGet (left, 0, FALSE, FALSE);
10148
10149   /* if bitfield then unpack the bits */
10150   if (IS_BITFIELD (retype))
10151     ifxCond = genUnpackBits (result, rname, PPOINTER, ifx);
10152   else
10153     {
10154       /* we have can just get the values */
10155       int size = AOP_SIZE (result);
10156       int offset = 0;
10157
10158       while (size--)
10159         {
10160
10161           emitcode ("movx", "a,@%s", rname);
10162           if (!ifx)
10163             aopPut (result, "a", offset);
10164
10165           offset++;
10166
10167           if (size || pi)
10168             emitcode ("inc", "%s", rname);
10169         }
10170     }
10171
10172   /* now some housekeeping stuff */
10173   if (aop)      /* we had to allocate for this iCode */
10174     {
10175       if (pi)
10176         aopPut (left, rname, 0);
10177       freeAsmop (NULL, aop, ic, TRUE);
10178     }
10179   else
10180     {
10181       /* we did not allocate which means left
10182          already in a pointer register, then
10183          if size > 0 && this could be used again
10184          we have to point it back to where it
10185          belongs */
10186       if ((AOP_SIZE (result) > 1 &&
10187            !OP_SYMBOL (left)->remat &&
10188            (OP_SYMBOL (left)->liveTo > ic->seq ||
10189             ic->depth)) &&
10190           !pi)
10191         {
10192           int size = AOP_SIZE (result) - 1;
10193           while (size--)
10194             emitcode ("dec", "%s", rname);
10195         }
10196     }
10197
10198   if (ifx && !ifx->generated)
10199     {
10200       genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
10201     }
10202
10203   /* done */
10204   freeAsmop (result, NULL, ic, TRUE);
10205   freeAsmop (left, NULL, ic, TRUE);
10206   if (pi) pi->generated = 1;
10207 }
10208
10209 /*--------------------------------------------------------------------*/
10210 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10211 /*--------------------------------------------------------------------*/
10212 static void
10213 loadDptrFromOperand (operand *op, bool loadBToo)
10214 {
10215   if (AOP_TYPE (op) != AOP_STR)
10216     {
10217       /* if this is rematerializable */
10218       if (AOP_TYPE (op) == AOP_IMMD)
10219         {
10220           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10221           if (loadBToo)
10222             {
10223               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10224                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10225               else
10226                 {
10227                   wassertl(FALSE, "need pointerCode");
10228                   emitcode (";", "mov b,???");
10229                   /* genPointerGet and genPointerSet originally did different
10230                   ** things for this case. Both seem wrong.
10231                   ** from genPointerGet:
10232                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10233                   ** from genPointerSet:
10234                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10235                   */
10236                 }
10237             }
10238         }
10239       else if (AOP_TYPE (op) == AOP_DPTR)
10240         {
10241           if (loadBToo)
10242             {
10243               MOVA (aopGet (op, 0, FALSE, FALSE));
10244               emitcode ("push", "acc");
10245               MOVA (aopGet (op, 1, FALSE, FALSE));
10246               emitcode ("push", "acc");
10247               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10248               emitcode ("pop", "dph");
10249               emitcode ("pop", "dpl");
10250             }
10251           else
10252             {
10253               MOVA (aopGet (op, 0, FALSE, FALSE));
10254               emitcode ("push", "acc");
10255               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10256               emitcode ("pop", "dpl");
10257             }
10258         }
10259       else
10260         {                       /* we need to get it byte by byte */
10261           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10262           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10263           if (loadBToo)
10264             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10265         }
10266     }
10267 }
10268
10269 /*-----------------------------------------------------------------*/
10270 /* genFarPointerGet - get value from far space                     */
10271 /*-----------------------------------------------------------------*/
10272 static void
10273 genFarPointerGet (operand * left,
10274                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10275 {
10276   int size, offset;
10277   char *ifxCond = "a";
10278   sym_link *retype = getSpec (operandType (result));
10279
10280   D (emitcode (";", "genFarPointerGet"));
10281
10282   aopOp (left, ic, FALSE);
10283   loadDptrFromOperand (left, FALSE);
10284
10285   /* so dptr now contains the address */
10286   aopOp (result, ic, FALSE);
10287
10288   /* if bit then unpack */
10289   if (IS_BITFIELD (retype))
10290     ifxCond = genUnpackBits (result, "dptr", FPOINTER, ifx);
10291   else
10292     {
10293       size = AOP_SIZE (result);
10294       offset = 0;
10295
10296       while (size--)
10297         {
10298           emitcode ("movx", "a,@dptr");
10299           if (!ifx)
10300             aopPut (result, "a", offset++);
10301           if (size || pi)
10302             emitcode ("inc", "dptr");
10303         }
10304     }
10305
10306   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10307     {
10308       aopPut (left, "dpl", 0);
10309       aopPut (left, "dph", 1);
10310       pi->generated = 1;
10311     }
10312
10313   if (ifx && !ifx->generated)
10314     {
10315       genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
10316     }
10317
10318   freeAsmop (result, NULL, ic, TRUE);
10319   freeAsmop (left, NULL, ic, TRUE);
10320 }
10321
10322 /*-----------------------------------------------------------------*/
10323 /* genCodePointerGet - get value from code space                   */
10324 /*-----------------------------------------------------------------*/
10325 static void
10326 genCodePointerGet (operand * left,
10327                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10328 {
10329   int size, offset;
10330   char *ifxCond = "a";
10331   sym_link *retype = getSpec (operandType (result));
10332
10333   D (emitcode (";", "genCodePointerGet"));
10334
10335   aopOp (left, ic, FALSE);
10336   loadDptrFromOperand (left, FALSE);
10337
10338   /* so dptr now contains the address */
10339   aopOp (result, ic, FALSE);
10340
10341   /* if bit then unpack */
10342   if (IS_BITFIELD (retype))
10343     ifxCond = genUnpackBits (result, "dptr", CPOINTER, ifx);
10344   else
10345     {
10346       size = AOP_SIZE (result);
10347       offset = 0;
10348
10349       while (size--)
10350         {
10351           emitcode ("clr", "a");
10352           emitcode ("movc", "a,@a+dptr");
10353           if (!ifx)
10354             aopPut (result, "a", offset++);
10355           if (size || pi)
10356             emitcode ("inc", "dptr");
10357         }
10358     }
10359
10360   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10361     {
10362       aopPut (left, "dpl", 0);
10363       aopPut (left, "dph", 1);
10364       pi->generated = 1;
10365     }
10366
10367   if (ifx && !ifx->generated)
10368     {
10369       genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
10370     }
10371
10372   freeAsmop (result, NULL, ic, TRUE);
10373   freeAsmop (left, NULL, ic, TRUE);
10374 }
10375
10376 /*-----------------------------------------------------------------*/
10377 /* genGenPointerGet - get value from generic pointer space         */
10378 /*-----------------------------------------------------------------*/
10379 static void
10380 genGenPointerGet (operand * left,
10381                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10382 {
10383   int size, offset;
10384   char *ifxCond = "a";
10385   sym_link *retype = getSpec (operandType (result));
10386
10387   D (emitcode (";", "genGenPointerGet"));
10388
10389   aopOp (left, ic, FALSE);
10390   loadDptrFromOperand (left, TRUE);
10391
10392   /* so dptr now contains the address */
10393   aopOp (result, ic, FALSE);
10394
10395   /* if bit then unpack */
10396   if (IS_BITFIELD (retype))
10397     {
10398       ifxCond = genUnpackBits (result, "dptr", GPOINTER, ifx);
10399     }
10400   else
10401     {
10402       size = AOP_SIZE (result);
10403       offset = 0;
10404
10405       while (size--)
10406         {
10407           emitcode ("lcall", "__gptrget");
10408           if (!ifx)
10409             aopPut (result, "a", offset++);
10410           if (size || pi)
10411             emitcode ("inc", "dptr");
10412         }
10413     }
10414
10415   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10416     {
10417       aopPut (left, "dpl", 0);
10418       aopPut (left, "dph", 1);
10419       pi->generated = 1;
10420     }
10421
10422   if (ifx && !ifx->generated)
10423     {
10424       genIfxJump (ifx, ifxCond, left, NULL, result, ic->next);
10425     }
10426
10427   freeAsmop (result, NULL, ic, TRUE);
10428   freeAsmop (left, NULL, ic, TRUE);
10429 }
10430
10431 /*-----------------------------------------------------------------*/
10432 /* genPointerGet - generate code for pointer get                   */
10433 /*-----------------------------------------------------------------*/
10434 static void
10435 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10436 {
10437   operand *left, *result;
10438   sym_link *type, *etype;
10439   int p_type;
10440
10441   D (emitcode (";", "genPointerGet"));
10442
10443   left = IC_LEFT (ic);
10444   result = IC_RESULT (ic);
10445
10446   if (getSize (operandType (result))>1)
10447     ifx = NULL;
10448
10449   /* depending on the type of pointer we need to
10450      move it to the correct pointer register */
10451   type = operandType (left);
10452   etype = getSpec (type);
10453   /* if left is of type of pointer then it is simple */
10454   if (IS_PTR (type) && !IS_FUNC (type->next))
10455     {
10456       p_type = DCL_TYPE (type);
10457     }
10458   else
10459     {
10460       /* we have to go by the storage class */
10461       p_type = PTR_TYPE (SPEC_OCLS (etype));
10462     }
10463
10464   /* special case when cast remat */
10465   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10466       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10467     {
10468       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10469       type = operandType (left);
10470       p_type = DCL_TYPE (type);
10471     }
10472   /* now that we have the pointer type we assign
10473      the pointer values */
10474   switch (p_type)
10475     {
10476
10477     case POINTER:
10478     case IPOINTER:
10479       genNearPointerGet (left, result, ic, pi, ifx);
10480       break;
10481
10482     case PPOINTER:
10483       genPagedPointerGet (left, result, ic, pi, ifx);
10484       break;
10485
10486     case FPOINTER:
10487       genFarPointerGet (left, result, ic, pi, ifx);
10488       break;
10489
10490     case CPOINTER:
10491       genCodePointerGet (left, result, ic, pi, ifx);
10492       break;
10493
10494     case GPOINTER:
10495       genGenPointerGet (left, result, ic, pi, ifx);
10496       break;
10497     }
10498 }
10499
10500
10501 /*-----------------------------------------------------------------*/
10502 /* genPackBits - generates code for packed bit storage             */
10503 /*-----------------------------------------------------------------*/
10504 static void
10505 genPackBits (sym_link * etype,
10506              operand * right,
10507              char *rname, int p_type)
10508 {
10509   int offset = 0;       /* source byte offset */
10510   int rlen = 0;         /* remaining bitfield length */
10511   int blen;             /* bitfield length */
10512   int bstr;             /* bitfield starting bit within byte */
10513   int litval;           /* source literal value (if AOP_LIT) */
10514   unsigned char mask;   /* bitmask within current byte */
10515
10516   D(emitcode (";", "genPackBits"));
10517
10518   blen = SPEC_BLEN (etype);
10519   bstr = SPEC_BSTR (etype);
10520
10521   /* If the bitfield length is less than a byte */
10522   if (blen < 8)
10523     {
10524       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10525               (unsigned char) (0xFF >> (8 - bstr)));
10526
10527       if (AOP_TYPE (right) == AOP_LIT)
10528         {
10529           /* Case with a bitfield length <8 and literal source
10530           */
10531           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10532           litval <<= bstr;
10533           litval &= (~mask) & 0xff;
10534           emitPtrByteGet (rname, p_type, FALSE);
10535           if ((mask|litval)!=0xff)
10536             emitcode ("anl","a,#0x%02x", mask);
10537           if (litval)
10538             emitcode ("orl","a,#0x%02x", litval);
10539         }
10540       else
10541         {
10542           if ((blen==1) && (p_type!=GPOINTER))
10543             {
10544               /* Case with a bitfield length == 1 and no generic pointer
10545               */
10546               if (AOP_TYPE (right) == AOP_CRY)
10547                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10548               else
10549                 {
10550                   MOVA (aopGet (right, 0, FALSE, FALSE));
10551                   emitcode ("rrc","a");
10552                 }
10553               emitPtrByteGet (rname, p_type, FALSE);
10554               emitcode ("mov","acc.%d,c",bstr);
10555             }
10556           else
10557             {
10558               bool pushedB;
10559               /* Case with a bitfield length < 8 and arbitrary source
10560               */
10561               MOVA (aopGet (right, 0, FALSE, FALSE));
10562               /* shift and mask source value */
10563               AccLsh (bstr);
10564               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10565
10566               pushedB = pushB ();
10567               /* transfer A to B and get next byte */
10568               emitPtrByteGet (rname, p_type, TRUE);
10569
10570               emitcode ("anl", "a,#0x%02x", mask);
10571               emitcode ("orl", "a,b");
10572               if (p_type == GPOINTER)
10573                 emitcode ("pop", "b");
10574
10575               popB (pushedB);
10576            }
10577         }
10578
10579       emitPtrByteSet (rname, p_type, "a");
10580       return;
10581     }
10582
10583   /* Bit length is greater than 7 bits. In this case, copy  */
10584   /* all except the partial byte at the end                 */
10585   for (rlen=blen;rlen>=8;rlen-=8)
10586     {
10587       emitPtrByteSet (rname, p_type,
10588                       aopGet (right, offset++, FALSE, TRUE) );
10589       if (rlen>8)
10590         emitcode ("inc", "%s", rname);
10591     }
10592
10593   /* If there was a partial byte at the end */
10594   if (rlen)
10595     {
10596       mask = (((unsigned char) -1 << rlen) & 0xff);
10597
10598       if (AOP_TYPE (right) == AOP_LIT)
10599         {
10600           /* Case with partial byte and literal source
10601           */
10602           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10603           litval >>= (blen-rlen);
10604           litval &= (~mask) & 0xff;
10605           emitPtrByteGet (rname, p_type, FALSE);
10606           if ((mask|litval)!=0xff)
10607             emitcode ("anl","a,#0x%02x", mask);
10608           if (litval)
10609             emitcode ("orl","a,#0x%02x", litval);
10610         }
10611       else
10612         {
10613           bool pushedB;
10614           /* Case with partial byte and arbitrary source
10615           */
10616           MOVA (aopGet (right, offset++, FALSE, FALSE));
10617           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10618
10619           pushedB = pushB ();
10620           /* transfer A to B and get next byte */
10621           emitPtrByteGet (rname, p_type, TRUE);
10622
10623           emitcode ("anl", "a,#0x%02x", mask);
10624           emitcode ("orl", "a,b");
10625           if (p_type == GPOINTER)
10626             emitcode ("pop", "b");
10627
10628           popB (pushedB);
10629         }
10630       emitPtrByteSet (rname, p_type, "a");
10631     }
10632 }
10633
10634
10635 /*-----------------------------------------------------------------*/
10636 /* genDataPointerSet - remat pointer to data space                 */
10637 /*-----------------------------------------------------------------*/
10638 static void
10639 genDataPointerSet (operand * right,
10640                    operand * result,
10641                    iCode * ic)
10642 {
10643   int size, offset = 0;
10644   char *l, buffer[256];
10645
10646   D (emitcode (";", "genDataPointerSet"));
10647
10648   aopOp (right, ic, FALSE);
10649
10650   l = aopGet (result, 0, FALSE, TRUE);
10651   l++; //remove #
10652   size = max (AOP_SIZE (right), AOP_SIZE (result));
10653   while (size--)
10654     {
10655       if (offset)
10656         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10657       else
10658         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10659       emitcode ("mov", "%s,%s", buffer,
10660                 aopGet (right, offset++, FALSE, FALSE));
10661     }
10662
10663   freeAsmop (right, NULL, ic, TRUE);
10664   freeAsmop (result, NULL, ic, TRUE);
10665 }
10666
10667 /*-----------------------------------------------------------------*/
10668 /* genNearPointerSet - emitcode for near pointer put               */
10669 /*-----------------------------------------------------------------*/
10670 static void
10671 genNearPointerSet (operand * right,
10672                    operand * result,
10673                    iCode * ic,
10674                    iCode * pi)
10675 {
10676   asmop *aop = NULL;
10677   regs *preg = NULL;
10678   char *rname, *l;
10679   sym_link *retype, *letype;
10680   sym_link *ptype = operandType (result);
10681
10682   D (emitcode (";", "genNearPointerSet"));
10683
10684   retype = getSpec (operandType (right));
10685   letype = getSpec (ptype);
10686
10687   aopOp (result, ic, FALSE);
10688
10689   /* if the result is rematerializable &
10690      in data space & not a bit variable */
10691   if (AOP_TYPE (result) == AOP_IMMD &&
10692       DCL_TYPE (ptype) == POINTER &&
10693       !IS_BITVAR (retype) &&
10694       !IS_BITVAR (letype))
10695     {
10696       genDataPointerSet (right, result, ic);
10697       return;
10698     }
10699
10700   /* if the value is already in a pointer register
10701      then don't need anything more */
10702   if (!AOP_INPREG (AOP (result)))
10703     {
10704       if (IS_AOP_PREG (result))
10705         {
10706           // Aha, it is a pointer, just in disguise.
10707           rname = aopGet (result, 0, FALSE, FALSE);
10708           if (*rname != '@')
10709             {
10710               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10711                       __FILE__, __LINE__);
10712             }
10713           else
10714             {
10715               // Expected case.
10716               emitcode ("mov", "a%s,%s", rname + 1, rname);
10717               rname++;  // skip the '@'.
10718             }
10719         }
10720       else
10721         {
10722           /* otherwise get a free pointer register */
10723           aop = newAsmop (0);
10724           preg = getFreePtr (ic, &aop, FALSE);
10725           emitcode ("mov", "%s,%s",
10726                     preg->name,
10727                     aopGet (result, 0, FALSE, TRUE));
10728           rname = preg->name;
10729         }
10730     }
10731   else
10732     {
10733       rname = aopGet (result, 0, FALSE, FALSE);
10734     }
10735
10736   aopOp (right, ic, FALSE);
10737
10738   /* if bitfield then unpack the bits */
10739   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10740     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10741   else
10742     {
10743       /* we can just get the values */
10744       int size = AOP_SIZE (right);
10745       int offset = 0;
10746
10747       while (size--)
10748         {
10749           l = aopGet (right, offset, FALSE, TRUE);
10750           if ((*l == '@') || (strcmp (l, "acc") == 0))
10751             {
10752               MOVA (l);
10753               emitcode ("mov", "@%s,a", rname);
10754             }
10755           else
10756             emitcode ("mov", "@%s,%s", rname, l);
10757           if (size || pi)
10758             emitcode ("inc", "%s", rname);
10759           offset++;
10760         }
10761     }
10762
10763   /* now some housekeeping stuff */
10764   if (aop)      /* we had to allocate for this iCode */
10765     {
10766       if (pi)
10767         aopPut (result, rname, 0);
10768       freeAsmop (NULL, aop, ic, TRUE);
10769     }
10770   else
10771     {
10772       /* we did not allocate which means left
10773          already in a pointer register, then
10774          if size > 0 && this could be used again
10775          we have to point it back to where it
10776          belongs */
10777       if ((AOP_SIZE (right) > 1 &&
10778            !OP_SYMBOL (result)->remat &&
10779            (OP_SYMBOL (result)->liveTo > ic->seq ||
10780             ic->depth)) &&
10781           !pi)
10782         {
10783           int size = AOP_SIZE (right) - 1;
10784           while (size--)
10785             emitcode ("dec", "%s", rname);
10786         }
10787     }
10788
10789   /* done */
10790   if (pi)
10791     pi->generated = 1;
10792   freeAsmop (right, NULL, ic, TRUE);
10793   freeAsmop (result, NULL, ic, TRUE);
10794 }
10795
10796 /*-----------------------------------------------------------------*/
10797 /* genPagedPointerSet - emitcode for Paged pointer put             */
10798 /*-----------------------------------------------------------------*/
10799 static void
10800 genPagedPointerSet (operand * right,
10801                     operand * result,
10802                     iCode * ic,
10803                     iCode * pi)
10804 {
10805   asmop *aop = NULL;
10806   regs *preg = NULL;
10807   char *rname, *l;
10808   sym_link *retype, *letype;
10809
10810   D (emitcode (";", "genPagedPointerSet"));
10811
10812   retype = getSpec (operandType (right));
10813   letype = getSpec (operandType (result));
10814
10815   aopOp (result, ic, FALSE);
10816
10817   /* if the value is already in a pointer register
10818      then don't need anything more */
10819   if (!AOP_INPREG (AOP (result)))
10820     {
10821       if (IS_AOP_PREG (result))
10822         {
10823           // Aha, it is a pointer, just in disguise.
10824           rname = aopGet (result, 0, FALSE, FALSE);
10825           if (*rname != '@')
10826             {
10827               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10828                       __FILE__, __LINE__);
10829             }
10830           else
10831             {
10832               // Expected case.
10833               emitcode ("mov", "a%s,%s", rname + 1, rname);
10834               rname++;  // skip the '@'.
10835             }
10836         }
10837       else
10838         {
10839           /* otherwise get a free pointer register */
10840           aop = newAsmop (0);
10841           preg = getFreePtr (ic, &aop, FALSE);
10842           emitcode ("mov", "%s,%s",
10843                     preg->name,
10844                     aopGet (result, 0, FALSE, TRUE));
10845           rname = preg->name;
10846         }
10847     }
10848   else
10849     {
10850       rname = aopGet (result, 0, FALSE, FALSE);
10851     }
10852
10853   aopOp (right, ic, FALSE);
10854
10855   /* if bitfield then unpack the bits */
10856   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10857     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10858   else
10859     {
10860       /* we can just get the values */
10861       int size = AOP_SIZE (right);
10862       int offset = 0;
10863
10864       while (size--)
10865         {
10866           l = aopGet (right, offset, FALSE, TRUE);
10867           MOVA (l);
10868           emitcode ("movx", "@%s,a", rname);
10869           if (size || pi)
10870             emitcode ("inc", "%s", rname);
10871           offset++;
10872         }
10873     }
10874
10875   /* now some housekeeping stuff */
10876   if (aop) /* we had to allocate for this iCode */
10877     {
10878       if (pi)
10879         aopPut (result, rname, 0);
10880       freeAsmop (NULL, aop, ic, TRUE);
10881     }
10882   else
10883     {
10884       /* we did not allocate which means left
10885          already in a pointer register, then
10886          if size > 0 && this could be used again
10887          we have to point it back to where it
10888          belongs */
10889       if (AOP_SIZE (right) > 1 &&
10890           !OP_SYMBOL (result)->remat &&
10891           (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) &&
10892           !pi)
10893         {
10894           int size = AOP_SIZE (right) - 1;
10895           while (size--)
10896             emitcode ("dec", "%s", rname);
10897         }
10898     }
10899
10900   /* done */
10901   if (pi)
10902     pi->generated = 1;
10903   freeAsmop (right, NULL, ic, TRUE);
10904   freeAsmop (result, NULL, ic, TRUE);
10905 }
10906
10907 /*-----------------------------------------------------------------*/
10908 /* genFarPointerSet - set value from far space                     */
10909 /*-----------------------------------------------------------------*/
10910 static void
10911 genFarPointerSet (operand * right,
10912                   operand * result, iCode * ic, iCode * pi)
10913 {
10914   int size, offset;
10915   sym_link *retype = getSpec (operandType (right));
10916   sym_link *letype = getSpec (operandType (result));
10917
10918   D(emitcode (";", "genFarPointerSet"));
10919
10920   aopOp (result, ic, FALSE);
10921   loadDptrFromOperand (result, FALSE);
10922
10923   /* so dptr now contains the address */
10924   aopOp (right, ic, FALSE);
10925
10926   /* if bit then unpack */
10927   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10928     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10929   else
10930     {
10931       size = AOP_SIZE (right);
10932       offset = 0;
10933
10934       while (size--)
10935         {
10936           char *l = aopGet (right, offset++, FALSE, FALSE);
10937           MOVA (l);
10938           emitcode ("movx", "@dptr,a");
10939           if (size || pi)
10940             emitcode ("inc", "dptr");
10941         }
10942     }
10943   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10944     aopPut (result, "dpl", 0);
10945     aopPut (result, "dph", 1);
10946     pi->generated=1;
10947   }
10948   freeAsmop (result, NULL, ic, TRUE);
10949   freeAsmop (right, NULL, ic, TRUE);
10950 }
10951
10952 /*-----------------------------------------------------------------*/
10953 /* genGenPointerSet - set value from generic pointer space         */
10954 /*-----------------------------------------------------------------*/
10955 static void
10956 genGenPointerSet (operand * right,
10957                   operand * result, iCode * ic, iCode * pi)
10958 {
10959   int size, offset;
10960   sym_link *retype = getSpec (operandType (right));
10961   sym_link *letype = getSpec (operandType (result));
10962
10963   D (emitcode (";", "genGenPointerSet"));
10964
10965   aopOp (result, ic, FALSE);
10966   loadDptrFromOperand (result, TRUE);
10967
10968   /* so dptr now contains the address */
10969   aopOp (right, ic, FALSE);
10970
10971   /* if bit then unpack */
10972   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10973     {
10974       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10975     }
10976   else
10977     {
10978       size = AOP_SIZE (right);
10979       offset = 0;
10980
10981       while (size--)
10982         {
10983           char *l = aopGet (right, offset++, FALSE, FALSE);
10984           MOVA (l);
10985           emitcode ("lcall", "__gptrput");
10986           if (size || pi)
10987             emitcode ("inc", "dptr");
10988         }
10989     }
10990
10991   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10992     aopPut (result, "dpl", 0);
10993     aopPut (result, "dph", 1);
10994     pi->generated=1;
10995   }
10996   freeAsmop (result, NULL, ic, TRUE);
10997   freeAsmop (right, NULL, ic, TRUE);
10998 }
10999
11000 /*-----------------------------------------------------------------*/
11001 /* genPointerSet - stores the value into a pointer location        */
11002 /*-----------------------------------------------------------------*/
11003 static void
11004 genPointerSet (iCode * ic, iCode *pi)
11005 {
11006   operand *right, *result;
11007   sym_link *type, *etype;
11008   int p_type;
11009
11010   D (emitcode (";", "genPointerSet"));
11011
11012   right = IC_RIGHT (ic);
11013   result = IC_RESULT (ic);
11014
11015   /* depending on the type of pointer we need to
11016      move it to the correct pointer register */
11017   type = operandType (result);
11018   etype = getSpec (type);
11019   /* if left is of type of pointer then it is simple */
11020   if (IS_PTR (type) && !IS_FUNC (type->next))
11021     {
11022       p_type = DCL_TYPE (type);
11023     }
11024   else
11025     {
11026       /* we have to go by the storage class */
11027       p_type = PTR_TYPE (SPEC_OCLS (etype));
11028     }
11029
11030   /* special case when cast remat */
11031   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11032       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11033           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11034           type = operandType (result);
11035           p_type = DCL_TYPE (type);
11036   }
11037
11038   /* now that we have the pointer type we assign
11039      the pointer values */
11040   switch (p_type)
11041     {
11042
11043     case POINTER:
11044     case IPOINTER:
11045       genNearPointerSet (right, result, ic, pi);
11046       break;
11047
11048     case PPOINTER:
11049       genPagedPointerSet (right, result, ic, pi);
11050       break;
11051
11052     case FPOINTER:
11053       genFarPointerSet (right, result, ic, pi);
11054       break;
11055
11056     case GPOINTER:
11057       genGenPointerSet (right, result, ic, pi);
11058       break;
11059
11060     default:
11061       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11062               "genPointerSet: illegal pointer type");
11063     }
11064 }
11065
11066 /*-----------------------------------------------------------------*/
11067 /* genIfx - generate code for Ifx statement                        */
11068 /*-----------------------------------------------------------------*/
11069 static void
11070 genIfx (iCode * ic, iCode * popIc)
11071 {
11072   operand *cond = IC_COND (ic);
11073   int isbit = 0;
11074   char *dup = NULL;
11075
11076   D (emitcode (";", "genIfx"));
11077
11078   aopOp (cond, ic, FALSE);
11079
11080   /* get the value into acc */
11081   if (AOP_TYPE (cond) != AOP_CRY)
11082     {
11083       toBoolean (cond);
11084     }
11085   else
11086     {
11087       isbit = 1;
11088       if (AOP(cond)->aopu.aop_dir)
11089         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11090     }
11091
11092   /* the result is now in the accumulator or a directly addressable bit */
11093   freeAsmop (cond, NULL, ic, TRUE);
11094
11095   /* if the condition is a bit variable */
11096   if (isbit && dup)
11097     genIfxJump(ic, dup, NULL, NULL, NULL, popIc);
11098   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11099     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL, popIc);
11100   else if (isbit && !IS_ITEMP (cond))
11101     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL, popIc);
11102   else
11103     genIfxJump (ic, "a", NULL, NULL, NULL, popIc);
11104
11105   ic->generated = 1;
11106 }
11107
11108 /*-----------------------------------------------------------------*/
11109 /* genAddrOf - generates code for address of                       */
11110 /*-----------------------------------------------------------------*/
11111 static void
11112 genAddrOf (iCode * ic)
11113 {
11114   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11115   int size, offset;
11116
11117   D (emitcode (";", "genAddrOf"));
11118
11119   aopOp (IC_RESULT (ic), ic, FALSE);
11120
11121   /* if the operand is on the stack then we
11122      need to get the stack offset of this
11123      variable */
11124   if (sym->onStack)
11125     {
11126       /* if it has an offset then we need to compute it */
11127       if (sym->stack)
11128         {
11129           int stack_offset = ((sym->stack < 0) ?
11130                               ((char) (sym->stack - _G.nRegsSaved)) :
11131                               ((char) sym->stack)) & 0xff;
11132           if ((abs(stack_offset) == 1) &&
11133               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11134               !isOperandVolatile (IC_RESULT (ic), FALSE))
11135             {
11136               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11137               if (stack_offset > 0)
11138                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11139               else
11140                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11141             }
11142           else
11143             {
11144               emitcode ("mov", "a,%s", SYM_BP (sym));
11145               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11146               aopPut (IC_RESULT (ic), "a", 0);
11147             }
11148         }
11149       else
11150         {
11151           /* we can just move _bp */
11152           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11153         }
11154       /* fill the result with zero */
11155       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11156
11157       offset = 1;
11158       while (size--)
11159         {
11160           aopPut (IC_RESULT (ic), zero, offset++);
11161         }
11162       goto release;
11163     }
11164
11165   /* object not on stack then we need the name */
11166   size = getDataSize (IC_RESULT (ic));
11167   offset = 0;
11168
11169   while (size--)
11170     {
11171       char s[SDCC_NAME_MAX];
11172       if (offset)
11173         {
11174           sprintf (s, "#(%s >> %d)",
11175                    sym->rname,
11176                    offset * 8);
11177         }
11178       else
11179         {
11180           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11181         }
11182       aopPut (IC_RESULT (ic), s, offset++);
11183     }
11184   if (opIsGptr (IC_RESULT (ic)))
11185     {
11186       char buffer[10];
11187       SNPRINTF (buffer, sizeof(buffer),
11188                 "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
11189       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
11190     }
11191
11192 release:
11193   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11194
11195 }
11196
11197 /*-----------------------------------------------------------------*/
11198 /* genFarFarAssign - assignment when both are in far space         */
11199 /*-----------------------------------------------------------------*/
11200 static void
11201 genFarFarAssign (operand * result, operand * right, iCode * ic)
11202 {
11203   int size = AOP_SIZE (right);
11204   int offset = 0;
11205   char *l;
11206
11207   D (emitcode (";", "genFarFarAssign"));
11208
11209   /* first push the right side on to the stack */
11210   while (size--)
11211     {
11212       l = aopGet (right, offset++, FALSE, FALSE);
11213       MOVA (l);
11214       emitcode ("push", "acc");
11215     }
11216
11217   freeAsmop (right, NULL, ic, FALSE);
11218   /* now assign DPTR to result */
11219   aopOp (result, ic, FALSE);
11220   size = AOP_SIZE (result);
11221   while (size--)
11222     {
11223       emitcode ("pop", "acc");
11224       aopPut (result, "a", --offset);
11225     }
11226   freeAsmop (result, NULL, ic, FALSE);
11227 }
11228
11229 /*-----------------------------------------------------------------*/
11230 /* genAssign - generate code for assignment                        */
11231 /*-----------------------------------------------------------------*/
11232 static void
11233 genAssign (iCode * ic)
11234 {
11235   operand *result, *right;
11236   int size, offset;
11237   unsigned long lit = 0L;
11238
11239   D (emitcode (";", "genAssign"));
11240
11241   result = IC_RESULT (ic);
11242   right = IC_RIGHT (ic);
11243
11244   /* if they are the same */
11245   if (operandsEqu (result, right) &&
11246       !isOperandVolatile (result, FALSE) &&
11247       !isOperandVolatile (right, FALSE))
11248     return;
11249
11250   aopOp (right, ic, FALSE);
11251
11252   /* special case both in far space */
11253   if (AOP_TYPE (right) == AOP_DPTR &&
11254       IS_TRUE_SYMOP (result) &&
11255       isOperandInFarSpace (result))
11256     {
11257       genFarFarAssign (result, right, ic);
11258       return;
11259     }
11260
11261   aopOp (result, ic, TRUE);
11262
11263   /* if they are the same registers */
11264   if (sameRegs (AOP (right), AOP (result)) &&
11265       !isOperandVolatile (result, FALSE) &&
11266       !isOperandVolatile (right, FALSE))
11267     goto release;
11268
11269   /* if the result is a bit */
11270   if (AOP_TYPE (result) == AOP_CRY)
11271     {
11272       assignBit (result, right);
11273       goto release;
11274     }
11275
11276   /* bit variables done */
11277   /* general case */
11278   size = getDataSize (result);
11279   offset = 0;
11280   if (AOP_TYPE (right) == AOP_LIT)
11281     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11282
11283   if ((size > 1) &&
11284       (AOP_TYPE (result) != AOP_REG) &&
11285       (AOP_TYPE (right) == AOP_LIT) &&
11286       !IS_FLOAT (operandType (right)) &&
11287       (lit < 256L))
11288     {
11289       while ((size) && (lit))
11290         {
11291           aopPut (result,
11292                   aopGet (right, offset, FALSE, FALSE),
11293                   offset);
11294           lit >>= 8;
11295           offset++;
11296           size--;
11297         }
11298       /* And now fill the rest with zeros. */
11299       if (size)
11300         {
11301           emitcode ("clr", "a");
11302         }
11303       while (size--)
11304         {
11305           aopPut (result, "a", offset);
11306           offset++;
11307         }
11308     }
11309   else
11310     {
11311       while (size--)
11312         {
11313           aopPut (result,
11314                   aopGet (right, offset, FALSE, FALSE),
11315                   offset);
11316           offset++;
11317         }
11318     }
11319   adjustArithmeticResult (ic);
11320
11321 release:
11322   freeAsmop (result, NULL, ic, TRUE);
11323   freeAsmop (right, NULL, ic, TRUE);
11324 }
11325
11326 /*-----------------------------------------------------------------*/
11327 /* genJumpTab - generates code for jump table                      */
11328 /*-----------------------------------------------------------------*/
11329 static void
11330 genJumpTab (iCode * ic)
11331 {
11332   symbol *jtab,*jtablo,*jtabhi;
11333   char *l;
11334   unsigned int count;
11335
11336   D (emitcode (";", "genJumpTab"));
11337
11338   count = elementsInSet( IC_JTLABELS (ic) );
11339
11340   if( count <= 16 )
11341     {
11342       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11343          if the switch argument is in a register.
11344          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11345       /* Peephole may not convert ljmp to sjmp or ret
11346          labelIsReturnOnly & labelInRange must check
11347          currPl->ic->op != JUMPTABLE */
11348       aopOp (IC_JTCOND (ic), ic, FALSE);
11349       /* get the condition into accumulator */
11350       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11351       MOVA (l);
11352       /* multiply by three */
11353       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11354         {
11355           emitcode ("mov", "b,#0x03");
11356           emitcode ("mul", "ab");
11357         }
11358       else
11359         {
11360           emitcode ("add", "a,acc");
11361           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11362         }
11363       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11364
11365       jtab = newiTempLabel (NULL);
11366       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11367       emitcode ("jmp", "@a+dptr");
11368       emitLabel (jtab);
11369       /* now generate the jump labels */
11370       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11371            jtab = setNextItem (IC_JTLABELS (ic)))
11372         emitcode ("ljmp", "%05d$", jtab->key + 100);
11373     }
11374   else
11375     {
11376       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11377          if the switch argument is in a register.
11378          For n>6 this algorithm may be more compact */
11379       jtablo = newiTempLabel (NULL);
11380       jtabhi = newiTempLabel (NULL);
11381
11382       /* get the condition into accumulator.
11383          Using b as temporary storage, if register push/pop is needed */
11384       aopOp (IC_JTCOND (ic), ic, FALSE);
11385       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11386       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11387           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11388         {
11389           // (MB) what if B is in use???
11390           wassertl(!BINUSE, "B was in use");
11391           emitcode ("mov", "b,%s", l);
11392           l = "b";
11393         }
11394       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11395       MOVA (l);
11396       if( count <= 112 )
11397         {
11398           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11399           emitcode ("movc", "a,@a+pc");
11400           emitcode ("push", "acc");
11401
11402           MOVA (l);
11403           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11404           emitcode ("movc", "a,@a+pc");
11405           emitcode ("push", "acc");
11406         }
11407       else
11408         {
11409           /* this scales up to n<=255, but needs two more bytes
11410              and changes dptr */
11411           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11412           emitcode ("movc", "a,@a+dptr");
11413           emitcode ("push", "acc");
11414
11415           MOVA (l);
11416           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11417           emitcode ("movc", "a,@a+dptr");
11418           emitcode ("push", "acc");
11419         }
11420
11421       emitcode ("ret", "");
11422
11423       /* now generate jump table, LSB */
11424       emitLabel (jtablo);
11425       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11426            jtab = setNextItem (IC_JTLABELS (ic)))
11427         emitcode (".db", "%05d$", jtab->key + 100);
11428
11429       /* now generate jump table, MSB */
11430       emitLabel (jtabhi);
11431       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11432            jtab = setNextItem (IC_JTLABELS (ic)))
11433          emitcode (".db", "%05d$>>8", jtab->key + 100);
11434     }
11435 }
11436
11437 /*-----------------------------------------------------------------*/
11438 /* genCast - gen code for casting                                  */
11439 /*-----------------------------------------------------------------*/
11440 static void
11441 genCast (iCode * ic)
11442 {
11443   operand *result = IC_RESULT (ic);
11444   sym_link *ctype = operandType (IC_LEFT (ic));
11445   sym_link *rtype = operandType (IC_RIGHT (ic));
11446   operand *right = IC_RIGHT (ic);
11447   int size, offset;
11448
11449   D (emitcode (";", "genCast"));
11450
11451   /* if they are equivalent then do nothing */
11452   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11453     return;
11454
11455   aopOp (right, ic, FALSE);
11456   aopOp (result, ic, FALSE);
11457
11458   /* if the result is a bit (and not a bitfield) */
11459   if (IS_BIT (OP_SYMBOL (result)->type))
11460     {
11461       assignBit (result, right);
11462       goto release;
11463     }
11464
11465   /* if they are the same size : or less */
11466   if (AOP_SIZE (result) <= AOP_SIZE (right))
11467     {
11468
11469       /* if they are in the same place */
11470       if (sameRegs (AOP (right), AOP (result)))
11471         goto release;
11472
11473       /* if they in different places then copy */
11474       size = AOP_SIZE (result);
11475       offset = 0;
11476       while (size--)
11477         {
11478           aopPut (result,
11479                   aopGet (right, offset, FALSE, FALSE),
11480                   offset);
11481           offset++;
11482         }
11483       goto release;
11484     }
11485
11486   /* if the result is of type pointer */
11487   if (IS_PTR (ctype))
11488     {
11489
11490       int p_type;
11491       sym_link *type = operandType (right);
11492       sym_link *etype = getSpec (type);
11493
11494       /* pointer to generic pointer */
11495       if (IS_GENPTR (ctype))
11496         {
11497           if (IS_PTR (type))
11498             {
11499               p_type = DCL_TYPE (type);
11500             }
11501           else
11502             {
11503               if (SPEC_SCLS(etype)==S_REGISTER) {
11504                 // let's assume it is a generic pointer
11505                 p_type=GPOINTER;
11506               } else {
11507                 /* we have to go by the storage class */
11508                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11509               }
11510             }
11511
11512           /* the first two bytes are known */
11513           size = GPTRSIZE - 1;
11514           offset = 0;
11515           while (size--)
11516             {
11517               aopPut (result,
11518                       aopGet (right, offset, FALSE, FALSE),
11519                       offset);
11520               offset++;
11521             }
11522           /* the last byte depending on type */
11523             {
11524                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11525                 char gpValStr[10];
11526
11527                 if (gpVal == -1)
11528                 {
11529                     // pointerTypeToGPByte will have bitched.
11530                     exit(1);
11531                 }
11532
11533                 sprintf(gpValStr, "#0x%02x", gpVal);
11534                 aopPut (result, gpValStr, GPTRSIZE - 1);
11535             }
11536           goto release;
11537         }
11538
11539       /* just copy the pointers */
11540       size = AOP_SIZE (result);
11541       offset = 0;
11542       while (size--)
11543         {
11544           aopPut (result,
11545                   aopGet (right, offset, FALSE, FALSE),
11546                   offset);
11547           offset++;
11548         }
11549       goto release;
11550     }
11551
11552   /* so we now know that the size of destination is greater
11553      than the size of the source */
11554   /* we move to result for the size of source */
11555   size = AOP_SIZE (right);
11556   offset = 0;
11557   while (size--)
11558     {
11559       aopPut (result,
11560               aopGet (right, offset, FALSE, FALSE),
11561               offset);
11562       offset++;
11563     }
11564
11565   /* now depending on the sign of the source && destination */
11566   size = AOP_SIZE (result) - AOP_SIZE (right);
11567   /* if unsigned or not an integral type */
11568   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11569     {
11570       while (size--)
11571         aopPut (result, zero, offset++);
11572     }
11573   else
11574     {
11575       /* we need to extend the sign :{ */
11576       char *l = aopGet (right, AOP_SIZE (right) - 1,
11577                         FALSE, FALSE);
11578       MOVA (l);
11579       emitcode ("rlc", "a");
11580       emitcode ("subb", "a,acc");
11581       while (size--)
11582         aopPut (result, "a", offset++);
11583     }
11584
11585   /* we are done hurray !!!! */
11586
11587 release:
11588   freeAsmop (result, NULL, ic, TRUE);
11589   freeAsmop (right, NULL, ic, TRUE);
11590 }
11591
11592 /*-----------------------------------------------------------------*/
11593 /* genDjnz - generate decrement & jump if not zero instrucion      */
11594 /*-----------------------------------------------------------------*/
11595 static int
11596 genDjnz (iCode * ic, iCode * ifx)
11597 {
11598   symbol *lbl, *lbl1;
11599   if (!ifx)
11600     return 0;
11601
11602   /* if the if condition has a false label
11603      then we cannot save */
11604   if (IC_FALSE (ifx))
11605     return 0;
11606
11607   /* if the minus is not of the form a = a - 1 */
11608   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11609       !IS_OP_LITERAL (IC_RIGHT (ic)))
11610     return 0;
11611
11612   if (operandLitValue (IC_RIGHT (ic)) != 1)
11613     return 0;
11614
11615   /* if the size of this greater than one then no
11616      saving */
11617   if (getSize (operandType (IC_RESULT (ic))) > 1)
11618     return 0;
11619
11620   /* otherwise we can save BIG */
11621
11622   D (emitcode (";", "genDjnz"));
11623
11624   lbl = newiTempLabel (NULL);
11625   lbl1 = newiTempLabel (NULL);
11626
11627   aopOp (IC_RESULT (ic), ic, FALSE);
11628
11629   if (AOP_NEEDSACC(IC_RESULT(ic)))
11630   {
11631       /* If the result is accessed indirectly via
11632        * the accumulator, we must explicitly write
11633        * it back after the decrement.
11634        */
11635       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11636
11637       if (strcmp(rByte, "a"))
11638       {
11639            /* Something is hopelessly wrong */
11640            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11641                    __FILE__, __LINE__);
11642            /* We can just give up; the generated code will be inefficient,
11643             * but what the hey.
11644             */
11645            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11646            return 0;
11647       }
11648       emitcode ("dec", "%s", rByte);
11649       aopPut (IC_RESULT (ic), rByte, 0);
11650       emitcode ("jnz", "%05d$", lbl->key + 100);
11651   }
11652   else if (IS_AOP_PREG (IC_RESULT (ic)))
11653     {
11654       emitcode ("dec", "%s",
11655                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11656       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11657       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11658       ifx->generated = 1;
11659       emitcode ("jnz", "%05d$", lbl->key + 100);
11660     }
11661   else
11662     {
11663       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11664                 lbl->key + 100);
11665     }
11666   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11667   emitLabel (lbl);
11668   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11669   emitLabel (lbl1);
11670
11671   if (!ifx->generated)
11672       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11673   ifx->generated = 1;
11674   return 1;
11675 }
11676
11677 /*-----------------------------------------------------------------*/
11678 /* genReceive - generate code for a receive iCode                  */
11679 /*-----------------------------------------------------------------*/
11680 static void
11681 genReceive (iCode * ic)
11682 {
11683   int size = getSize (operandType (IC_RESULT (ic)));
11684   int offset = 0;
11685
11686   D (emitcode (";", "genReceive"));
11687
11688   if (ic->argreg == 1)
11689     { /* first parameter */
11690       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11691            isOperandInPagedSpace (IC_RESULT (ic))) &&
11692           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11693            IS_TRUE_SYMOP (IC_RESULT (ic))))
11694         {
11695           regs *tempRegs[4];
11696           int receivingA = 0;
11697           int roffset = 0;
11698
11699           for (offset = 0; offset<size; offset++)
11700             if (!strcmp (fReturn[offset], "a"))
11701               receivingA = 1;
11702
11703           if (!receivingA)
11704             {
11705               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11706                 {
11707                   for (offset = size-1; offset>0; offset--)
11708                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11709                   emitcode("mov","a,%s", fReturn[0]);
11710                   _G.accInUse++;
11711                   aopOp (IC_RESULT (ic), ic, FALSE);
11712                   _G.accInUse--;
11713                   aopPut (IC_RESULT (ic), "a", offset);
11714                   for (offset = 1; offset<size; offset++)
11715                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11716                   goto release;
11717                 }
11718             }
11719           else
11720             {
11721               if (getTempRegs(tempRegs, size, ic))
11722                 {
11723                   for (offset = 0; offset<size; offset++)
11724                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11725                   aopOp (IC_RESULT (ic), ic, FALSE);
11726                   for (offset = 0; offset<size; offset++)
11727                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11728                   goto release;
11729                 }
11730             }
11731
11732           offset = fReturnSizeMCS51 - size;
11733           while (size--)
11734             {
11735               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11736                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11737               offset++;
11738             }
11739           aopOp (IC_RESULT (ic), ic, FALSE);
11740           size = AOP_SIZE (IC_RESULT (ic));
11741           offset = 0;
11742           while (size--)
11743             {
11744               emitcode ("pop", "acc");
11745               aopPut (IC_RESULT (ic), "a", offset++);
11746             }
11747         }
11748       else
11749         {
11750           _G.accInUse++;
11751           aopOp (IC_RESULT (ic), ic, FALSE);
11752           _G.accInUse--;
11753           assignResultValue (IC_RESULT (ic), NULL);
11754         }
11755     }
11756   else if (ic->argreg > 12)
11757     { /* bit parameters */
11758       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11759
11760       BitBankUsed = 1;
11761       if (!reg || reg->rIdx != ic->argreg-5)
11762         {
11763           aopOp (IC_RESULT (ic), ic, FALSE);
11764           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11765           outBitC(IC_RESULT (ic));
11766         }
11767     }
11768   else
11769     { /* other parameters */
11770       int rb1off ;
11771       aopOp (IC_RESULT (ic), ic, FALSE);
11772       rb1off = ic->argreg;
11773       while (size--)
11774         {
11775           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11776         }
11777     }
11778
11779 release:
11780   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11781 }
11782
11783 /*-----------------------------------------------------------------*/
11784 /* genDummyRead - generate code for dummy read of volatiles        */
11785 /*-----------------------------------------------------------------*/
11786 static void
11787 genDummyRead (iCode * ic)
11788 {
11789   operand *op;
11790   int size, offset;
11791
11792   D (emitcode(";", "genDummyRead"));
11793
11794   op = IC_RIGHT (ic);
11795   if (op && IS_SYMOP (op))
11796     {
11797       aopOp (op, ic, FALSE);
11798
11799       /* if the result is a bit */
11800       if (AOP_TYPE (op) == AOP_CRY)
11801         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11802       else
11803         {
11804           /* bit variables done */
11805           /* general case */
11806           size = AOP_SIZE (op);
11807           offset = 0;
11808           while (size--)
11809           {
11810             MOVA (aopGet (op, offset, FALSE, FALSE));
11811             offset++;
11812           }
11813         }
11814
11815       freeAsmop (op, NULL, ic, TRUE);
11816     }
11817
11818   op = IC_LEFT (ic);
11819   if (op && IS_SYMOP (op))
11820     {
11821       aopOp (op, ic, FALSE);
11822
11823       /* if the result is a bit */
11824       if (AOP_TYPE (op) == AOP_CRY)
11825         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11826       else
11827         {
11828           /* bit variables done */
11829           /* general case */
11830           size = AOP_SIZE (op);
11831           offset = 0;
11832           while (size--)
11833           {
11834             MOVA (aopGet (op, offset, FALSE, FALSE));
11835             offset++;
11836           }
11837         }
11838
11839       freeAsmop (op, NULL, ic, TRUE);
11840     }
11841 }
11842
11843 /*-----------------------------------------------------------------*/
11844 /* genCritical - generate code for start of a critical sequence    */
11845 /*-----------------------------------------------------------------*/
11846 static void
11847 genCritical (iCode *ic)
11848 {
11849   symbol *tlbl = newiTempLabel (NULL);
11850
11851   D (emitcode(";", "genCritical"));
11852
11853   if (IC_RESULT (ic))
11854     {
11855       aopOp (IC_RESULT (ic), ic, TRUE);
11856       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11857       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11858       aopPut (IC_RESULT (ic), zero, 0);
11859       emitLabel (tlbl);
11860       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11861     }
11862   else
11863     {
11864       emitcode ("setb", "c");
11865       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11866       emitcode ("clr", "c");
11867       emitLabel (tlbl);
11868       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11869     }
11870 }
11871
11872 /*-----------------------------------------------------------------*/
11873 /* genEndCritical - generate code for end of a critical sequence   */
11874 /*-----------------------------------------------------------------*/
11875 static void
11876 genEndCritical (iCode *ic)
11877 {
11878   D(emitcode(";", "genEndCritical"));
11879
11880   if (IC_RIGHT (ic))
11881     {
11882       aopOp (IC_RIGHT (ic), ic, FALSE);
11883       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11884         {
11885           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11886           emitcode ("mov", "ea,c");
11887         }
11888       else
11889         {
11890           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11891             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11892           emitcode ("rrc", "a");
11893           emitcode ("mov", "ea,c");
11894         }
11895       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11896     }
11897   else
11898     {
11899       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11900       emitcode ("mov", "ea,c");
11901     }
11902 }
11903
11904 /*-----------------------------------------------------------------*/
11905 /* gen51Code - generate code for 8051 based controllers            */
11906 /*-----------------------------------------------------------------*/
11907 void
11908 gen51Code (iCode * lic)
11909 {
11910   iCode *ic;
11911   int cln = 0;
11912   /* int cseq = 0; */
11913
11914   _G.currentFunc = NULL;
11915   lineHead = lineCurr = NULL;
11916
11917   /* print the allocation information */
11918   if (allocInfo && currFunc)
11919     printAllocInfo (currFunc, codeOutBuf);
11920   /* if debug information required */
11921   if (options.debug && currFunc)
11922     {
11923       debugFile->writeFunction (currFunc, lic);
11924     }
11925   /* stack pointer name */
11926   if (options.useXstack)
11927     spname = "_spx";
11928   else
11929     spname = "sp";
11930
11931
11932   for (ic = lic; ic; ic = ic->next)
11933     {
11934       _G.current_iCode = ic;
11935
11936       if (ic->lineno && cln != ic->lineno)
11937         {
11938           if (options.debug)
11939             {
11940               debugFile->writeCLine (ic);
11941             }
11942           if (!options.noCcodeInAsm) {
11943             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11944                       printCLine(ic->filename, ic->lineno));
11945           }
11946           cln = ic->lineno;
11947         }
11948       #if 0
11949       if (ic->seqPoint && ic->seqPoint != cseq)
11950         {
11951           emitcode (";", "sequence point %d", ic->seqPoint);
11952           cseq = ic->seqPoint;
11953         }
11954       #endif
11955       if (options.iCodeInAsm) {
11956         char regsInUse[80];
11957         int i;
11958         const char *iLine;
11959
11960         #if 0
11961         for (i=0; i<8; i++) {
11962           sprintf (&regsInUse[i],
11963                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11964         regsInUse[i]=0;
11965         #else
11966         strcpy (regsInUse, "--------");
11967         for (i=0; i < 8; i++) {
11968           if (bitVectBitValue (ic->rMask, i))
11969             {
11970               int offset = regs8051[i].offset;
11971               regsInUse[offset] = offset + '0'; /* show rMask */
11972             }
11973         #endif
11974         }
11975         iLine = printILine(ic);
11976         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11977         dbuf_free(iLine);
11978       }
11979       /* if the result is marked as
11980          spilt and rematerializable or code for
11981          this has already been generated then
11982          do nothing */
11983       if (resultRemat (ic) || ic->generated)
11984         continue;
11985
11986       /* depending on the operation */
11987       switch (ic->op)
11988         {
11989         case '!':
11990           genNot (ic);
11991           break;
11992
11993         case '~':
11994           genCpl (ic);
11995           break;
11996
11997         case UNARYMINUS:
11998           genUminus (ic);
11999           break;
12000
12001         case IPUSH:
12002           genIpush (ic);
12003           break;
12004
12005         case IPOP:
12006           {
12007             iCode *ifxIc, *popIc;
12008             bool CommonRegs = FALSE;
12009
12010             /* IPOP happens only when trying to restore a
12011                spilt live range, if there is an ifx statement
12012                following this pop (or several) then the if statement might
12013                be using some of the registers being popped which
12014                would destory the contents of the register so
12015                we need to check for this condition and handle it */
12016             for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next);
12017             for (popIc = ic; popIc && popIc->op == IPOP; popIc = popIc->next)
12018               CommonRegs |= (ifxIc && ifxIc->op == IFX && !ifxIc->generated &&
12019                              regsInCommon (IC_LEFT (popIc), IC_COND (ifxIc)));
12020             if (CommonRegs)
12021               genIfx (ifxIc, ic);
12022             else
12023               genIpop (ic);
12024           }
12025           break;
12026
12027         case CALL:
12028           genCall (ic);
12029           break;
12030
12031         case PCALL:
12032           genPcall (ic);
12033           break;
12034
12035         case FUNCTION:
12036           genFunction (ic);
12037           break;
12038
12039         case ENDFUNCTION:
12040           genEndFunction (ic);
12041           break;
12042
12043         case RETURN:
12044           genRet (ic);
12045           break;
12046
12047         case LABEL:
12048           genLabel (ic);
12049           break;
12050
12051         case GOTO:
12052           genGoto (ic);
12053           break;
12054
12055         case '+':
12056           genPlus (ic);
12057           break;
12058
12059         case '-':
12060           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
12061             genMinus (ic);
12062           break;
12063
12064         case '*':
12065           genMult (ic);
12066           break;
12067
12068         case '/':
12069           genDiv (ic);
12070           break;
12071
12072         case '%':
12073           genMod (ic);
12074           break;
12075
12076         case '>':
12077           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
12078           break;
12079
12080         case '<':
12081           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
12082           break;
12083
12084         case LE_OP:
12085         case GE_OP:
12086         case NE_OP:
12087
12088           /* note these two are xlated by algebraic equivalence
12089              in decorateType() in SDCCast.c */
12090           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12091                   "got '>=' or '<=' shouldn't have come here");
12092           break;
12093
12094         case EQ_OP:
12095           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
12096           break;
12097
12098         case AND_OP:
12099           genAndOp (ic);
12100           break;
12101
12102         case OR_OP:
12103           genOrOp (ic);
12104           break;
12105
12106         case '^':
12107           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
12108           break;
12109
12110         case '|':
12111           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
12112           break;
12113
12114         case BITWISEAND:
12115           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
12116           break;
12117
12118         case INLINEASM:
12119           genInline (ic);
12120           break;
12121
12122         case RRC:
12123           genRRC (ic);
12124           break;
12125
12126         case RLC:
12127           genRLC (ic);
12128           break;
12129
12130         case GETHBIT:
12131           genGetHbit (ic);
12132           break;
12133
12134         case GETABIT:
12135           genGetAbit (ic);
12136           break;
12137
12138         case GETBYTE:
12139           genGetByte (ic);
12140           break;
12141
12142         case GETWORD:
12143           genGetWord (ic);
12144           break;
12145
12146         case LEFT_OP:
12147           genLeftShift (ic);
12148           break;
12149
12150         case RIGHT_OP:
12151           genRightShift (ic);
12152           break;
12153
12154         case GET_VALUE_AT_ADDRESS:
12155           genPointerGet (ic,
12156                          hasInc (IC_LEFT (ic), ic,
12157                                  getSize (operandType (IC_RESULT (ic)))),
12158                          ifxForOp (IC_RESULT (ic), ic) );
12159           break;
12160
12161         case '=':
12162           if (POINTER_SET (ic))
12163             genPointerSet (ic,
12164                            hasInc (IC_RESULT (ic), ic,
12165                                    getSize (operandType (IC_RIGHT (ic)))));
12166           else
12167             genAssign (ic);
12168           break;
12169
12170         case IFX:
12171           genIfx (ic, NULL);
12172           break;
12173
12174         case ADDRESS_OF:
12175           genAddrOf (ic);
12176           break;
12177
12178         case JUMPTABLE:
12179           genJumpTab (ic);
12180           break;
12181
12182         case CAST:
12183           genCast (ic);
12184           break;
12185
12186         case RECEIVE:
12187           genReceive (ic);
12188           break;
12189
12190         case SEND:
12191           addSet (&_G.sendSet, ic);
12192           break;
12193
12194         case DUMMY_READ_VOLATILE:
12195           genDummyRead (ic);
12196           break;
12197
12198         case CRITICAL:
12199           genCritical (ic);
12200           break;
12201
12202         case ENDCRITICAL:
12203           genEndCritical (ic);
12204           break;
12205
12206         case SWAP:
12207           genSwap (ic);
12208           break;
12209
12210         default:
12211           ic = ic;
12212         }
12213     }
12214
12215   _G.current_iCode = NULL;
12216
12217   /* now we are ready to call the
12218      peep hole optimizer */
12219   if (!options.nopeep)
12220     peepHole (&lineHead);
12221
12222   /* now do the actual printing */
12223   printLine (lineHead, codeOutBuf);
12224   return;
12225 }