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