a5da703fa0e3dec3487f80268bae174fecb9e9e5
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 #define D(x) do if (options.verboseAsm) {x;} while(0)
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include "SDCCglobl.h"
38 #include "newalloc.h"
39
40 #include "common.h"
41 #include "SDCCpeeph.h"
42 #include "ralloc.h"
43 #include "rtrack.h"
44 #include "gen.h"
45 #include "dbuf_string.h"
46
47 char *aopLiteral (value * val, int offset);
48 char *aopLiteralLong (value * val, int offset, int size);
49 extern int allocInfo;
50
51 /* this is the down and dirty file with all kinds of
52    kludgy & hacky stuff. This is what it is all about
53    CODE GENERATION for a specific MCU . some of the
54    routines may be reusable, will have to see */
55
56 static char *zero = "#0x00";
57 static char *one = "#0x01";
58 static char *spname;
59
60 char *fReturn8051[] =
61 {"dpl", "dph", "b", "a"};
62 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
63 char **fReturn = fReturn8051;
64 static char *accUse[] =
65 {"a", "b"};
66
67 static unsigned short rbank = -1;
68
69 #define REG_WITH_INDEX   mcs51_regWithIdx
70
71 #define AOP(op) op->aop
72 #define AOP_TYPE(op) AOP(op)->type
73 #define AOP_SIZE(op) AOP(op)->size
74 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
75                         AOP_TYPE(x) == AOP_R0))
76
77 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
78                          AOP_TYPE(x) == AOP_DPTR || \
79                          AOP(x)->paged))
80
81 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
82                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
83                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
84
85 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
86
87 #define R0INB   _G.bu.bs.r0InB
88 #define R1INB   _G.bu.bs.r1InB
89 #define OPINB   _G.bu.bs.OpInB
90 #define BINUSE  _G.bu.BInUse
91
92 static struct
93   {
94     short r0Pushed;
95     short r1Pushed;
96     union
97       {
98         struct
99           {
100             short r0InB : 2;//2 so we can see it overflow
101             short r1InB : 2;//2 so we can see it overflow
102             short OpInB : 2;//2 so we can see it overflow
103           } bs;
104         short BInUse;
105       } bu;
106     short accInUse;
107     short inLine;
108     short debugLine;
109     short nRegsSaved;
110     set *sendSet;
111     iCode *current_iCode;
112     symbol *currentFunc;
113   }
114 _G;
115
116 static char *rb1regs[] = {
117     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
118     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
119 };
120
121 extern struct dbuf_s *codeOutBuf;
122
123 #define RESULTONSTACK(x) \
124                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
125                          IC_RESULT(x)->aop->type == AOP_STK )
126
127 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
128 #define MOVB(x)  movb(x)
129
130 #define CLRC     emitcode("clr","c")
131 #define SETC     emitcode("setb","c")
132
133 static lineNode *lineHead = NULL;
134 static lineNode *lineCurr = NULL;
135
136 static unsigned char SLMask[] =
137 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
138  0xE0, 0xC0, 0x80, 0x00};
139 static unsigned char SRMask[] =
140 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
141  0x07, 0x03, 0x01, 0x00};
142
143 #define LSB     0
144 #define MSB16   1
145 #define MSB24   2
146 #define MSB32   3
147
148 /*-----------------------------------------------------------------*/
149 /* emitcode - writes the code into a file : for now it is simple    */
150 /*-----------------------------------------------------------------*/
151 void
152 emitcode (const char *inst, const char *fmt,...)
153 {
154   va_list ap;
155   struct dbuf_s dbuf;
156   const char *lbp, *lb;
157
158   dbuf_init (&dbuf, INITIAL_INLINEASM);
159
160   va_start (ap, fmt);
161
162   if (inst && *inst)
163     {
164       dbuf_append_str (&dbuf, inst);
165
166       if (fmt && *fmt)
167         {
168           dbuf_append_char (&dbuf, '\t');
169           dbuf_tvprintf (&dbuf, fmt, ap);
170         }
171     }
172   else
173     {
174       dbuf_tvprintf (&dbuf, fmt, ap);
175     }
176
177   lbp = lb = dbuf_c_str(&dbuf);
178
179   while (isspace ((unsigned char)*lbp))
180     {
181       lbp++;
182     }
183
184   if (lbp)
185     {
186       rtrackUpdate (lbp);
187
188       lineCurr = (lineCurr ?
189                   connectLine (lineCurr, newLineNode (lb)) :
190                   (lineHead = newLineNode (lb)));
191
192       lineCurr->isInline = _G.inLine;
193       lineCurr->isDebug = _G.debugLine;
194       lineCurr->ic = _G.current_iCode;
195       lineCurr->isComment = (*lbp==';');
196     }
197
198   va_end (ap);
199
200   dbuf_destroy(&dbuf);
201 }
202
203 static void
204 emitLabel (symbol *tlbl)
205 {
206   emitcode ("", "%05d$:", tlbl->key + 100);
207   lineCurr->isLabel = 1;
208 }
209
210 /*-----------------------------------------------------------------*/
211 /* mcs51_emitDebuggerSymbol - associate the current code location  */
212 /*   with a debugger symbol                                        */
213 /*-----------------------------------------------------------------*/
214 void
215 mcs51_emitDebuggerSymbol (char * debugSym)
216 {
217   _G.debugLine = 1;
218   emitcode ("", "%s ==.", debugSym);
219   _G.debugLine = 0;
220 }
221
222 /*-----------------------------------------------------------------*/
223 /* mova - moves specified value into accumulator                   */
224 /*-----------------------------------------------------------------*/
225 static void
226 mova (const char *x)
227 {
228   /* do some early peephole optimization */
229   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
230     return;
231
232   /* if it is a literal mov try to get it cheaper */
233   if (*x == '#' &&
234       rtrackMoveALit(x))
235     return;
236
237   emitcode("mov", "a,%s", x);
238 }
239
240 /*-----------------------------------------------------------------*/
241 /* movb - moves specified value into register b                    */
242 /*-----------------------------------------------------------------*/
243 static void
244 movb (const char *x)
245 {
246   /* do some early peephole optimization */
247   if (!strncmp(x, "b", 2))
248     return;
249
250   /* if it is a literal mov try to get it cheaper */
251   if (*x == '#')
252     {
253       emitcode("mov","b,%s", rtrackGetLit(x));
254       return;
255     }
256
257   emitcode("mov","b,%s", x);
258 }
259
260 /*-----------------------------------------------------------------*/
261 /* pushB - saves register B if necessary                           */
262 /*-----------------------------------------------------------------*/
263 static bool
264 pushB (void)
265 {
266   bool pushedB = FALSE;
267
268   if (BINUSE)
269     {
270       emitcode ("push", "b");
271 //    printf("B was in use !\n");
272       pushedB = TRUE;
273     }
274   else
275     {
276       OPINB++;
277     }
278   return pushedB;
279 }
280
281 /*-----------------------------------------------------------------*/
282 /* popB - restores value of register B if necessary                */
283 /*-----------------------------------------------------------------*/
284 static void
285 popB (bool pushedB)
286 {
287   if (pushedB)
288     {
289       emitcode ("pop", "b");
290     }
291   else
292     {
293       OPINB--;
294     }
295 }
296
297 /*-----------------------------------------------------------------*/
298 /* pushReg - saves register                                        */
299 /*-----------------------------------------------------------------*/
300 static bool
301 pushReg (int index, bool bits_pushed)
302 {
303   regs * reg = REG_WITH_INDEX (index);
304   if (reg->type == REG_BIT)
305     {
306       if (!bits_pushed)
307         emitcode ("push", "%s", reg->base);
308       return TRUE;
309     }
310   else
311     emitcode ("push", "%s", reg->dname);
312   return bits_pushed;
313 }
314
315 /*-----------------------------------------------------------------*/
316 /* popReg - restores register                                      */
317 /*-----------------------------------------------------------------*/
318 static bool
319 popReg (int index, bool bits_popped)
320 {
321   regs * reg = REG_WITH_INDEX (index);
322   if (reg->type == REG_BIT)
323     {
324       if (!bits_popped)
325         emitcode ("pop", "%s", reg->base);
326       return TRUE;
327     }
328   else
329     emitcode ("pop", "%s", reg->dname);
330   return bits_popped;
331 }
332
333 /*-----------------------------------------------------------------*/
334 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
335 /*-----------------------------------------------------------------*/
336 static regs *
337 getFreePtr (iCode * ic, asmop ** aopp, bool result)
338 {
339   bool r0iu, r1iu;
340   bool r0ou, r1ou;
341
342   /* the logic: if r0 & r1 used in the instruction
343      then we are in trouble otherwise */
344
345   /* first check if r0 & r1 are used by this
346      instruction, in which case we are in trouble */
347   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
348   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
349   if (r0iu && r1iu) {
350       goto endOfWorld;
351     }
352
353   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
354   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
355
356   /* if no usage of r0 then return it */
357   if (!r0iu && !r0ou)
358     {
359       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
360       (*aopp)->type = AOP_R0;
361
362       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
363     }
364
365   /* if no usage of r1 then return it */
366   if (!r1iu && !r1ou)
367     {
368       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
369       (*aopp)->type = AOP_R1;
370
371       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
372     }
373
374   /* now we know they both have usage */
375   /* if r0 not used in this instruction */
376   if (!r0iu)
377     {
378       /* push it if not already pushed */
379       if (ic->op == IPUSH)
380         {
381           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
382           R0INB++;
383         }
384       else if (!_G.r0Pushed)
385         {
386           emitcode ("push", "%s",
387                     REG_WITH_INDEX (R0_IDX)->dname);
388           _G.r0Pushed++;
389         }
390
391       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
392       (*aopp)->type = AOP_R0;
393
394       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
395     }
396
397   /* if r1 not used then */
398
399   if (!r1iu)
400     {
401       /* push it if not already pushed */
402       if (ic->op == IPUSH)
403         {
404           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
405           R1INB++;
406         }
407       else if (!_G.r1Pushed)
408         {
409           emitcode ("push", "%s",
410                     REG_WITH_INDEX (R1_IDX)->dname);
411           _G.r1Pushed++;
412         }
413
414       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
415       (*aopp)->type = AOP_R1;
416       return REG_WITH_INDEX (R1_IDX);
417     }
418
419 endOfWorld:
420   /* I said end of world, but not quite end of world yet */
421   /* if this is a result then we can push it on the stack */
422   if (result)
423     {
424       (*aopp)->type = AOP_STK;
425       return NULL;
426     }
427   /* in the case that result AND left AND right needs a pointer reg
428      we can safely use the result's */
429   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
430     {
431       (*aopp)->type = AOP_R0;
432       return REG_WITH_INDEX (R0_IDX);
433     }
434   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
435     {
436       (*aopp)->type = AOP_R1;
437       return REG_WITH_INDEX (R1_IDX);
438     }
439
440   /* now this is REALLY the end of the world */
441   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
442           "getFreePtr should never reach here");
443   exit (1);
444 }
445
446
447 /*-----------------------------------------------------------------*/
448 /* getTempRegs - initialize an array of pointers to GPR registers */
449 /*               that are not in use. Returns 1 if the requested   */
450 /*               number of registers were available, 0 otherwise.  */
451 /*-----------------------------------------------------------------*/
452 int
453 getTempRegs(regs **tempRegs, int size, iCode *ic)
454 {
455   bitVect * freeRegs;
456   int i;
457   int offset;
458
459   if (!ic)
460     ic = _G.current_iCode;
461   if (!ic)
462     return 0;
463   if (!_G.currentFunc)
464     return 0;
465
466   freeRegs = newBitVect(8);
467   bitVectSetBit (freeRegs, R2_IDX);
468   bitVectSetBit (freeRegs, R3_IDX);
469   bitVectSetBit (freeRegs, R4_IDX);
470   bitVectSetBit (freeRegs, R5_IDX);
471   bitVectSetBit (freeRegs, R6_IDX);
472   bitVectSetBit (freeRegs, R7_IDX);
473
474   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
475     {
476       bitVect * newfreeRegs;
477       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
478       freeBitVect(freeRegs);
479       freeRegs = newfreeRegs;
480     }
481   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
482
483   offset = 0;
484   for (i=0; i<freeRegs->size; i++)
485     {
486       if (bitVectBitValue(freeRegs,i))
487         tempRegs[offset++] = REG_WITH_INDEX(i);
488       if (offset>=size)
489         {
490           freeBitVect(freeRegs);
491           return 1;
492         }
493     }
494
495   freeBitVect(freeRegs);
496   return 0;
497 }
498
499
500 /*-----------------------------------------------------------------*/
501 /* newAsmop - creates a new asmOp                                  */
502 /*-----------------------------------------------------------------*/
503 static asmop *
504 newAsmop (short type)
505 {
506   asmop *aop;
507
508   aop = Safe_calloc (1, sizeof (asmop));
509   aop->type = type;
510   aop->allocated = 1;
511   return aop;
512 }
513
514 /*-----------------------------------------------------------------*/
515 /* pointerCode - returns the code for a pointer type               */
516 /*-----------------------------------------------------------------*/
517 static int
518 pointerCode (sym_link * etype)
519 {
520
521   return PTR_TYPE (SPEC_OCLS (etype));
522
523 }
524
525 /*-----------------------------------------------------------------*/
526 /* leftRightUseAcc - returns size of accumulator use by operands   */
527 /*-----------------------------------------------------------------*/
528 static int
529 leftRightUseAcc(iCode *ic)
530 {
531   operand *op;
532   int size;
533   int accuseSize = 0;
534   int accuse = 0;
535
536   if (!ic)
537     {
538       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
539               "null iCode pointer");
540       return 0;
541     }
542
543   if (ic->op == IFX)
544     {
545       op = IC_COND (ic);
546       if (IS_OP_ACCUSE (op))
547         {
548           accuse = 1;
549           size = getSize (OP_SYMBOL (op)->type);
550           if (size>accuseSize)
551             accuseSize = size;
552         }
553     }
554   else if (ic->op == JUMPTABLE)
555     {
556       op = IC_JTCOND (ic);
557       if (IS_OP_ACCUSE (op))
558         {
559           accuse = 1;
560           size = getSize (OP_SYMBOL (op)->type);
561           if (size>accuseSize)
562             accuseSize = size;
563         }
564     }
565   else
566     {
567       op = IC_LEFT (ic);
568       if (IS_OP_ACCUSE (op))
569         {
570           accuse = 1;
571           size = getSize (OP_SYMBOL (op)->type);
572           if (size>accuseSize)
573             accuseSize = size;
574         }
575       op = IC_RIGHT (ic);
576       if (IS_OP_ACCUSE (op))
577         {
578           accuse = 1;
579           size = getSize (OP_SYMBOL (op)->type);
580           if (size>accuseSize)
581             accuseSize = size;
582         }
583     }
584
585   if (accuseSize)
586     return accuseSize;
587   else
588     return accuse;
589 }
590
591 /*-----------------------------------------------------------------*/
592 /* aopForSym - for a true symbol                                   */
593 /*-----------------------------------------------------------------*/
594 static asmop *
595 aopForSym (iCode * ic, symbol * sym, bool result)
596 {
597   asmop *aop;
598   memmap *space;
599   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
600
601   wassertl (ic != NULL, "Got a null iCode");
602   wassertl (sym != NULL, "Got a null symbol");
603
604   space = SPEC_OCLS (sym->etype);
605
606   /* if already has one */
607   if (sym->aop)
608     {
609       sym->aop->allocated++;
610       return sym->aop;
611     }
612
613   /* assign depending on the storage class */
614   /* if it is on the stack or indirectly addressable */
615   /* space we need to assign either r0 or r1 to it   */
616   if (sym->onStack || sym->iaccess)
617     {
618       sym->aop = aop = newAsmop (0);
619       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
620       aop->size = getSize (sym->type);
621
622       /* now assign the address of the variable to
623          the pointer register */
624       if (aop->type != AOP_STK)
625         {
626           if (sym->onStack)
627             {
628               signed char offset = ((sym->stack < 0) ?
629                          ((signed char) (sym->stack - _G.nRegsSaved)) :
630                          ((signed char) sym->stack)) & 0xff;
631
632               if ((abs(offset) <= 3) ||
633                   (accuse && (abs(offset) <= 7)))
634                 {
635                   emitcode ("mov", "%s,%s",
636                             aop->aopu.aop_ptr->name, SYM_BP (sym));
637                   while (offset < 0)
638                     {
639                       emitcode ("dec", aop->aopu.aop_ptr->name);
640                       offset++;
641                     }
642                   while (offset > 0)
643                     {
644                       emitcode ("inc", aop->aopu.aop_ptr->name);
645                       offset--;
646                     }
647                 }
648               else
649                 {
650                   if (accuse)
651                     emitcode ("push", "acc");
652                   emitcode ("mov", "a,%s", SYM_BP (sym));
653                   emitcode ("add", "a,#0x%02x", offset & 0xff);
654                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
655                   if (accuse)
656                     emitcode ("pop", "acc");
657                 }
658             }
659           else
660             {
661               emitcode ("mov", "%s,#%s",
662                         aop->aopu.aop_ptr->name,
663                         sym->rname);
664             }
665           aop->paged = space->paged;
666         }
667       else
668         aop->aopu.aop_stk = sym->stack;
669       return aop;
670     }
671
672   /* if in bit space */
673   if (IN_BITSPACE (space))
674     {
675       sym->aop = aop = newAsmop (AOP_CRY);
676       aop->aopu.aop_dir = sym->rname;
677       aop->size = getSize (sym->type);
678       return aop;
679     }
680   /* if it is in direct space */
681   if (IN_DIRSPACE (space))
682     {
683       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
684       //printTypeChainRaw(sym->type, NULL);
685       //printf("space = %s\n", space ? space->sname : "NULL");
686       sym->aop = aop = newAsmop (AOP_DIR);
687       aop->aopu.aop_dir = sym->rname;
688       aop->size = getSize (sym->type);
689       return aop;
690     }
691
692   /* special case for a function */
693   if (IS_FUNC (sym->type))
694     {
695       sym->aop = aop = newAsmop (AOP_IMMD);
696       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
697       aop->size = getSize (sym->type);
698       return aop;
699     }
700
701   /* only remaining is far space */
702   /* in which case DPTR gets the address */
703   sym->aop = aop = newAsmop (AOP_DPTR);
704   emitcode ("mov", "dptr,#%s", sym->rname);
705   aop->size = getSize (sym->type);
706
707   /* if it is in code space */
708   if (IN_CODESPACE (space))
709     aop->code = 1;
710
711   return aop;
712 }
713
714 /*-----------------------------------------------------------------*/
715 /* aopForRemat - rematerializes an object                          */
716 /*-----------------------------------------------------------------*/
717 static asmop *
718 aopForRemat (symbol * sym)
719 {
720   iCode *ic = sym->rematiCode;
721   asmop *aop = newAsmop (AOP_IMMD);
722   int ptr_type = 0;
723   int val = 0;
724
725   for (;;)
726     {
727       if (ic->op == '+')
728         val += (int) operandLitValue (IC_RIGHT (ic));
729       else if (ic->op == '-')
730         val -= (int) operandLitValue (IC_RIGHT (ic));
731       else if (IS_CAST_ICODE(ic))
732         {
733           sym_link *from_type = operandType(IC_RIGHT(ic));
734           aop->aopu.aop_immd.from_cast_remat = 1;
735           ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
736           ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
737           continue;
738         }
739       else break;
740
741       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
742     }
743
744   if (val)
745     {
746       SNPRINTF (buffer, sizeof(buffer),
747                 "(%s %c 0x%04x)",
748                 OP_SYMBOL (IC_LEFT (ic))->rname,
749                 val >= 0 ? '+' : '-',
750                 abs (val) & 0xffff);
751     }
752   else
753     {
754       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
755     }
756
757   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
758   /* set immd2 field if required */
759   if (aop->aopu.aop_immd.from_cast_remat)
760     {
761       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
762       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
763     }
764
765   return aop;
766 }
767
768 /*-----------------------------------------------------------------*/
769 /* regsInCommon - two operands have some registers in common       */
770 /*-----------------------------------------------------------------*/
771 static bool
772 regsInCommon (operand * op1, operand * op2)
773 {
774   symbol *sym1, *sym2;
775   int i;
776
777   /* if they have registers in common */
778   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
779     return FALSE;
780
781   sym1 = OP_SYMBOL (op1);
782   sym2 = OP_SYMBOL (op2);
783
784   if (sym1->nRegs == 0 || sym2->nRegs == 0)
785     return FALSE;
786
787   for (i = 0; i < sym1->nRegs; i++)
788     {
789       int j;
790       if (!sym1->regs[i])
791         continue;
792
793       for (j = 0; j < sym2->nRegs; j++)
794         {
795           if (!sym2->regs[j])
796             continue;
797
798           if (sym2->regs[j] == sym1->regs[i])
799             return TRUE;
800         }
801     }
802
803   return FALSE;
804 }
805
806 /*-----------------------------------------------------------------*/
807 /* operandsEqu - equivalent                                        */
808 /*-----------------------------------------------------------------*/
809 static bool
810 operandsEqu (operand * op1, operand * op2)
811 {
812   symbol *sym1, *sym2;
813
814   /* if they're not symbols */
815   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
816     return FALSE;
817
818   sym1 = OP_SYMBOL (op1);
819   sym2 = OP_SYMBOL (op2);
820
821   /* if both are itemps & one is spilt
822      and the other is not then false */
823   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
824       sym1->isspilt != sym2->isspilt)
825     return FALSE;
826
827   /* if they are the same */
828   if (sym1 == sym2)
829     return TRUE;
830
831   /* if they have the same rname */
832   if (sym1->rname[0] && sym2->rname[0] &&
833       strcmp (sym1->rname, sym2->rname) == 0 &&
834       !(IS_PARM (op2) && IS_ITEMP (op1)))
835     return TRUE;
836
837   /* if left is a tmp & right is not */
838   if (IS_ITEMP (op1) &&
839       !IS_ITEMP (op2) &&
840       sym1->isspilt &&
841       (sym1->usl.spillLoc == sym2))
842     return TRUE;
843
844   if (IS_ITEMP (op2) &&
845       !IS_ITEMP (op1) &&
846       sym2->isspilt &&
847       sym1->level > 0 &&
848       (sym2->usl.spillLoc == sym1))
849     return TRUE;
850
851   return FALSE;
852 }
853
854 /*-----------------------------------------------------------------*/
855 /* sameByte - two asmops have the same address at given offsets    */
856 /*-----------------------------------------------------------------*/
857 static bool
858 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
859 {
860   if (aop1 == aop2 && off1 == off2)
861     return TRUE;
862
863   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
864     return FALSE;
865
866   if (aop1->type != aop2->type)
867     return FALSE;
868
869   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
870     return FALSE;
871
872   return TRUE;
873 }
874
875 /*-----------------------------------------------------------------*/
876 /* sameRegs - two asmops have the same registers                   */
877 /*-----------------------------------------------------------------*/
878 static bool
879 sameRegs (asmop * aop1, asmop * aop2)
880 {
881   int i;
882
883   if (aop1 == aop2)
884     return TRUE;
885
886   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
887     return FALSE;
888
889   if (aop1->type != aop2->type)
890     return FALSE;
891
892   if (aop1->size != aop2->size)
893     return FALSE;
894
895   for (i = 0; i < aop1->size; i++)
896     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
897       return FALSE;
898
899   return TRUE;
900 }
901
902 /*-----------------------------------------------------------------*/
903 /* aopOp - allocates an asmop for an operand  :                    */
904 /*-----------------------------------------------------------------*/
905 static void
906 aopOp (operand * op, iCode * ic, bool result)
907 {
908   asmop *aop;
909   symbol *sym;
910   int i;
911
912   if (!op)
913     return;
914
915   /* if this a literal */
916   if (IS_OP_LITERAL (op))
917     {
918       op->aop = aop = newAsmop (AOP_LIT);
919       aop->aopu.aop_lit = op->operand.valOperand;
920       aop->size = getSize (operandType (op));
921       return;
922     }
923
924   /* if already has a asmop then continue */
925   if (op->aop)
926     {
927       op->aop->allocated++;
928       return;
929     }
930
931   /* if the underlying symbol has a aop */
932   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
933     {
934       op->aop = OP_SYMBOL (op)->aop;
935       op->aop->allocated++;
936       return;
937     }
938
939   /* if this is a true symbol */
940   if (IS_TRUE_SYMOP (op))
941     {
942       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
943       return;
944     }
945
946   /* this is a temporary : this has
947      only five choices :
948      a) register
949      b) spillocation
950      c) rematerialize
951      d) conditional
952      e) can be a return use only */
953
954   sym = OP_SYMBOL (op);
955
956   /* if the type is a conditional */
957   if (sym->regType == REG_CND)
958     {
959       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
960       aop->size = sym->ruonly ? 1 : 0;
961       return;
962     }
963
964   /* if it is spilt then two situations
965      a) is rematerialize
966      b) has a spill location */
967   if (sym->isspilt || sym->nRegs == 0)
968     {
969
970       /* rematerialize it NOW */
971       if (sym->remat)
972         {
973           sym->aop = op->aop = aop = aopForRemat (sym);
974           aop->size = operandSize (op);
975           return;
976         }
977
978       if (sym->accuse)
979         {
980           int i;
981           sym->aop = op->aop = aop = newAsmop (AOP_ACC);
982           aop->size = getSize (sym->type);
983           for (i = 0; i < 2; i++)
984             aop->aopu.aop_str[i] = accUse[i];
985           return;
986         }
987
988       if (sym->ruonly)
989         {
990           unsigned i;
991
992           sym->aop = op->aop = aop = newAsmop (AOP_STR);
993           aop->size = getSize (sym->type);
994           for (i = 0; i < fReturnSizeMCS51; i++)
995             aop->aopu.aop_str[i] = fReturn[i];
996           return;
997         }
998
999       if (sym->usl.spillLoc)
1000         {
1001           asmop *oldAsmOp = NULL;
1002
1003           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1004             {
1005               /* force a new aop if sizes differ */
1006               oldAsmOp = sym->usl.spillLoc->aop;
1007               sym->usl.spillLoc->aop = NULL;
1008             }
1009           sym->aop = op->aop = aop = aopForSym (ic, sym->usl.spillLoc, result);
1010           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1011             {
1012               /* Don't reuse the new aop, go with the last one */
1013               sym->usl.spillLoc->aop = oldAsmOp;
1014             }
1015           aop->size = getSize (sym->type);
1016           return;
1017         }
1018
1019       /* else must be a dummy iTemp */
1020       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1021       aop->size = getSize (sym->type);
1022       return;
1023     }
1024
1025   /* if the type is a bit register */
1026   if (sym->regType == REG_BIT)
1027     {
1028       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1029       aop->size = sym->nRegs;//1???
1030       aop->aopu.aop_reg[0] = sym->regs[0];
1031       aop->aopu.aop_dir = sym->regs[0]->name;
1032       return;
1033     }
1034
1035   /* must be in a register */
1036   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1037   aop->size = sym->nRegs;
1038   for (i = 0; i < sym->nRegs; i++)
1039     aop->aopu.aop_reg[i] = sym->regs[i];
1040 }
1041
1042 /*-----------------------------------------------------------------*/
1043 /* freeAsmop - free up the asmop given to an operand               */
1044 /*-----------------------------------------------------------------*/
1045 static void
1046 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1047 {
1048   asmop *aop;
1049
1050   if (!op)
1051     aop = aaop;
1052   else
1053     aop = op->aop;
1054
1055   if (!aop)
1056     return;
1057
1058   aop->allocated--;
1059
1060   if (aop->allocated)
1061     goto dealloc;
1062
1063   /* depending on the asmop type only three cases need work
1064      AOP_R0, AOP_R1 & AOP_STK */
1065   switch (aop->type)
1066     {
1067     case AOP_R0:
1068       if (R0INB)
1069         {
1070           emitcode ("mov", "r0,b");
1071           R0INB--;
1072         }
1073       else if (_G.r0Pushed)
1074         {
1075           if (pop)
1076             {
1077               emitcode ("pop", "ar0");
1078               _G.r0Pushed--;
1079             }
1080         }
1081       bitVectUnSetBit (ic->rUsed, R0_IDX);
1082       break;
1083
1084     case AOP_R1:
1085       if (R1INB)
1086         {
1087           emitcode ("mov", "r1,b");
1088           R1INB--;
1089         }
1090       else if (_G.r1Pushed)
1091         {
1092           if (pop)
1093             {
1094               emitcode ("pop", "ar1");
1095               _G.r1Pushed--;
1096             }
1097         }
1098       bitVectUnSetBit (ic->rUsed, R1_IDX);
1099       break;
1100
1101     case AOP_STK:
1102       {
1103         int sz = aop->size;
1104         int stk = aop->aopu.aop_stk + aop->size - 1;
1105         bitVectUnSetBit (ic->rUsed, R0_IDX);
1106         bitVectUnSetBit (ic->rUsed, R1_IDX);
1107
1108         getFreePtr (ic, &aop, FALSE);
1109
1110         if (stk)
1111           {
1112             emitcode ("mov", "a,_bp");
1113             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1114             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1115           }
1116         else
1117           {
1118             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1119           }
1120
1121         while (sz--)
1122           {
1123             emitcode ("pop", "acc");
1124             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1125             if (!sz)
1126               break;
1127             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1128           }
1129         op->aop = aop;
1130         freeAsmop (op, NULL, ic, TRUE);
1131         if (_G.r1Pushed)
1132           {
1133             emitcode ("pop", "ar1");
1134             _G.r1Pushed--;
1135           }
1136         if (_G.r0Pushed)
1137           {
1138             emitcode ("pop", "ar0");
1139             _G.r0Pushed--;
1140           }
1141       }
1142       break;
1143     }
1144
1145 dealloc:
1146   /* all other cases just dealloc */
1147   if (op)
1148     {
1149       op->aop = NULL;
1150       if (IS_SYMOP (op))
1151         {
1152           OP_SYMBOL (op)->aop = NULL;
1153           /* if the symbol has a spill */
1154           if (SPIL_LOC (op))
1155             SPIL_LOC (op)->aop = NULL;
1156         }
1157     }
1158 }
1159
1160 /*------------------------------------------------------------------*/
1161 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1162 /*                      pop r0 or r1 off stack if pushed            */
1163 /*------------------------------------------------------------------*/
1164 static void
1165 freeForBranchAsmop (operand * op)
1166 {
1167   asmop *aop;
1168
1169   if (!op)
1170     return;
1171
1172   aop = op->aop;
1173
1174   if (!aop)
1175     return;
1176
1177   if (!aop->allocated)
1178     return;
1179
1180   switch (aop->type)
1181     {
1182     case AOP_R0:
1183       if (R0INB)
1184         {
1185           emitcode ("mov", "r0,b");
1186         }
1187       else if (_G.r0Pushed)
1188         {
1189           emitcode ("pop", "ar0");
1190         }
1191       break;
1192
1193     case AOP_R1:
1194       if (R1INB)
1195         {
1196           emitcode ("mov", "r1,b");
1197         }
1198       else if (_G.r1Pushed)
1199         {
1200           emitcode ("pop", "ar1");
1201         }
1202       break;
1203
1204     case AOP_STK:
1205       {
1206         int sz = aop->size;
1207         int stk = aop->aopu.aop_stk + aop->size - 1;
1208
1209         emitcode ("mov", "b,r0");
1210         if (stk)
1211           {
1212             emitcode ("mov", "a,_bp");
1213             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1214             emitcode ("mov", "r0,a");
1215           }
1216         else
1217           {
1218             emitcode ("mov", "r0,_bp");
1219           }
1220
1221         while (sz--)
1222           {
1223             emitcode ("pop", "acc");
1224             emitcode ("mov", "@r0,a");
1225             if (!sz)
1226               break;
1227             emitcode ("dec", "r0");
1228           }
1229         emitcode ("mov", "r0,b");
1230       }
1231     }
1232
1233 }
1234
1235 /*-----------------------------------------------------------------*/
1236 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1237 /*                 clobber the accumulator                         */
1238 /*-----------------------------------------------------------------*/
1239 static bool
1240 aopGetUsesAcc (operand * oper, int offset)
1241 {
1242   asmop * aop = AOP (oper);
1243
1244   if (offset > (aop->size - 1))
1245     return FALSE;
1246
1247   switch (aop->type)
1248     {
1249
1250     case AOP_R0:
1251     case AOP_R1:
1252       if (aop->paged)
1253         return TRUE;
1254       return FALSE;
1255     case AOP_DPTR:
1256       return TRUE;
1257     case AOP_IMMD:
1258       return FALSE;
1259     case AOP_DIR:
1260       return FALSE;
1261     case AOP_REG:
1262       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1263       return FALSE;
1264     case AOP_CRY:
1265       return TRUE;
1266     case AOP_ACC:
1267       if (offset)
1268         return FALSE;
1269       return TRUE;
1270     case AOP_LIT:
1271       return FALSE;
1272     case AOP_STR:
1273       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1274         return TRUE;
1275       return FALSE;
1276     case AOP_DUMMY:
1277       return FALSE;
1278     default:
1279       /* Error case --- will have been caught already */
1280       wassert(0);
1281       return FALSE;
1282     }
1283 }
1284
1285 /*-------------------------------------------------------------------*/
1286 /* aopGet - for fetching value of the aop                            */
1287 /*-------------------------------------------------------------------*/
1288 static char *
1289 aopGet (operand * oper, int offset, bool bit16, bool dname)
1290 {
1291   asmop * aop = AOP (oper);
1292
1293   /* offset is greater than
1294      size then zero */
1295   if (offset > (aop->size - 1) &&
1296       aop->type != AOP_LIT)
1297     return zero;
1298
1299   /* depending on type */
1300   switch (aop->type)
1301     {
1302     case AOP_DUMMY:
1303       return zero;
1304
1305     case AOP_R0:
1306     case AOP_R1:
1307       /* if we need to increment it */
1308       while (offset > aop->coff)
1309         {
1310           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1311           aop->coff++;
1312         }
1313
1314       while (offset < aop->coff)
1315         {
1316           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1317           aop->coff--;
1318         }
1319
1320       aop->coff = offset;
1321       if (aop->paged)
1322         {
1323           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1324           return (dname ? "acc" : "a");
1325         }
1326       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1327       return Safe_strdup(buffer);
1328
1329     case AOP_DPTR:
1330       if (aop->code && aop->coff==0 && offset>=1) {
1331         emitcode ("mov", "a,#0x%02x", offset);
1332         emitcode ("movc", "a,@a+dptr");
1333         return (dname ? "acc" : "a");
1334       }
1335
1336       while (offset > aop->coff)
1337         {
1338           emitcode ("inc", "dptr");
1339           aop->coff++;
1340         }
1341
1342       while (offset < aop->coff)
1343         {
1344           emitcode ("lcall", "__decdptr");
1345           aop->coff--;
1346         }
1347
1348       aop->coff = offset;
1349       if (aop->code)
1350         {
1351           emitcode ("clr", "a");
1352           emitcode ("movc", "a,@a+dptr");
1353         }
1354       else
1355         {
1356           emitcode ("movx", "a,@dptr");
1357         }
1358       return (dname ? "acc" : "a");
1359
1360     case AOP_IMMD:
1361       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1362         {
1363           SNPRINTF(buffer, sizeof(buffer),
1364                    "%s",aop->aopu.aop_immd.aop_immd2);
1365         }
1366       else if (bit16)
1367         {
1368           SNPRINTF(buffer, sizeof(buffer),
1369                    "#%s", aop->aopu.aop_immd.aop_immd1);
1370         }
1371       else if (offset)
1372         {
1373           SNPRINTF (buffer, sizeof(buffer),
1374                     "#(%s >> %d)",
1375                     aop->aopu.aop_immd.aop_immd1,
1376                     offset * 8);
1377         }
1378       else
1379         {
1380           SNPRINTF (buffer, sizeof(buffer),
1381                     "#%s",
1382                     aop->aopu.aop_immd.aop_immd1);
1383         }
1384       return Safe_strdup(buffer);
1385
1386     case AOP_DIR:
1387       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1388         {
1389           SNPRINTF (buffer, sizeof(buffer),
1390                     "(%s >> %d)",
1391                     aop->aopu.aop_dir, offset * 8);
1392         }
1393       else if (offset)
1394         {
1395           SNPRINTF (buffer, sizeof(buffer),
1396                     "(%s + %d)",
1397                     aop->aopu.aop_dir,
1398                     offset);
1399         }
1400       else
1401         {
1402           SNPRINTF (buffer, sizeof(buffer),
1403                     "%s",
1404                     aop->aopu.aop_dir);
1405         }
1406
1407       return Safe_strdup(buffer);
1408
1409     case AOP_REG:
1410       if (dname)
1411         return aop->aopu.aop_reg[offset]->dname;
1412       else
1413         return aop->aopu.aop_reg[offset]->name;
1414
1415     case AOP_CRY:
1416       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1417       emitcode ("clr", "a");
1418       emitcode ("rlc", "a");
1419       return (dname ? "acc" : "a");
1420
1421     case AOP_ACC:
1422       if (!offset && dname)
1423         return "acc";
1424       return aop->aopu.aop_str[offset];
1425
1426     case AOP_LIT:
1427       return aopLiteral (aop->aopu.aop_lit, offset);
1428
1429     case AOP_STR:
1430       aop->coff = offset;
1431       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1432           dname)
1433         return "acc";
1434
1435       return aop->aopu.aop_str[offset];
1436
1437     }
1438
1439   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1440           "aopget got unsupported aop->type");
1441   exit (1);
1442 }
1443
1444 /*-----------------------------------------------------------------*/
1445 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1446 /*                 clobber the accumulator                         */
1447 /*-----------------------------------------------------------------*/
1448 static bool
1449 aopPutUsesAcc (operand * oper, const char *s, int offset)
1450 {
1451   asmop * aop = AOP (oper);
1452
1453   if (offset > (aop->size - 1))
1454     return FALSE;
1455
1456   switch (aop->type)
1457     {
1458     case AOP_DUMMY:
1459       return TRUE;
1460     case AOP_DIR:
1461       return FALSE;
1462     case AOP_REG:
1463       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1464       return FALSE;
1465     case AOP_DPTR:
1466       return TRUE;
1467     case AOP_R0:
1468     case AOP_R1:
1469       return ((aop->paged) || (*s == '@'));
1470     case AOP_STK:
1471       return (*s == '@');
1472     case AOP_CRY:
1473       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1474     case AOP_STR:
1475       return FALSE;
1476     case AOP_IMMD:
1477       return FALSE;
1478     case AOP_ACC:
1479       return FALSE;
1480     default:
1481       /* Error case --- will have been caught already */
1482       wassert(0);
1483       return FALSE;
1484     }
1485 }
1486
1487 /*-----------------------------------------------------------------*/
1488 /* aopPut - puts a string for a aop and indicates if acc is in use */
1489 /*-----------------------------------------------------------------*/
1490 static bool
1491 aopPut (operand * result, const char *s, int offset)
1492 {
1493   bool bvolatile = isOperandVolatile (result, FALSE);
1494   bool accuse = FALSE;
1495   asmop * aop = AOP (result);
1496   const char *d = NULL;
1497
1498   if (aop->size && offset > (aop->size - 1))
1499     {
1500       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1501               "aopPut got offset > aop->size");
1502       exit (1);
1503     }
1504
1505   /* will assign value to value */
1506   /* depending on where it is ofcourse */
1507   switch (aop->type)
1508     {
1509     case AOP_DUMMY:
1510       MOVA (s);         /* read s in case it was volatile */
1511       accuse = TRUE;
1512       break;
1513
1514     case AOP_DIR:
1515       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1516         {
1517           SNPRINTF (buffer, sizeof(buffer),
1518                     "(%s >> %d)",
1519                     aop->aopu.aop_dir, offset * 8);
1520         }
1521       else if (offset)
1522         {
1523           SNPRINTF (buffer, sizeof(buffer),
1524                     "(%s + %d)",
1525                     aop->aopu.aop_dir, offset);
1526         }
1527       else
1528         {
1529           SNPRINTF (buffer, sizeof(buffer),
1530                     "%s",
1531                     aop->aopu.aop_dir);
1532         }
1533
1534       if (strcmp (buffer, s) || bvolatile)
1535         {
1536           emitcode ("mov", "%s,%s", buffer, s);
1537         }
1538       if (!strcmp (buffer, "acc"))
1539         {
1540           accuse = TRUE;
1541         }
1542       break;
1543
1544     case AOP_REG:
1545       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1546           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1547         {
1548           if (*s == '@' ||
1549               strcmp (s, "r0") == 0 ||
1550               strcmp (s, "r1") == 0 ||
1551               strcmp (s, "r2") == 0 ||
1552               strcmp (s, "r3") == 0 ||
1553               strcmp (s, "r4") == 0 ||
1554               strcmp (s, "r5") == 0 ||
1555               strcmp (s, "r6") == 0 ||
1556               strcmp (s, "r7") == 0)
1557             {
1558               emitcode ("mov", "%s,%s",
1559                         aop->aopu.aop_reg[offset]->dname, s);
1560             }
1561           else
1562             {
1563               emitcode ("mov", "%s,%s",
1564                         aop->aopu.aop_reg[offset]->name, s);
1565             }
1566         }
1567       break;
1568
1569     case AOP_DPTR:
1570       if (aop->code)
1571         {
1572           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1573                   "aopPut writing to code space");
1574           exit (1);
1575         }
1576
1577       while (offset > aop->coff)
1578         {
1579           aop->coff++;
1580           emitcode ("inc", "dptr");
1581         }
1582
1583       while (offset < aop->coff)
1584         {
1585           aop->coff--;
1586           emitcode ("lcall", "__decdptr");
1587         }
1588
1589       aop->coff = offset;
1590
1591       /* if not in accumulator */
1592       MOVA (s);
1593
1594       emitcode ("movx", "@dptr,a");
1595       break;
1596
1597     case AOP_R0:
1598     case AOP_R1:
1599       while (offset > aop->coff)
1600         {
1601           aop->coff++;
1602           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1603         }
1604       while (offset < aop->coff)
1605         {
1606           aop->coff--;
1607           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1608         }
1609       aop->coff = offset;
1610
1611       if (aop->paged)
1612         {
1613           MOVA (s);
1614           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1615         }
1616       else if (*s == '@')
1617         {
1618           MOVA (s);
1619           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1620         }
1621       else if (strcmp (s, "r0") == 0 ||
1622                strcmp (s, "r1") == 0 ||
1623                strcmp (s, "r2") == 0 ||
1624                strcmp (s, "r3") == 0 ||
1625                strcmp (s, "r4") == 0 ||
1626                strcmp (s, "r5") == 0 ||
1627                strcmp (s, "r6") == 0 ||
1628                strcmp (s, "r7") == 0)
1629         {
1630           char buffer[10];
1631           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1632           emitcode ("mov", "@%s,%s",
1633                     aop->aopu.aop_ptr->name, buffer);
1634         }
1635       else
1636         {
1637           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1638         }
1639       break;
1640
1641     case AOP_STK:
1642       if (strcmp (s, "a") == 0)
1643         {
1644           emitcode ("push", "acc");
1645         }
1646       else if (*s=='@')
1647         {
1648           MOVA(s);
1649           emitcode ("push", "acc");
1650         }
1651       else if (strcmp (s, "r0") == 0 ||
1652                strcmp (s, "r1") == 0 ||
1653                strcmp (s, "r2") == 0 ||
1654                strcmp (s, "r3") == 0 ||
1655                strcmp (s, "r4") == 0 ||
1656                strcmp (s, "r5") == 0 ||
1657                strcmp (s, "r6") == 0 ||
1658                strcmp (s, "r7") == 0)
1659         {
1660           char buffer[10];
1661           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1662           emitcode ("push", buffer);
1663         }
1664       else
1665         {
1666           emitcode ("push", s);
1667         }
1668
1669       break;
1670
1671     case AOP_CRY:
1672       // destination is carry for return-use-only
1673       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1674       // source is no literal and not in carry
1675       if ((s != zero) && (s != one) && strcmp (s, "c"))
1676         {
1677           MOVA (s);
1678           /* set C, if a >= 1 */
1679           emitcode ("add", "a,#0xff");
1680           s = "c";
1681         }
1682       // now source is zero, one or carry
1683
1684       /* if result no bit variable */
1685       if (!d)
1686         {
1687           if (!strcmp (s, "c"))
1688             {
1689               /* inefficient: move carry into A and use jz/jnz */
1690               emitcode ("clr", "a");
1691               emitcode ("rlc", "a");
1692               accuse = TRUE;
1693             }
1694           else
1695             {
1696               MOVA (s);
1697               accuse = TRUE;
1698             }
1699         }
1700       else if (s == zero)
1701           emitcode ("clr", "%s", d);
1702       else if (s == one)
1703           emitcode ("setb", "%s", d);
1704       else if (strcmp (s, d))
1705           emitcode ("mov", "%s,c", d);
1706       break;
1707
1708     case AOP_STR:
1709       aop->coff = offset;
1710       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1711         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1712       break;
1713
1714     case AOP_ACC:
1715       accuse = TRUE;
1716       aop->coff = offset;
1717       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1718         break;
1719
1720       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1721         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1722       break;
1723
1724     default:
1725       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1726               "aopPut got unsupported aop->type");
1727       exit (1);
1728     }
1729
1730     return accuse;
1731 }
1732
1733
1734 #if 0
1735 /*-----------------------------------------------------------------*/
1736 /* pointToEnd :- points to the last byte of the operand            */
1737 /*-----------------------------------------------------------------*/
1738 static void
1739 pointToEnd (asmop * aop)
1740 {
1741   int count;
1742   if (!aop)
1743     return;
1744
1745   aop->coff = count = (aop->size - 1);
1746   switch (aop->type)
1747     {
1748     case AOP_R0:
1749     case AOP_R1:
1750       while (count--)
1751         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1752       break;
1753     case AOP_DPTR:
1754       while (count--)
1755         emitcode ("inc", "dptr");
1756       break;
1757     }
1758
1759 }
1760 #endif
1761
1762 /*-----------------------------------------------------------------*/
1763 /* reAdjustPreg - points a register back to where it should        */
1764 /*-----------------------------------------------------------------*/
1765 static void
1766 reAdjustPreg (asmop * aop)
1767 {
1768   if ((aop->coff==0) || (aop->size <= 1))
1769     return;
1770
1771   switch (aop->type)
1772     {
1773     case AOP_R0:
1774     case AOP_R1:
1775       while (aop->coff--)
1776         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1777       break;
1778     case AOP_DPTR:
1779       while (aop->coff--)
1780         {
1781           emitcode ("lcall", "__decdptr");
1782         }
1783       break;
1784     }
1785   aop->coff = 0;
1786 }
1787
1788 /*-----------------------------------------------------------------*/
1789 /* opIsGptr: returns non-zero if the passed operand is             */
1790 /* a generic pointer type.                                         */
1791 /*-----------------------------------------------------------------*/
1792 static int
1793 opIsGptr (operand * op)
1794 {
1795   if (op && IS_GENPTR (operandType (op)) && (AOP_SIZE (op) == GPTRSIZE))
1796     {
1797       return 1;
1798     }
1799   return 0;
1800 }
1801
1802 /*-----------------------------------------------------------------*/
1803 /* getDataSize - get the operand data size                         */
1804 /*-----------------------------------------------------------------*/
1805 static int
1806 getDataSize (operand * op)
1807 {
1808   int size = AOP_SIZE (op);
1809
1810   if (size == GPTRSIZE)
1811     {
1812       sym_link *type = operandType (op);
1813       if (IS_GENPTR (type))
1814         {
1815           /* generic pointer; arithmetic operations
1816            * should ignore the high byte (pointer type).
1817            */
1818           size--;
1819         }
1820     }
1821   return size;
1822 }
1823
1824 /*-----------------------------------------------------------------*/
1825 /* outAcc - output Acc                                             */
1826 /*-----------------------------------------------------------------*/
1827 static void
1828 outAcc (operand * result)
1829 {
1830   int size, offset;
1831   size = getDataSize (result);
1832   if (size)
1833     {
1834       aopPut (result, "a", 0);
1835       size--;
1836       offset = 1;
1837       /* unsigned or positive */
1838       while (size--)
1839         {
1840           aopPut (result, zero, offset++);
1841         }
1842     }
1843 }
1844
1845 /*-----------------------------------------------------------------*/
1846 /* outBitC - output a bit C                                        */
1847 /*-----------------------------------------------------------------*/
1848 static void
1849 outBitC (operand * result)
1850 {
1851   /* if the result is bit */
1852   if (AOP_TYPE (result) == AOP_CRY)
1853     {
1854       if (!IS_OP_RUONLY (result))
1855         aopPut (result, "c", 0);
1856     }
1857   else if (AOP_TYPE (result) != AOP_DUMMY)
1858     {
1859       emitcode ("clr", "a");
1860       emitcode ("rlc", "a");
1861       outAcc (result);
1862     }
1863 }
1864
1865 /*-----------------------------------------------------------------*/
1866 /* toBoolean - emit code for orl a,operator(sizeop)                */
1867 /*-----------------------------------------------------------------*/
1868 static void
1869 toBoolean (operand * oper)
1870 {
1871   int size = AOP_SIZE (oper) - 1;
1872   int offset = 1;
1873   bool AccUsed = FALSE;
1874   bool pushedB;
1875
1876   while (!AccUsed && size--)
1877     {
1878       AccUsed |= aopGetUsesAcc(oper, offset++);
1879     }
1880
1881   size = AOP_SIZE (oper) - 1;
1882   offset = 1;
1883   MOVA (aopGet (oper, 0, FALSE, FALSE));
1884   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1885     {
1886       pushedB = pushB ();
1887       emitcode("mov", "b,a");
1888       while (--size)
1889         {
1890           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1891           emitcode ("orl", "b,a");
1892         }
1893       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1894       emitcode ("orl", "a,b");
1895       popB (pushedB);
1896     }
1897   else
1898     {
1899       while (size--)
1900         {
1901           emitcode ("orl", "a,%s",
1902                     aopGet (oper, offset++, FALSE, FALSE));
1903         }
1904     }
1905 }
1906
1907 /*-----------------------------------------------------------------*/
1908 /* toCarry - make boolean and move into carry                      */
1909 /*-----------------------------------------------------------------*/
1910 static void
1911 toCarry (operand * oper)
1912 {
1913   /* if the operand is a literal then
1914      we know what the value is */
1915   if (AOP_TYPE (oper) == AOP_LIT)
1916     {
1917       if ((int) operandLitValue (oper))
1918         SETC;
1919       else
1920         CLRC;
1921     }
1922   else if (AOP_TYPE (oper) == AOP_CRY)
1923     {
1924       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1925     }
1926   else
1927     {
1928       /* or the operand into a */
1929       toBoolean (oper);
1930       /* set C, if a >= 1 */
1931       emitcode ("add", "a,#0xff");
1932     }
1933 }
1934
1935 /*-----------------------------------------------------------------*/
1936 /* assignBit - assign operand to bit operand                       */
1937 /*-----------------------------------------------------------------*/
1938 static void
1939 assignBit (operand * result, operand * right)
1940 {
1941   /* if the right side is a literal then
1942      we know what the value is */
1943   if (AOP_TYPE (right) == AOP_LIT)
1944     {
1945       if ((int) operandLitValue (right))
1946         aopPut (result, one, 0);
1947       else
1948         aopPut (result, zero, 0);
1949     }
1950   else
1951     {
1952       toCarry (right);
1953       aopPut (result, "c", 0);
1954     }
1955 }
1956
1957
1958 /*-------------------------------------------------------------------*/
1959 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1960 /*-------------------------------------------------------------------*/
1961 static char *
1962 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1963 {
1964   char * l;
1965
1966   if (aopGetUsesAcc (oper, offset))
1967     {
1968       emitcode("mov", "b,a");
1969       MOVA (aopGet (oper, offset, bit16, dname));
1970       emitcode("xch", "a,b");
1971       aopPut (oper, "a", offset);
1972       emitcode("xch", "a,b");
1973       l = "b";
1974     }
1975   else
1976     {
1977       l = aopGet (oper, offset, bit16, dname);
1978       emitcode("xch", "a,%s", l);
1979     }
1980   return l;
1981 }
1982
1983
1984 /*-----------------------------------------------------------------*/
1985 /* genNot - generate code for ! operation                          */
1986 /*-----------------------------------------------------------------*/
1987 static void
1988 genNot (iCode * ic)
1989 {
1990   symbol *tlbl;
1991
1992   D (emitcode (";", "genNot"));
1993
1994   /* assign asmOps to operand & result */
1995   aopOp (IC_LEFT (ic), ic, FALSE);
1996   aopOp (IC_RESULT (ic), ic, TRUE);
1997
1998   /* if in bit space then a special case */
1999   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2000     {
2001       /* if left==result then cpl bit */
2002       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2003         {
2004           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2005         }
2006       else
2007         {
2008           toCarry (IC_LEFT (ic));
2009           emitcode ("cpl", "c");
2010           outBitC (IC_RESULT (ic));
2011         }
2012       goto release;
2013     }
2014
2015   toBoolean (IC_LEFT (ic));
2016
2017   /* set C, if a == 0 */
2018   tlbl = newiTempLabel (NULL);
2019   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2020   emitLabel (tlbl);
2021   outBitC (IC_RESULT (ic));
2022
2023 release:
2024   /* release the aops */
2025   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2026   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2027 }
2028
2029
2030 /*-----------------------------------------------------------------*/
2031 /* genCpl - generate code for complement                           */
2032 /*-----------------------------------------------------------------*/
2033 static void
2034 genCpl (iCode * ic)
2035 {
2036   int offset = 0;
2037   int size;
2038   symbol *tlbl;
2039   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2040
2041   D(emitcode (";", "genCpl"));
2042
2043   /* assign asmOps to operand & result */
2044   aopOp (IC_LEFT (ic), ic, FALSE);
2045   aopOp (IC_RESULT (ic), ic, TRUE);
2046
2047   /* special case if in bit space */
2048   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2049     {
2050       char *l;
2051
2052       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2053           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2054         {
2055           /* promotion rules are responsible for this strange result:
2056              bit -> int -> ~int -> bit
2057              uchar -> int -> ~int -> bit
2058           */
2059           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2060           goto release;
2061         }
2062
2063       tlbl=newiTempLabel(NULL);
2064       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2065       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2066           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2067           IS_AOP_PREG (IC_LEFT (ic)))
2068         {
2069           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2070         }
2071       else
2072         {
2073           MOVA (l);
2074           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2075         }
2076       emitLabel (tlbl);
2077       outBitC (IC_RESULT(ic));
2078       goto release;
2079     }
2080
2081   size = AOP_SIZE (IC_RESULT (ic));
2082   while (size--)
2083     {
2084       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2085       MOVA (l);
2086       emitcode ("cpl", "a");
2087       aopPut (IC_RESULT (ic), "a", offset++);
2088     }
2089
2090
2091 release:
2092   /* release the aops */
2093   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2094   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2095 }
2096
2097 /*-----------------------------------------------------------------*/
2098 /* genUminusFloat - unary minus for floating points                */
2099 /*-----------------------------------------------------------------*/
2100 static void
2101 genUminusFloat (operand * op, operand * result)
2102 {
2103   int size, offset = 0;
2104   char *l;
2105
2106   D (emitcode (";", "genUminusFloat"));
2107
2108   /* for this we just copy and then flip the bit */
2109
2110   size = AOP_SIZE (op) - 1;
2111
2112   while (size--)
2113     {
2114       aopPut (result,
2115               aopGet (op, offset, FALSE, FALSE),
2116               offset);
2117       offset++;
2118     }
2119
2120   l = aopGet (op, offset, FALSE, FALSE);
2121   MOVA (l);
2122
2123   emitcode ("cpl", "acc.7");
2124   aopPut (result, "a", offset);
2125 }
2126
2127 /*-----------------------------------------------------------------*/
2128 /* genUminus - unary minus code generation                         */
2129 /*-----------------------------------------------------------------*/
2130 static void
2131 genUminus (iCode * ic)
2132 {
2133   int offset, size;
2134   sym_link *optype;
2135
2136   D (emitcode (";", "genUminus"));
2137
2138   /* assign asmops */
2139   aopOp (IC_LEFT (ic), ic, FALSE);
2140   aopOp (IC_RESULT (ic), ic, TRUE);
2141
2142   /* if both in bit space then special
2143      case */
2144   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2145       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2146     {
2147
2148       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2149       emitcode ("cpl", "c");
2150       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2151       goto release;
2152     }
2153
2154   optype = operandType (IC_LEFT (ic));
2155
2156   /* if float then do float stuff */
2157   if (IS_FLOAT (optype))
2158     {
2159       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2160       goto release;
2161     }
2162
2163   /* otherwise subtract from zero */
2164   size = AOP_SIZE (IC_LEFT (ic));
2165   offset = 0;
2166   while (size--)
2167     {
2168       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2169       if (!strcmp (l, "a"))
2170         {
2171           if (offset == 0)
2172             SETC;
2173           emitcode ("cpl", "a");
2174           emitcode ("addc", "a,#0x00");
2175         }
2176       else
2177         {
2178           if (offset == 0)
2179             CLRC;
2180           emitcode ("clr", "a");
2181           emitcode ("subb", "a,%s", l);
2182         }
2183       aopPut (IC_RESULT (ic), "a", offset++);
2184     }
2185
2186   /* if any remaining bytes in the result */
2187   /* we just need to propagate the sign   */
2188   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2189     {
2190       emitcode ("rlc", "a");
2191       emitcode ("subb", "a,acc");
2192       while (size--)
2193         aopPut (IC_RESULT (ic), "a", offset++);
2194     }
2195
2196 release:
2197   /* release the aops */
2198   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2199   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2200 }
2201
2202 /*-----------------------------------------------------------------*/
2203 /* saveRegisters - will look for a call and save the registers     */
2204 /*-----------------------------------------------------------------*/
2205 static void
2206 saveRegisters (iCode * lic)
2207 {
2208   int i;
2209   iCode *ic;
2210   bitVect *rsave;
2211
2212   /* look for call */
2213   for (ic = lic; ic; ic = ic->next)
2214     if (ic->op == CALL || ic->op == PCALL)
2215       break;
2216
2217   if (!ic)
2218     {
2219       fprintf (stderr, "found parameter push with no function call\n");
2220       return;
2221     }
2222
2223   /* if the registers have been saved already or don't need to be then
2224      do nothing */
2225   if (ic->regsSaved)
2226     return;
2227   if (IS_SYMOP(IC_LEFT(ic)) &&
2228       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2229        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2230     return;
2231
2232   /* save the registers in use at this time but skip the
2233      ones for the result */
2234   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2235                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2236
2237   ic->regsSaved = 1;
2238   if (options.useXstack)
2239     {
2240       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2241       int nBits = bitVectnBitsOn (rsavebits);
2242       int count = bitVectnBitsOn (rsave);
2243
2244       if (nBits != 0)
2245         {
2246           count = count - nBits + 1;
2247           /* remove all but the first bits as they are pushed all at once */
2248           rsave = bitVectCplAnd (rsave, rsavebits);
2249           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2250         }
2251       freeBitVect (rsavebits);
2252
2253       if (count == 1)
2254         {
2255           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2256           if (reg->type == REG_BIT)
2257             {
2258               emitcode ("mov", "a,%s", reg->base);
2259             }
2260           else
2261             {
2262               emitcode ("mov", "a,%s", reg->name);
2263             }
2264           emitcode ("mov", "r0,%s", spname);
2265           emitcode ("inc", "%s", spname);// allocate before use
2266           emitcode ("movx", "@r0,a");
2267           if (bitVectBitValue (rsave, R0_IDX))
2268             emitcode ("mov", "r0,a");
2269         }
2270       else if (count != 0)
2271         {
2272           if (bitVectBitValue (rsave, R0_IDX))
2273             {
2274               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2275             }
2276           emitcode ("mov", "r0,%s", spname);
2277           MOVA ("r0");
2278           emitcode ("add", "a,#0x%02x", count);
2279           emitcode ("mov", "%s,a", spname);
2280           for (i = 0; i < mcs51_nRegs; i++)
2281             {
2282               if (bitVectBitValue (rsave, i))
2283                 {
2284                   regs * reg = REG_WITH_INDEX (i);
2285                   if (i == R0_IDX)
2286                     {
2287                       emitcode ("pop", "acc");
2288                       emitcode ("push", "acc");
2289                     }
2290                   else if (reg->type == REG_BIT)
2291                     {
2292                       emitcode ("mov", "a,%s", reg->base);
2293                     }
2294                   else
2295                     {
2296                       emitcode ("mov", "a,%s", reg->name);
2297                     }
2298                   emitcode ("movx", "@r0,a");
2299                   if (--count)
2300                     {
2301                       emitcode ("inc", "r0");
2302                     }
2303                 }
2304             }
2305           if (bitVectBitValue (rsave, R0_IDX))
2306             {
2307               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2308             }
2309         }
2310     }
2311   else
2312     {
2313       bool bits_pushed = FALSE;
2314       for (i = 0; i < mcs51_nRegs; i++)
2315         {
2316           if (bitVectBitValue (rsave, i))
2317             {
2318               bits_pushed = pushReg (i, bits_pushed);
2319             }
2320         }
2321     }
2322   freeBitVect (rsave);
2323 }
2324
2325 /*-----------------------------------------------------------------*/
2326 /* unsaveRegisters - pop the pushed registers                      */
2327 /*-----------------------------------------------------------------*/
2328 static void
2329 unsaveRegisters (iCode * ic)
2330 {
2331   int i;
2332   bitVect *rsave;
2333
2334   /* restore the registers in use at this time but skip the
2335      ones for the result */
2336   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2337                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2338
2339   if (options.useXstack)
2340     {
2341       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2342       int nBits = bitVectnBitsOn (rsavebits);
2343       int count = bitVectnBitsOn (rsave);
2344
2345       if (nBits != 0)
2346         {
2347           count = count - nBits + 1;
2348           /* remove all but the first bits as they are popped all at once */
2349           rsave = bitVectCplAnd (rsave, rsavebits);
2350           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2351         }
2352       freeBitVect (rsavebits);
2353
2354       if (count == 1)
2355         {
2356           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2357           emitcode ("mov", "r0,%s", spname);
2358           emitcode ("dec", "r0");
2359           emitcode ("movx", "a,@r0");
2360           if (reg->type == REG_BIT)
2361             {
2362               emitcode ("mov", "%s,a", reg->base);
2363             }
2364           else
2365             {
2366               emitcode ("mov", "%s,a", reg->name);
2367             }
2368           emitcode ("dec", "%s", spname);
2369         }
2370       else if (count != 0)
2371         {
2372           emitcode ("mov", "r0,%s", spname);
2373           for (i = mcs51_nRegs; i >= 0; i--)
2374             {
2375               if (bitVectBitValue (rsave, i))
2376                 {
2377                   regs * reg = REG_WITH_INDEX (i);
2378                   emitcode ("dec", "r0");
2379                   emitcode ("movx", "a,@r0");
2380                   if (i == R0_IDX)
2381                     {
2382                       emitcode ("push", "acc");
2383                     }
2384                   else if (reg->type == REG_BIT)
2385                     {
2386                       emitcode ("mov", "%s,a", reg->base);
2387                     }
2388                   else
2389                     {
2390                       emitcode ("mov", "%s,a", reg->name);
2391                     }
2392                 }
2393             }
2394           emitcode ("mov", "%s,r0", spname);
2395           if (bitVectBitValue (rsave, R0_IDX))
2396             {
2397               emitcode ("pop", "ar0");
2398             }
2399         }
2400     }
2401   else
2402     {
2403       bool bits_popped = FALSE;
2404       for (i = mcs51_nRegs; i >= 0; i--)
2405         {
2406           if (bitVectBitValue (rsave, i))
2407             {
2408               bits_popped = popReg (i, bits_popped);
2409             }
2410         }
2411     }
2412   freeBitVect (rsave);
2413 }
2414
2415
2416 /*-----------------------------------------------------------------*/
2417 /* pushSide -                                                      */
2418 /*-----------------------------------------------------------------*/
2419 static void
2420 pushSide (operand * oper, int size, iCode * ic)
2421 {
2422   int offset = 0;
2423   int nPushed = _G.r0Pushed + _G.r1Pushed;
2424
2425   aopOp (oper, ic, FALSE);
2426
2427   if (nPushed != _G.r0Pushed + _G.r1Pushed)
2428     {
2429       while (offset < size)
2430         {
2431           char *l = aopGet (oper, offset, FALSE, TRUE);
2432           emitcode ("mov", "%s,%s", fReturn[offset++], l);
2433         }
2434       freeAsmop (oper, NULL, ic, TRUE);
2435       offset = 0;
2436       while (offset < size)
2437         {
2438           emitcode ("push", "%s", fReturn[offset++]);
2439         }
2440       return;
2441     }
2442
2443   while (size--)
2444     {
2445       char *l = aopGet (oper, offset++, FALSE, TRUE);
2446       if (AOP_TYPE (oper) != AOP_REG &&
2447           AOP_TYPE (oper) != AOP_DIR &&
2448           strcmp (l, "a"))
2449         {
2450           MOVA (l);
2451           emitcode ("push", "acc");
2452         }
2453       else
2454         {
2455           emitcode ("push", "%s", l);
2456         }
2457     }
2458
2459   freeAsmop (oper, NULL, ic, TRUE);
2460 }
2461
2462 /*-----------------------------------------------------------------*/
2463 /* assignResultValue - also indicates if acc is in use afterwards  */
2464 /*-----------------------------------------------------------------*/
2465 static bool
2466 assignResultValue (operand * oper, operand * func)
2467 {
2468   int offset = 0;
2469   int size = AOP_SIZE (oper);
2470   bool accuse = FALSE;
2471   bool pushedA = FALSE;
2472
2473   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2474     {
2475       outBitC (oper);
2476       return FALSE;
2477     }
2478
2479   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2480     {
2481       emitcode ("push", "acc");
2482       pushedA = TRUE;
2483     }
2484   while (size--)
2485     {
2486       if ((offset == 3) && pushedA)
2487         emitcode ("pop", "acc");
2488       accuse |= aopPut (oper, fReturn[offset], offset);
2489       offset++;
2490     }
2491   return accuse;
2492 }
2493
2494
2495 /*-----------------------------------------------------------------*/
2496 /* genXpush - pushes onto the external stack                       */
2497 /*-----------------------------------------------------------------*/
2498 static void
2499 genXpush (iCode * ic)
2500 {
2501   asmop *aop = newAsmop (0);
2502   regs *r;
2503   int size, offset = 0;
2504
2505   D (emitcode (";", "genXpush"));
2506
2507   aopOp (IC_LEFT (ic), ic, FALSE);
2508   r = getFreePtr (ic, &aop, FALSE);
2509
2510   size = AOP_SIZE (IC_LEFT (ic));
2511
2512   if (size == 1)
2513     {
2514       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2515       emitcode ("mov", "%s,%s", r->name, spname);
2516       emitcode ("inc", "%s", spname); // allocate space first
2517       emitcode ("movx", "@%s,a", r->name);
2518     }
2519   else
2520     {
2521       // allocate space first
2522       emitcode ("mov", "%s,%s", r->name, spname);
2523       MOVA (r->name);
2524       emitcode ("add", "a,#0x%02x", size);
2525       emitcode ("mov", "%s,a", spname);
2526
2527       while (size--)
2528         {
2529           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2530           emitcode ("movx", "@%s,a", r->name);
2531           emitcode ("inc", "%s", r->name);
2532         }
2533     }
2534
2535   freeAsmop (NULL, aop, ic, TRUE);
2536   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2537 }
2538
2539 /*-----------------------------------------------------------------*/
2540 /* genIpush - generate code for pushing this gets a little complex */
2541 /*-----------------------------------------------------------------*/
2542 static void
2543 genIpush (iCode * ic)
2544 {
2545   int size, offset = 0;
2546   char *l;
2547   char *prev = "";
2548
2549   D (emitcode (";", "genIpush"));
2550
2551   /* if this is not a parm push : ie. it is spill push
2552      and spill push is always done on the local stack */
2553   if (!ic->parmPush)
2554     {
2555
2556       /* and the item is spilt then do nothing */
2557       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2558         return;
2559
2560       aopOp (IC_LEFT (ic), ic, FALSE);
2561       size = AOP_SIZE (IC_LEFT (ic));
2562       /* push it on the stack */
2563       while (size--)
2564         {
2565           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2566           if (*l == '#')
2567             {
2568               MOVA (l);
2569               l = "acc";
2570             }
2571           emitcode ("push", "%s", l);
2572         }
2573       return;
2574     }
2575
2576   /* this is a parameter push: in this case we call
2577      the routine to find the call and save those
2578      registers that need to be saved */
2579   saveRegisters (ic);
2580
2581   /* if use external stack then call the external
2582      stack pushing routine */
2583   if (options.useXstack)
2584     {
2585       genXpush (ic);
2586       return;
2587     }
2588
2589   /* then do the push */
2590   aopOp (IC_LEFT (ic), ic, FALSE);
2591
2592   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2593   size = AOP_SIZE (IC_LEFT (ic));
2594
2595   while (size--)
2596     {
2597       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2598       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2599           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2600         {
2601           if (strcmp (l, prev) || *l == '@')
2602             MOVA (l);
2603           emitcode ("push", "acc");
2604         }
2605       else
2606         {
2607           emitcode ("push", "%s", l);
2608         }
2609       prev = l;
2610     }
2611
2612   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2613 }
2614
2615 /*-----------------------------------------------------------------*/
2616 /* genIpop - recover the registers: can happen only for spilling   */
2617 /*-----------------------------------------------------------------*/
2618 static void
2619 genIpop (iCode * ic)
2620 {
2621   int size, offset;
2622
2623   D (emitcode (";", "genIpop"));
2624
2625   /* if the temp was not pushed then */
2626   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2627     return;
2628
2629   aopOp (IC_LEFT (ic), ic, FALSE);
2630   size = AOP_SIZE (IC_LEFT (ic));
2631   offset = (size - 1);
2632   while (size--)
2633     {
2634       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2635                                      FALSE, TRUE));
2636     }
2637
2638   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2639 }
2640
2641 /*-----------------------------------------------------------------*/
2642 /* saveRBank - saves an entire register bank on the stack          */
2643 /*-----------------------------------------------------------------*/
2644 static void
2645 saveRBank (int bank, iCode * ic, bool pushPsw)
2646 {
2647   int i;
2648   int count = 8 + (pushPsw ? 1 : 0);
2649   asmop *aop = NULL;
2650   regs *r = NULL;
2651
2652   if (options.useXstack)
2653     {
2654       if (!ic)
2655         {
2656           /* Assume r0 is available for use. */
2657           r = REG_WITH_INDEX (R0_IDX);
2658         }
2659       else
2660         {
2661           aop = newAsmop (0);
2662           r = getFreePtr (ic, &aop, FALSE);
2663         }
2664       // allocate space first
2665       emitcode ("mov", "%s,%s", r->name, spname);
2666       MOVA (r->name);
2667       emitcode ("add", "a,#0x%02x", count);
2668       emitcode ("mov", "%s,a", spname);
2669     }
2670
2671   for (i = 0; i < 8; i++)
2672     {
2673       if (options.useXstack)
2674         {
2675           emitcode ("mov", "a,(%s+%d)",
2676                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2677           emitcode ("movx", "@%s,a", r->name);
2678           if (--count)
2679             emitcode ("inc", "%s", r->name);
2680         }
2681       else
2682         emitcode ("push", "(%s+%d)",
2683                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2684     }
2685
2686   if (pushPsw)
2687     {
2688       if (options.useXstack)
2689         {
2690           emitcode ("mov", "a,psw");
2691           emitcode ("movx", "@%s,a", r->name);
2692         }
2693       else
2694         {
2695           emitcode ("push", "psw");
2696         }
2697
2698       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2699     }
2700
2701   if (aop)
2702     {
2703       freeAsmop (NULL, aop, ic, TRUE);
2704     }
2705
2706   if (ic)
2707     {
2708       ic->bankSaved = 1;
2709     }
2710 }
2711
2712 /*-----------------------------------------------------------------*/
2713 /* unsaveRBank - restores the register bank from stack             */
2714 /*-----------------------------------------------------------------*/
2715 static void
2716 unsaveRBank (int bank, iCode * ic, bool popPsw)
2717 {
2718   int i;
2719   asmop *aop = NULL;
2720   regs *r = NULL;
2721
2722   if (options.useXstack)
2723     {
2724       if (!ic)
2725         {
2726           /* Assume r0 is available for use. */
2727           r = REG_WITH_INDEX (R0_IDX);;
2728         }
2729       else
2730         {
2731           aop = newAsmop (0);
2732           r = getFreePtr (ic, &aop, FALSE);
2733         }
2734       emitcode ("mov", "%s,%s", r->name, spname);
2735     }
2736
2737   if (popPsw)
2738     {
2739       if (options.useXstack)
2740         {
2741           emitcode ("dec", "%s", r->name);
2742           emitcode ("movx", "a,@%s", r->name);
2743           emitcode ("mov", "psw,a");
2744         }
2745       else
2746         {
2747           emitcode ("pop", "psw");
2748         }
2749     }
2750
2751   for (i = 7; i >= 0; i--)
2752     {
2753       if (options.useXstack)
2754         {
2755           emitcode ("dec", "%s", r->name);
2756           emitcode ("movx", "a,@%s", r->name);
2757           emitcode ("mov", "(%s+%d),a",
2758                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2759         }
2760       else
2761         {
2762           emitcode ("pop", "(%s+%d)",
2763                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2764         }
2765     }
2766
2767   if (options.useXstack)
2768     {
2769       emitcode ("mov", "%s,%s", spname, r->name);
2770     }
2771
2772   if (aop)
2773     {
2774       freeAsmop (NULL, aop, ic, TRUE);
2775     }
2776 }
2777
2778 /*-----------------------------------------------------------------*/
2779 /* genSend - gen code for SEND                                     */
2780 /*-----------------------------------------------------------------*/
2781 static void genSend(set *sendSet)
2782 {
2783   iCode *sic;
2784   int bit_count = 0;
2785
2786   /* first we do all bit parameters */
2787   for (sic = setFirstItem (sendSet); sic;
2788        sic = setNextItem (sendSet))
2789     {
2790       if (sic->argreg > 12)
2791         {
2792           int bit = sic->argreg-13;
2793
2794           aopOp (IC_LEFT (sic), sic, FALSE);
2795
2796           /* if left is a literal then
2797              we know what the value is */
2798           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2799             {
2800               if (((int) operandLitValue (IC_LEFT (sic))))
2801                   emitcode ("setb", "b[%d]", bit);
2802               else
2803                   emitcode ("clr", "b[%d]", bit);
2804             }
2805           else
2806             {
2807               /* we need to or */
2808               toCarry (IC_LEFT (sic));
2809               emitcode ("mov", "b[%d],c", bit);
2810             }
2811           bit_count++;
2812           BitBankUsed = 1;
2813
2814           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2815         }
2816     }
2817
2818   if (bit_count)
2819     {
2820       saveRegisters (setFirstItem (sendSet));
2821       emitcode ("mov", "bits,b");
2822     }
2823
2824   /* then we do all other parameters */
2825   for (sic = setFirstItem (sendSet); sic;
2826        sic = setNextItem (sendSet))
2827     {
2828       if (sic->argreg <= 12)
2829         {
2830           int size, offset = 0;
2831           aopOp (IC_LEFT (sic), sic, FALSE);
2832           size = AOP_SIZE (IC_LEFT (sic));
2833
2834           if (sic->argreg == 1)
2835             {
2836               while (size--)
2837                 {
2838                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2839                   if (strcmp (l, fReturn[offset]))
2840                     {
2841                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2842                     }
2843                   offset++;
2844                 }
2845             }
2846           else
2847             {
2848               while (size--)
2849                 {
2850                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2851                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2852                   offset++;
2853                 }
2854             }
2855           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2856         }
2857     }
2858 }
2859
2860 /*-----------------------------------------------------------------*/
2861 /* selectRegBank - emit code to select the register bank           */
2862 /*-----------------------------------------------------------------*/
2863 static void
2864 selectRegBank (short bank, bool keepFlags)
2865 {
2866   /* if f.e. result is in carry */
2867   if (keepFlags)
2868     {
2869       emitcode ("anl", "psw,#0xE7");
2870       if (bank)
2871         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2872     }
2873   else
2874     {
2875       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2876     }
2877 }
2878
2879 /*-----------------------------------------------------------------*/
2880 /* genCall - generates a call statement                            */
2881 /*-----------------------------------------------------------------*/
2882 static void
2883 genCall (iCode * ic)
2884 {
2885   sym_link *dtype;
2886   sym_link *etype;
2887 //  bool restoreBank = FALSE;
2888   bool swapBanks = FALSE;
2889   bool accuse = FALSE;
2890   bool accPushed = FALSE;
2891   bool resultInF0 = FALSE;
2892   bool assignResultGenerated = FALSE;
2893
2894   D (emitcode (";", "genCall"));
2895
2896   dtype = operandType (IC_LEFT (ic));
2897   etype = getSpec(dtype);
2898   /* if send set is not empty then assign */
2899   if (_G.sendSet)
2900     {
2901         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2902             genSend(reverseSet(_G.sendSet));
2903         } else {
2904             genSend(_G.sendSet);
2905         }
2906       _G.sendSet = NULL;
2907     }
2908
2909   /* if we are calling a not _naked function that is not using
2910      the same register bank then we need to save the
2911      destination registers on the stack */
2912   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2913       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2914        !IFFUNC_ISISR (dtype))
2915     {
2916       swapBanks = TRUE;
2917     }
2918
2919   /* if caller saves & we have not saved then */
2920   if (!ic->regsSaved)
2921       saveRegisters (ic);
2922
2923   if (swapBanks)
2924     {
2925         emitcode ("mov", "psw,#0x%02x",
2926            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2927     }
2928
2929   /* make the call */
2930   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2931     {
2932       if (IFFUNC_CALLEESAVES(dtype))
2933         {
2934           werror (E_BANKED_WITH_CALLEESAVES);
2935         }
2936       else
2937         {
2938           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2939                      OP_SYMBOL (IC_LEFT (ic))->rname :
2940                      OP_SYMBOL (IC_LEFT (ic))->name);
2941
2942           emitcode ("mov", "r0,#%s", l);
2943           emitcode ("mov", "r1,#(%s >> 8)", l);
2944           emitcode ("mov", "r2,#(%s >> 16)", l);
2945           emitcode ("lcall", "__sdcc_banked_call");
2946         }
2947     }
2948   else
2949     {
2950       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2951                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2952                                 OP_SYMBOL (IC_LEFT (ic))->name));
2953     }
2954
2955   if (swapBanks)
2956     {
2957       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2958     }
2959
2960   /* if we need assign a result value */
2961   if ((IS_ITEMP (IC_RESULT (ic)) &&
2962        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2963        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2964         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2965         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2966       IS_TRUE_SYMOP (IC_RESULT (ic)))
2967     {
2968
2969       _G.accInUse++;
2970       aopOp (IC_RESULT (ic), ic, FALSE);
2971       _G.accInUse--;
2972
2973       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2974       assignResultGenerated = TRUE;
2975
2976       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2977     }
2978
2979   /* adjust the stack for parameters if required */
2980   if (ic->parmBytes)
2981     {
2982       int i;
2983       if (ic->parmBytes > 3)
2984         {
2985           if (accuse)
2986             {
2987               emitcode ("push", "acc");
2988               accPushed = TRUE;
2989             }
2990           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2991               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2992               !assignResultGenerated)
2993             {
2994               emitcode ("mov", "F0,c");
2995               resultInF0 = TRUE;
2996             }
2997
2998           emitcode ("mov", "a,%s", spname);
2999           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3000           emitcode ("mov", "%s,a", spname);
3001
3002           /* unsaveRegisters from xstack needs acc, but */
3003           /* unsaveRegisters from stack needs this popped */
3004           if (accPushed && !options.useXstack)
3005             {
3006               emitcode ("pop", "acc");
3007               accPushed = FALSE;
3008             }
3009         }
3010       else
3011         for (i = 0; i < ic->parmBytes; i++)
3012           emitcode ("dec", "%s", spname);
3013     }
3014
3015   /* if we had saved some registers then unsave them */
3016   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3017     {
3018       if (accuse && !accPushed && options.useXstack)
3019         {
3020           /* xstack needs acc, but doesn't touch normal stack */
3021           emitcode ("push", "acc");
3022           accPushed = TRUE;
3023         }
3024       unsaveRegisters (ic);
3025     }
3026
3027 //  /* if register bank was saved then pop them */
3028 //  if (restoreBank)
3029 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3030
3031   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3032     {
3033       if (resultInF0)
3034           emitcode ("mov", "c,F0");
3035
3036       aopOp (IC_RESULT (ic), ic, FALSE);
3037       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3038       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3039     }
3040
3041   if (accPushed)
3042     emitcode ("pop", "acc");
3043 }
3044
3045 /*-----------------------------------------------------------------*/
3046 /* genPcall - generates a call by pointer statement                */
3047 /*-----------------------------------------------------------------*/
3048 static void
3049 genPcall (iCode * ic)
3050 {
3051   sym_link *dtype;
3052   sym_link *etype;
3053   symbol *rlbl = newiTempLabel (NULL);
3054 //  bool restoreBank=FALSE;
3055   bool swapBanks = FALSE;
3056   bool resultInF0 = FALSE;
3057
3058   D (emitcode (";", "genPcall"));
3059
3060   dtype = operandType (IC_LEFT (ic))->next;
3061   etype = getSpec(dtype);
3062   /* if caller saves & we have not saved then */
3063   if (!ic->regsSaved)
3064     saveRegisters (ic);
3065
3066   /* if we are calling a not _naked function that is not using
3067      the same register bank then we need to save the
3068      destination registers on the stack */
3069   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3070       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3071       !IFFUNC_ISISR (dtype))
3072     {
3073 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3074 //    restoreBank=TRUE;
3075       swapBanks = TRUE;
3076       // need caution message to user here
3077     }
3078
3079   if (IS_LITERAL (etype))
3080     {
3081       /* if send set is not empty then assign */
3082       if (_G.sendSet)
3083         {
3084           genSend(reverseSet(_G.sendSet));
3085           _G.sendSet = NULL;
3086         }
3087
3088       if (swapBanks)
3089         {
3090           emitcode ("mov", "psw,#0x%02x",
3091            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3092         }
3093
3094       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3095         {
3096           if (IFFUNC_CALLEESAVES (dtype))
3097             {
3098               werror (E_BANKED_WITH_CALLEESAVES);
3099             }
3100           else
3101             {
3102               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3103
3104               emitcode ("mov", "r0,#%s", l);
3105               emitcode ("mov", "r1,#(%s >> 8)", l);
3106               emitcode ("mov", "r2,#(%s >> 16)", l);
3107               emitcode ("lcall", "__sdcc_banked_call");
3108             }
3109         }
3110       else
3111         {
3112           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3113         }
3114     }
3115   else
3116     {
3117       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3118         {
3119           if (IFFUNC_CALLEESAVES (dtype))
3120             {
3121               werror (E_BANKED_WITH_CALLEESAVES);
3122             }
3123           else
3124             {
3125               aopOp (IC_LEFT (ic), ic, FALSE);
3126
3127               if (!swapBanks)
3128                 {
3129                   /* what if aopGet needs r0 or r1 ??? */
3130                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3131                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3132                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3133                 }
3134               else
3135                 {
3136                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3137                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3138                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3139                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3140                 }
3141
3142               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3143
3144               /* if send set is not empty then assign */
3145               if (_G.sendSet)
3146                 {
3147                   genSend(reverseSet(_G.sendSet));
3148                   _G.sendSet = NULL;
3149                 }
3150
3151               if (swapBanks)
3152                 {
3153                   emitcode ("mov", "psw,#0x%02x",
3154                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3155                 }
3156
3157               /* make the call */
3158               emitcode ("lcall", "__sdcc_banked_call");
3159             }
3160         }
3161       else if (_G.sendSet)
3162         {
3163           /* push the return address on to the stack */
3164           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3165           emitcode ("push", "acc");
3166           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3167           emitcode ("push", "acc");
3168
3169           /* now push the function address */
3170           pushSide (IC_LEFT (ic), FPTRSIZE, ic);
3171
3172           /* if send set is not empty then assign */
3173           if (_G.sendSet)
3174             {
3175               genSend(reverseSet(_G.sendSet));
3176               _G.sendSet = NULL;
3177             }
3178
3179           if (swapBanks)
3180             {
3181               emitcode ("mov", "psw,#0x%02x",
3182                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3183             }
3184
3185           /* make the call */
3186           emitcode ("ret", "");
3187           emitLabel (rlbl);
3188         }
3189       else /* the send set is empty */
3190         {
3191           char *l;
3192           /* now get the calling address into dptr */
3193           aopOp (IC_LEFT (ic), ic, FALSE);
3194
3195           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3196           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3197             {
3198               emitcode ("mov", "r0,%s", l);
3199               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3200               emitcode ("mov", "dph,%s", l);
3201               emitcode ("mov", "dpl,r0");
3202             }
3203           else
3204             {
3205               emitcode ("mov", "dpl,%s", l);
3206               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3207               emitcode ("mov", "dph,%s", l);
3208             }
3209
3210           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3211
3212           if (swapBanks)
3213             {
3214               emitcode ("mov", "psw,#0x%02x",
3215                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3216             }
3217
3218           /* make the call */
3219           emitcode ("lcall", "__sdcc_call_dptr");
3220         }
3221     }
3222   if (swapBanks)
3223     {
3224       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3225     }
3226
3227   /* if we need assign a result value */
3228   if ((IS_ITEMP (IC_RESULT (ic)) &&
3229        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3230        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3231         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3232       IS_TRUE_SYMOP (IC_RESULT (ic)))
3233     {
3234
3235       _G.accInUse++;
3236       aopOp (IC_RESULT (ic), ic, FALSE);
3237       _G.accInUse--;
3238
3239       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3240
3241       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3242     }
3243
3244   /* adjust the stack for parameters if required */
3245   if (ic->parmBytes)
3246     {
3247       int i;
3248       if (ic->parmBytes > 3)
3249         {
3250           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3251               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3252             {
3253               emitcode ("mov", "F0,c");
3254               resultInF0 = TRUE;
3255             }
3256
3257           emitcode ("mov", "a,%s", spname);
3258           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3259           emitcode ("mov", "%s,a", spname);
3260         }
3261       else
3262         for (i = 0; i < ic->parmBytes; i++)
3263           emitcode ("dec", "%s", spname);
3264     }
3265
3266 //  /* if register bank was saved then unsave them */
3267 //  if (restoreBank)
3268 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3269
3270   /* if we had saved some registers then unsave them */
3271   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3272     unsaveRegisters (ic);
3273
3274   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3275     {
3276       if (resultInF0)
3277           emitcode ("mov", "c,F0");
3278
3279       aopOp (IC_RESULT (ic), ic, FALSE);
3280       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3281       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3282     }
3283 }
3284
3285 /*-----------------------------------------------------------------*/
3286 /* resultRemat - result  is rematerializable                       */
3287 /*-----------------------------------------------------------------*/
3288 static int
3289 resultRemat (iCode * ic)
3290 {
3291   if (SKIP_IC (ic) || ic->op == IFX)
3292     return 0;
3293
3294   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3295     {
3296       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3297       if (sym->remat && !POINTER_SET (ic))
3298         return 1;
3299     }
3300
3301   return 0;
3302 }
3303
3304 /*-----------------------------------------------------------------*/
3305 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3306 /*-----------------------------------------------------------------*/
3307 static int
3308 regsCmp(void *p1, void *p2)
3309 {
3310   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3311 }
3312
3313 static bool
3314 inExcludeList (char *s)
3315 {
3316   const char *p = setFirstItem(options.excludeRegsSet);
3317
3318   if (p == NULL || STRCASECMP(p, "none") == 0)
3319     return FALSE;
3320
3321
3322   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3323 }
3324
3325 /*-----------------------------------------------------------------*/
3326 /* genFunction - generated code for function entry                 */
3327 /*-----------------------------------------------------------------*/
3328 static void
3329 genFunction (iCode * ic)
3330 {
3331   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3332   sym_link *ftype;
3333   bool     switchedPSW = FALSE;
3334   int      calleesaves_saved_register = -1;
3335   int      stackAdjust = sym->stack;
3336   int      accIsFree = sym->recvSize < 4;
3337   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3338   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3339
3340   _G.nRegsSaved = 0;
3341   /* create the function header */
3342   emitcode (";", "-----------------------------------------");
3343   emitcode (";", " function %s", sym->name);
3344   emitcode (";", "-----------------------------------------");
3345
3346   emitcode ("", "%s:", sym->rname);
3347   lineCurr->isLabel = 1;
3348   ftype = operandType (IC_LEFT (ic));
3349   _G.currentFunc = sym;
3350
3351   if (IFFUNC_ISNAKED(ftype))
3352   {
3353       emitcode(";", "naked function: no prologue.");
3354       return;
3355   }
3356
3357   /* here we need to generate the equates for the
3358      register bank if required */
3359   if (FUNC_REGBANK (ftype) != rbank)
3360     {
3361       int i;
3362
3363       rbank = FUNC_REGBANK (ftype);
3364       for (i = 0; i < mcs51_nRegs; i++)
3365         {
3366           if (regs8051[i].type != REG_BIT)
3367             {
3368               if (strcmp (regs8051[i].base, "0") == 0)
3369                 emitcode ("", "%s = 0x%02x",
3370                           regs8051[i].dname,
3371                           8 * rbank + regs8051[i].offset);
3372               else
3373                 emitcode ("", "%s = %s + 0x%02x",
3374                           regs8051[i].dname,
3375                           regs8051[i].base,
3376                           8 * rbank + regs8051[i].offset);
3377             }
3378         }
3379     }
3380
3381   /* if this is an interrupt service routine then
3382      save acc, b, dpl, dph  */
3383   if (IFFUNC_ISISR (sym->type))
3384     {
3385       bitVect *rsavebits;
3386
3387       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3388       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3389         {
3390           emitcode ("push", "bits");
3391           BitBankUsed = 1;
3392         }
3393       freeBitVect (rsavebits);
3394
3395       if (!inExcludeList ("acc"))
3396         emitcode ("push", "acc");
3397       if (!inExcludeList ("b"))
3398         emitcode ("push", "b");
3399       if (!inExcludeList ("dpl"))
3400         emitcode ("push", "dpl");
3401       if (!inExcludeList ("dph"))
3402         emitcode ("push", "dph");
3403       /* if this isr has no bank i.e. is going to
3404          run with bank 0 , then we need to save more
3405          registers :-) */
3406       if (!FUNC_REGBANK (sym->type))
3407         {
3408           int i;
3409
3410           /* if this function does not call any other
3411              function then we can be economical and
3412              save only those registers that are used */
3413           if (!IFFUNC_HASFCALL(sym->type))
3414             {
3415               /* if any registers used */
3416               if (sym->regsUsed)
3417                 {
3418                   /* save the registers used */
3419                   for (i = 0; i < sym->regsUsed->size; i++)
3420                     {
3421                       if (bitVectBitValue (sym->regsUsed, i))
3422                         pushReg (i, TRUE);
3423                     }
3424                 }
3425             }
3426           else
3427             {
3428               /* this function has a function call. We cannot
3429                  determine register usage so we will have to push the
3430                  entire bank */
3431                 saveRBank (0, ic, FALSE);
3432                 if (options.parms_in_bank1) {
3433                     for (i=0; i < 8 ; i++ ) {
3434                         emitcode ("push","%s",rb1regs[i]);
3435                     }
3436                 }
3437             }
3438         }
3439       else
3440         {
3441             /* This ISR uses a non-zero bank.
3442              *
3443              * We assume that the bank is available for our
3444              * exclusive use.
3445              *
3446              * However, if this ISR calls a function which uses some
3447              * other bank, we must save that bank entirely.
3448              */
3449             unsigned long banksToSave = 0;
3450
3451             if (IFFUNC_HASFCALL(sym->type))
3452             {
3453
3454 #define MAX_REGISTER_BANKS 4
3455
3456                 iCode *i;
3457                 int ix;
3458
3459                 for (i = ic; i; i = i->next)
3460                 {
3461                     if (i->op == ENDFUNCTION)
3462                     {
3463                         /* we got to the end OK. */
3464                         break;
3465                     }
3466
3467                     if (i->op == CALL)
3468                     {
3469                         sym_link *dtype;
3470
3471                         dtype = operandType (IC_LEFT(i));
3472                         if (dtype
3473                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3474                         {
3475                              /* Mark this bank for saving. */
3476                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3477                              {
3478                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3479                              }
3480                              else
3481                              {
3482                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3483                              }
3484
3485                              /* And note that we don't need to do it in
3486                               * genCall.
3487                               */
3488                              i->bankSaved = 1;
3489                         }
3490                     }
3491                     if (i->op == PCALL)
3492                     {
3493                         /* This is a mess; we have no idea what
3494                          * register bank the called function might
3495                          * use.
3496                          *
3497                          * The only thing I can think of to do is
3498                          * throw a warning and hope.
3499                          */
3500                         werror(W_FUNCPTR_IN_USING_ISR);
3501                     }
3502                 }
3503
3504                 if (banksToSave && options.useXstack)
3505                 {
3506                     /* Since we aren't passing it an ic,
3507                      * saveRBank will assume r0 is available to abuse.
3508                      *
3509                      * So switch to our (trashable) bank now, so
3510                      * the caller's R0 isn't trashed.
3511                      */
3512                     emitcode ("push", "psw");
3513                     emitcode ("mov", "psw,#0x%02x",
3514                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3515                     switchedPSW = TRUE;
3516                 }
3517
3518                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3519                 {
3520                      if (banksToSave & (1 << ix))
3521                      {
3522                          saveRBank(ix, NULL, FALSE);
3523                      }
3524                 }
3525             }
3526             // TODO: this needs a closer look
3527             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3528         }
3529
3530       /* Set the register bank to the desired value if nothing else */
3531       /* has done so yet. */
3532       if (!switchedPSW)
3533         {
3534           emitcode ("push", "psw");
3535           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3536         }
3537     }
3538   else
3539     {
3540       /* This is a non-ISR function. The caller has already switched register */
3541       /* banks, if necessary, so just handle the callee-saves option. */
3542
3543       /* if callee-save to be used for this function
3544          then save the registers being used in this function */
3545       if (IFFUNC_CALLEESAVES(sym->type))
3546         {
3547           int i;
3548
3549           /* if any registers used */
3550           if (sym->regsUsed)
3551             {
3552               bool bits_pushed = FALSE;
3553               /* save the registers used */
3554               for (i = 0; i < sym->regsUsed->size; i++)
3555                 {
3556                   if (bitVectBitValue (sym->regsUsed, i))
3557                     {
3558                       /* remember one saved register for later usage */
3559                       if (calleesaves_saved_register < 0)
3560                         calleesaves_saved_register = i;
3561                       bits_pushed = pushReg (i, bits_pushed);
3562                       _G.nRegsSaved++;
3563                     }
3564                 }
3565             }
3566         }
3567     }
3568
3569   if (fReentrant)
3570     {
3571       if (options.useXstack)
3572         {
3573           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3574             {
3575               emitcode ("mov", "r0,%s", spname);
3576               emitcode ("inc", "%s", spname);
3577               emitcode ("xch", "a,_bpx");
3578               emitcode ("movx", "@r0,a");
3579               emitcode ("inc", "r0");
3580               emitcode ("mov", "a,r0");
3581               emitcode ("xch", "a,_bpx");
3582             }
3583           if (sym->stack)
3584             {
3585               emitcode ("push", "_bp");     /* save the callers stack  */
3586               emitcode ("mov", "_bp,sp");
3587             }
3588         }
3589       else
3590         {
3591           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3592             {
3593               /* set up the stack */
3594               emitcode ("push", "_bp");     /* save the callers stack  */
3595               emitcode ("mov", "_bp,sp");
3596             }
3597         }
3598     }
3599
3600   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3601   /* before setting up the stack frame completely. */
3602   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3603     {
3604       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3605
3606       if (rsym->isitmp)
3607         {
3608           if (rsym && rsym->regType == REG_CND)
3609             rsym = NULL;
3610           if (rsym && (rsym->accuse || rsym->ruonly))
3611             rsym = NULL;
3612           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3613             rsym = rsym->usl.spillLoc;
3614         }
3615
3616       /* If the RECEIVE operand immediately spills to the first entry on the */
3617       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3618       /* rather than the usual @r0/r1 machinations. */
3619       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3620         {
3621           int ofs;
3622
3623           _G.current_iCode = ric;
3624           D(emitcode (";", "genReceive"));
3625           for (ofs=0; ofs < sym->recvSize; ofs++)
3626             {
3627               if (!strcmp (fReturn[ofs], "a"))
3628                 emitcode ("push", "acc");
3629               else
3630                 emitcode ("push", fReturn[ofs]);
3631             }
3632           stackAdjust -= sym->recvSize;
3633           if (stackAdjust<0)
3634             {
3635               assert (stackAdjust>=0);
3636               stackAdjust = 0;
3637             }
3638           _G.current_iCode = ic;
3639           ric->generated = 1;
3640           accIsFree = 1;
3641         }
3642       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3643       /* to free up the accumulator. */
3644       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3645         {
3646           int ofs;
3647
3648           _G.current_iCode = ric;
3649           D(emitcode (";", "genReceive"));
3650           for (ofs=0; ofs < sym->recvSize; ofs++)
3651             {
3652               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3653             }
3654           _G.current_iCode = ic;
3655           ric->generated = 1;
3656           accIsFree = 1;
3657         }
3658     }
3659
3660   /* adjust the stack for the function */
3661   if (stackAdjust)
3662     {
3663       int i = stackAdjust;
3664       if (i > 256)
3665         werror (W_STACK_OVERFLOW, sym->name);
3666
3667       if (i > 3 && accIsFree)
3668         {
3669           emitcode ("mov", "a,sp");
3670           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3671           emitcode ("mov", "sp,a");
3672         }
3673       else if (i > 5)
3674         {
3675           /* The accumulator is not free, so we will need another register */
3676           /* to clobber. No need to worry about a possible conflict with */
3677           /* the above early RECEIVE optimizations since they would have */
3678           /* freed the accumulator if they were generated. */
3679
3680           if (IFFUNC_CALLEESAVES(sym->type))
3681             {
3682               /* if it's a callee-saves function we need a saved register */
3683               if (calleesaves_saved_register >= 0)
3684                 {
3685                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3686                   emitcode ("mov", "a,sp");
3687                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3688                   emitcode ("mov", "sp,a");
3689                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3690                 }
3691               else
3692                 /* do it the hard way */
3693                 while (i--)
3694                   emitcode ("inc", "sp");
3695             }
3696           else
3697             {
3698               /* not callee-saves, we can clobber r0 */
3699               emitcode ("mov", "r0,a");
3700               emitcode ("mov", "a,sp");
3701               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3702               emitcode ("mov", "sp,a");
3703               emitcode ("mov", "a,r0");
3704             }
3705         }
3706       else
3707         while (i--)
3708           emitcode ("inc", "sp");
3709     }
3710
3711   if (sym->xstack)
3712     {
3713       char i = ((char) sym->xstack & 0xff);
3714
3715       if (i > 3 && accIsFree)
3716         {
3717           emitcode ("mov", "a,_spx");
3718           emitcode ("add", "a,#0x%02x", i & 0xff);
3719           emitcode ("mov", "_spx,a");
3720         }
3721       else if (i > 5)
3722         {
3723           emitcode ("push", "acc");
3724           emitcode ("mov", "a,_spx");
3725           emitcode ("add", "a,#0x%02x", i & 0xff);
3726           emitcode ("mov", "_spx,a");
3727           emitcode ("pop", "acc");
3728         }
3729       else
3730         {
3731           while (i--)
3732             emitcode ("inc", "_spx");
3733         }
3734     }
3735
3736   /* if critical function then turn interrupts off */
3737   if (IFFUNC_ISCRITICAL (ftype))
3738     {
3739       symbol *tlbl = newiTempLabel (NULL);
3740       emitcode ("setb", "c");
3741       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3742       emitcode ("clr", "c");
3743       emitLabel (tlbl);
3744       emitcode ("push", "psw"); /* save old ea via c in psw */
3745     }
3746 }
3747
3748 /*-----------------------------------------------------------------*/
3749 /* genEndFunction - generates epilogue for functions               */
3750 /*-----------------------------------------------------------------*/
3751 static void
3752 genEndFunction (iCode * ic)
3753 {
3754   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3755   lineNode *lnp = lineCurr;
3756   bitVect  *regsUsed;
3757   bitVect  *regsUsedPrologue;
3758   bitVect  *regsUnneeded;
3759   int      idx;
3760
3761   _G.currentFunc = NULL;
3762   if (IFFUNC_ISNAKED(sym->type))
3763   {
3764       emitcode(";", "naked function: no epilogue.");
3765       if (options.debug && currFunc)
3766         debugFile->writeEndFunction (currFunc, ic, 0);
3767       return;
3768   }
3769
3770   if (IFFUNC_ISCRITICAL (sym->type))
3771     {
3772       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3773         {
3774           emitcode ("rlc", "a");   /* save c in a */
3775           emitcode ("pop", "psw"); /* restore ea via c in psw */
3776           emitcode ("mov", "ea,c");
3777           emitcode ("rrc", "a");   /* restore c from a */
3778         }
3779       else
3780         {
3781           emitcode ("pop", "psw"); /* restore ea via c in psw */
3782           emitcode ("mov", "ea,c");
3783         }
3784     }
3785
3786   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3787     {
3788       if (options.useXstack)
3789         {
3790           if (sym->stack)
3791             {
3792               emitcode ("mov", "sp,_bp");
3793               emitcode ("pop", "_bp");
3794             }
3795           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3796             {
3797               emitcode ("xch", "a,_bpx");
3798               emitcode ("mov", "r0,a");
3799               emitcode ("dec", "r0");
3800               emitcode ("movx", "a,@r0");
3801               emitcode ("xch", "a,_bpx");
3802               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3803             }
3804         }
3805       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3806         {
3807           if (sym->stack)
3808             emitcode ("mov", "sp,_bp");
3809           emitcode ("pop", "_bp");
3810         }
3811     }
3812
3813   /* restore the register bank  */
3814   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3815   {
3816     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3817      || !options.useXstack)
3818     {
3819         /* Special case of ISR using non-zero bank with useXstack
3820          * is handled below.
3821          */
3822         emitcode ("pop", "psw");
3823     }
3824   }
3825
3826   if (IFFUNC_ISISR (sym->type))
3827     {
3828       bitVect *rsavebits;
3829
3830       /* now we need to restore the registers */
3831       /* if this isr has no bank i.e. is going to
3832          run with bank 0 , then we need to save more
3833          registers :-) */
3834       if (!FUNC_REGBANK (sym->type))
3835         {
3836           int i;
3837           /* if this function does not call any other
3838              function then we can be economical and
3839              save only those registers that are used */
3840           if (!IFFUNC_HASFCALL(sym->type))
3841             {
3842               /* if any registers used */
3843               if (sym->regsUsed)
3844                 {
3845                   /* save the registers used */
3846                   for (i = sym->regsUsed->size; i >= 0; i--)
3847                     {
3848                       if (bitVectBitValue (sym->regsUsed, i))
3849                         popReg (i, TRUE);
3850                     }
3851                 }
3852             }
3853           else
3854             {
3855               if (options.parms_in_bank1) {
3856                   for (i = 7 ; i >= 0 ; i-- ) {
3857                       emitcode ("pop","%s",rb1regs[i]);
3858                   }
3859               }
3860               /* this function has a function call. We cannot
3861                  determine register usage so we will have to pop the
3862                  entire bank */
3863               unsaveRBank (0, ic, FALSE);
3864             }
3865         }
3866         else
3867         {
3868             /* This ISR uses a non-zero bank.
3869              *
3870              * Restore any register banks saved by genFunction
3871              * in reverse order.
3872              */
3873             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3874             int ix;
3875
3876             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3877             {
3878                 if (savedBanks & (1 << ix))
3879                 {
3880                     unsaveRBank(ix, NULL, FALSE);
3881                 }
3882             }
3883
3884             if (options.useXstack)
3885             {
3886                 /* Restore bank AFTER calling unsaveRBank,
3887                  * since it can trash r0.
3888                  */
3889                 emitcode ("pop", "psw");
3890             }
3891         }
3892
3893       if (!inExcludeList ("dph"))
3894         emitcode ("pop", "dph");
3895       if (!inExcludeList ("dpl"))
3896         emitcode ("pop", "dpl");
3897       if (!inExcludeList ("b"))
3898         emitcode ("pop", "b");
3899       if (!inExcludeList ("acc"))
3900         emitcode ("pop", "acc");
3901
3902       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3903       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3904         emitcode ("pop", "bits");
3905       freeBitVect (rsavebits);
3906
3907       /* if debug then send end of function */
3908       if (options.debug && currFunc)
3909         {
3910           debugFile->writeEndFunction (currFunc, ic, 1);
3911         }
3912
3913       emitcode ("reti", "");
3914     }
3915   else
3916     {
3917       if (IFFUNC_CALLEESAVES(sym->type))
3918         {
3919           int i;
3920
3921           /* if any registers used */
3922           if (sym->regsUsed)
3923             {
3924               /* save the registers used */
3925               for (i = sym->regsUsed->size; i >= 0; i--)
3926                 {
3927                   if (bitVectBitValue (sym->regsUsed, i) ||
3928                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3929                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3930                 }
3931             }
3932           else if (mcs51_ptrRegReq)
3933             {
3934               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3935               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3936             }
3937
3938         }
3939
3940       /* if debug then send end of function */
3941       if (options.debug && currFunc)
3942         {
3943           debugFile->writeEndFunction (currFunc, ic, 1);
3944         }
3945
3946       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3947         {
3948           emitcode ("ljmp", "__sdcc_banked_ret");
3949         }
3950       else
3951         {
3952           emitcode ("ret", "");
3953         }
3954     }
3955
3956   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3957     return;
3958
3959   /* If this was an interrupt handler using bank 0 that called another */
3960   /* function, then all registers must be saved; nothing to optimized. */
3961   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3962       && !FUNC_REGBANK(sym->type))
3963     return;
3964
3965   /* There are no push/pops to optimize if not callee-saves or ISR */
3966   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3967     return;
3968
3969   /* If there were stack parameters, we cannot optimize without also    */
3970   /* fixing all of the stack offsets; this is too dificult to consider. */
3971   if (FUNC_HASSTACKPARM(sym->type))
3972     return;
3973
3974   /* Compute the registers actually used */
3975   regsUsed = newBitVect (mcs51_nRegs);
3976   regsUsedPrologue = newBitVect (mcs51_nRegs);
3977   while (lnp)
3978     {
3979       if (lnp->ic && lnp->ic->op == FUNCTION)
3980         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3981       else
3982         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3983
3984       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3985           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3986         break;
3987       if (!lnp->prev)
3988         break;
3989       lnp = lnp->prev;
3990     }
3991
3992   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3993       && !bitVectBitValue (regsUsed, CND_IDX))
3994     {
3995       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3996       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3997           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3998         bitVectUnSetBit (regsUsed, CND_IDX);
3999     }
4000   else
4001     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4002
4003   /* If this was an interrupt handler that called another function */
4004   /* function, then assume A, B, DPH, & DPL may be modified by it. */
4005   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4006     {
4007       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4008       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4009       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4010       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4011       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4012     }
4013
4014   /* Remove the unneeded push/pops */
4015   regsUnneeded = newBitVect (mcs51_nRegs);
4016   while (lnp)
4017     {
4018       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4019         {
4020           if (!strncmp(lnp->line, "push", 4))
4021             {
4022               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4023               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4024                 {
4025                   connectLine (lnp->prev, lnp->next);
4026                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4027                 }
4028             }
4029           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4030             {
4031               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4032               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4033                 {
4034                   connectLine (lnp->prev, lnp->next);
4035                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4036                 }
4037             }
4038         }
4039       lnp = lnp->next;
4040     }
4041
4042   for (idx = 0; idx < regsUnneeded->size; idx++)
4043     if (bitVectBitValue (regsUnneeded, idx))
4044       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4045
4046   freeBitVect (regsUnneeded);
4047   freeBitVect (regsUsed);
4048   freeBitVect (regsUsedPrologue);
4049 }
4050
4051 /*-----------------------------------------------------------------*/
4052 /* genRet - generate code for return statement                     */
4053 /*-----------------------------------------------------------------*/
4054 static void
4055 genRet (iCode * ic)
4056 {
4057   int size, offset = 0, pushed = 0;
4058
4059   D (emitcode (";", "genRet"));
4060
4061   /* if we have no return value then
4062      just generate the "ret" */
4063   if (!IC_LEFT (ic))
4064     goto jumpret;
4065
4066   /* we have something to return then
4067      move the return value into place */
4068   aopOp (IC_LEFT (ic), ic, FALSE);
4069   size = AOP_SIZE (IC_LEFT (ic));
4070
4071   if (IS_BIT(_G.currentFunc->etype))
4072     {
4073       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4074         toCarry (IC_LEFT (ic));
4075     }
4076   else
4077     {
4078       while (size--)
4079         {
4080           char *l;
4081           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4082             {
4083               /* #NOCHANGE */
4084               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4085               emitcode ("push", "%s", l);
4086               pushed++;
4087             }
4088           else
4089             {
4090               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4091               if (strcmp (fReturn[offset], l))
4092                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4093             }
4094         }
4095
4096       while (pushed)
4097         {
4098           pushed--;
4099           if (strcmp (fReturn[pushed], "a"))
4100             emitcode ("pop", fReturn[pushed]);
4101           else
4102             emitcode ("pop", "acc");
4103         }
4104     }
4105   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4106
4107 jumpret:
4108   /* generate a jump to the return label
4109      if the next is not the return statement */
4110   if (!(ic->next && ic->next->op == LABEL &&
4111         IC_LABEL (ic->next) == returnLabel))
4112
4113     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4114
4115 }
4116
4117 /*-----------------------------------------------------------------*/
4118 /* genLabel - generates a label                                    */
4119 /*-----------------------------------------------------------------*/
4120 static void
4121 genLabel (iCode * ic)
4122 {
4123   /* special case never generate */
4124   if (IC_LABEL (ic) == entryLabel)
4125     return;
4126
4127   emitLabel (IC_LABEL (ic));
4128 }
4129
4130 /*-----------------------------------------------------------------*/
4131 /* genGoto - generates a ljmp                                      */
4132 /*-----------------------------------------------------------------*/
4133 static void
4134 genGoto (iCode * ic)
4135 {
4136   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4137 }
4138
4139 /*-----------------------------------------------------------------*/
4140 /* findLabelBackwards: walks back through the iCode chain looking  */
4141 /* for the given label. Returns number of iCode instructions     */
4142 /* between that label and given ic.          */
4143 /* Returns zero if label not found.          */
4144 /*-----------------------------------------------------------------*/
4145 static int
4146 findLabelBackwards (iCode * ic, int key)
4147 {
4148   int count = 0;
4149
4150   while (ic->prev)
4151     {
4152       ic = ic->prev;
4153       count++;
4154
4155       /* If we have any pushes or pops, we cannot predict the distance.
4156          I don't like this at all, this should be dealt with in the
4157          back-end */
4158       if (ic->op == IPUSH || ic->op == IPOP) {
4159         return 0;
4160       }
4161
4162       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4163         {
4164           return count;
4165         }
4166     }
4167
4168   return 0;
4169 }
4170
4171 /*-----------------------------------------------------------------*/
4172 /* genPlusIncr :- does addition with increment if possible         */
4173 /*-----------------------------------------------------------------*/
4174 static bool
4175 genPlusIncr (iCode * ic)
4176 {
4177   unsigned int icount;
4178   unsigned int size = getDataSize (IC_RESULT (ic));
4179
4180   /* will try to generate an increment */
4181   /* if the right side is not a literal
4182      we cannot */
4183   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4184     return FALSE;
4185
4186   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4187
4188   D(emitcode (";","genPlusIncr"));
4189
4190   /* if increment >=16 bits in register or direct space */
4191   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4192         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4193         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4194       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4195       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4196       (size > 1) &&
4197       (icount == 1))
4198     {
4199       symbol *tlbl;
4200       int emitTlbl;
4201       int labelRange;
4202
4203       /* If the next instruction is a goto and the goto target
4204        * is < 10 instructions previous to this, we can generate
4205        * jumps straight to that target.
4206        */
4207       if (ic->next && ic->next->op == GOTO
4208           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4209           && labelRange <= 10)
4210         {
4211           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4212           tlbl = IC_LABEL (ic->next);
4213           emitTlbl = 0;
4214         }
4215       else
4216         {
4217           tlbl = newiTempLabel (NULL);
4218           emitTlbl = 1;
4219         }
4220       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4221       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4222           IS_AOP_PREG (IC_RESULT (ic)))
4223         emitcode ("cjne", "%s,#0x00,%05d$",
4224                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4225                   tlbl->key + 100);
4226       else
4227         {
4228           emitcode ("clr", "a");
4229           emitcode ("cjne", "a,%s,%05d$",
4230                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4231                     tlbl->key + 100);
4232         }
4233
4234       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4235       if (size > 2)
4236         {
4237           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4238               IS_AOP_PREG (IC_RESULT (ic)))
4239             emitcode ("cjne", "%s,#0x00,%05d$",
4240                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4241                       tlbl->key + 100);
4242           else
4243             emitcode ("cjne", "a,%s,%05d$",
4244                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4245                       tlbl->key + 100);
4246
4247           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4248         }
4249       if (size > 3)
4250         {
4251           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4252               IS_AOP_PREG (IC_RESULT (ic)))
4253             emitcode ("cjne", "%s,#0x00,%05d$",
4254                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4255                       tlbl->key + 100);
4256           else
4257             {
4258               emitcode ("cjne", "a,%s,%05d$",
4259                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4260                         tlbl->key + 100);
4261             }
4262           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4263         }
4264
4265       if (emitTlbl)
4266         {
4267           emitLabel (tlbl);
4268         }
4269       return TRUE;
4270     }
4271
4272   /* if result is dptr */
4273   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4274       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4275       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4276       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4277     {
4278       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4279         return FALSE;
4280
4281       if (icount > 9)
4282         return FALSE;
4283
4284       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4285         return FALSE;
4286
4287       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4288       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4289       while (icount--)
4290         emitcode ("inc", "dptr");
4291
4292       return TRUE;
4293     }
4294
4295   /* if the literal value of the right hand side
4296      is greater than 4 then it is not worth it */
4297   if (icount > 4)
4298     return FALSE;
4299
4300   /* if the sizes are greater than 1 then we cannot */
4301   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4302       AOP_SIZE (IC_LEFT (ic)) > 1)
4303     return FALSE;
4304
4305   /* we can if the aops of the left & result match or
4306      if they are in registers and the registers are the
4307      same */
4308   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4309     {
4310       if (icount > 3)
4311         {
4312           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4313           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4314           aopPut (IC_RESULT (ic), "a", 0);
4315         }
4316       else
4317         {
4318           while (icount--)
4319             {
4320               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4321             }
4322         }
4323
4324       return TRUE;
4325     }
4326
4327   if (icount == 1)
4328     {
4329       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4330       emitcode ("inc", "a");
4331       aopPut (IC_RESULT (ic), "a", 0);
4332       return TRUE;
4333     }
4334
4335   return FALSE;
4336 }
4337
4338 /*-----------------------------------------------------------------*/
4339 /* outBitAcc - output a bit in acc                                 */
4340 /*-----------------------------------------------------------------*/
4341 static void
4342 outBitAcc (operand * result)
4343 {
4344   symbol *tlbl = newiTempLabel (NULL);
4345   /* if the result is a bit */
4346   if (AOP_TYPE (result) == AOP_CRY)
4347     {
4348       aopPut (result, "a", 0);
4349     }
4350   else
4351     {
4352       emitcode ("jz", "%05d$", tlbl->key + 100);
4353       emitcode ("mov", "a,%s", one);
4354       emitLabel (tlbl);
4355       outAcc (result);
4356     }
4357 }
4358
4359 /*-----------------------------------------------------------------*/
4360 /* genPlusBits - generates code for addition of two bits           */
4361 /*-----------------------------------------------------------------*/
4362 static void
4363 genPlusBits (iCode * ic)
4364 {
4365   D (emitcode (";", "genPlusBits"));
4366
4367   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4368   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4369     {
4370       symbol *lbl = newiTempLabel (NULL);
4371       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4372       emitcode ("cpl", "c");
4373       emitLabel (lbl);
4374       outBitC (IC_RESULT (ic));
4375     }
4376   else
4377     {
4378       emitcode ("clr", "a");
4379       emitcode ("rlc", "a");
4380       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4381       emitcode ("addc", "a,%s", zero);
4382       outAcc (IC_RESULT (ic));
4383     }
4384 }
4385
4386 #if 0
4387 /* This is the original version of this code.
4388
4389  * This is being kept around for reference,
4390  * because I am not entirely sure I got it right...
4391  */
4392 static void
4393 adjustArithmeticResult (iCode * ic)
4394 {
4395   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4396       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4397       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4398     aopPut (IC_RESULT (ic),
4399             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4400             2);
4401
4402   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4403       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4404       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4405     aopPut (IC_RESULT (ic),
4406             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4407             2);
4408
4409   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4410       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4411       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4412       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4413       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4414     {
4415       char buffer[5];
4416       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4417       aopPut (IC_RESULT (ic), buffer, 2);
4418     }
4419 }
4420 #else
4421 /* This is the pure and virtuous version of this code.
4422  * I'm pretty certain it's right, but not enough to toss the old
4423  * code just yet...
4424  */
4425 static void
4426 adjustArithmeticResult (iCode * ic)
4427 {
4428   if (opIsGptr (IC_RESULT (ic)))
4429     {
4430       char buffer[10];
4431
4432       if (opIsGptr (IC_LEFT (ic)))
4433         {
4434           if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4435             {
4436               aopPut (IC_RESULT (ic),
4437                       aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4438                       GPTRSIZE - 1);
4439             }
4440           return;
4441         }
4442
4443       if (opIsGptr (IC_RIGHT (ic)))
4444         {
4445           if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4446             {
4447               aopPut (IC_RESULT (ic),
4448                       aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4449                       GPTRSIZE - 1);
4450             }
4451           return;
4452         }
4453
4454       if (IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4455           IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4456           !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4457           !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4458         {
4459           SNPRINTF (buffer, sizeof(buffer),
4460                     "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4461           aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4462           return;
4463         }
4464       if (IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4465           !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4466         {
4467           SNPRINTF (buffer, sizeof(buffer),
4468                     "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4469           aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4470           return;
4471         }
4472       if (IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4473           !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4474         {
4475           SNPRINTF (buffer, sizeof(buffer),
4476                     "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_RIGHT (ic)))), NULL, NULL));
4477           aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4478           return;
4479         }
4480     }
4481 }
4482 #endif
4483
4484 /*-----------------------------------------------------------------*/
4485 /* genPlus - generates code for addition                           */
4486 /*-----------------------------------------------------------------*/
4487 static void
4488 genPlus (iCode * ic)
4489 {
4490   int size, offset = 0;
4491   int skip_bytes = 0;
4492   char *add = "add";
4493   bool swappedLR = FALSE;
4494   operand *leftOp, *rightOp;
4495   operand * op;
4496
4497   D (emitcode (";", "genPlus"));
4498
4499   /* special cases :- */
4500
4501   aopOp (IC_LEFT (ic), ic, FALSE);
4502   aopOp (IC_RIGHT (ic), ic, FALSE);
4503   aopOp (IC_RESULT (ic), ic, TRUE);
4504
4505   /* if literal, literal on the right or
4506      if left requires ACC or right is already
4507      in ACC */
4508   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4509       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4510       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4511     {
4512       operand *t = IC_RIGHT (ic);
4513       IC_RIGHT (ic) = IC_LEFT (ic);
4514       IC_LEFT (ic) = t;
4515       swappedLR = TRUE;
4516     }
4517
4518   /* if both left & right are in bit
4519      space */
4520   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4521       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4522     {
4523       genPlusBits (ic);
4524       goto release;
4525     }
4526
4527   /* if left in bit space & right literal */
4528   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4529       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4530     {
4531       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4532       /* if result in bit space */
4533       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4534         {
4535           if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4536             emitcode ("cpl", "c");
4537           outBitC (IC_RESULT (ic));
4538         }
4539       else
4540         {
4541           size = getDataSize (IC_RESULT (ic));
4542           while (size--)
4543             {
4544               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4545               emitcode ("addc", "a,%s", zero);
4546               aopPut (IC_RESULT (ic), "a", offset++);
4547             }
4548         }
4549       goto release;
4550     }
4551
4552   /* if I can do an increment instead
4553      of add then GOOD for ME */
4554   if (genPlusIncr (ic) == TRUE)
4555     goto release;
4556
4557   size = getDataSize (IC_RESULT (ic));
4558   leftOp = IC_LEFT(ic);
4559   rightOp = IC_RIGHT(ic);
4560   op = IC_LEFT(ic);
4561
4562   /* if this is an add for an array access
4563      at a 256 byte boundary */
4564   if ( 2 == size
4565        && AOP_TYPE (op) == AOP_IMMD
4566        && IS_SYMOP (op)
4567        && IS_SPEC (OP_SYM_ETYPE (op))
4568        && SPEC_ABSA (OP_SYM_ETYPE (op))
4569        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4570      )
4571     {
4572       D(emitcode (";", "genPlus aligned array"));
4573       aopPut (IC_RESULT (ic),
4574               aopGet (rightOp, 0, FALSE, FALSE),
4575               0);
4576
4577       if( 1 == getDataSize (IC_RIGHT (ic)) )
4578         {
4579           aopPut (IC_RESULT (ic),
4580                   aopGet (leftOp, 1, FALSE, FALSE),
4581                   1);
4582         }
4583       else
4584         {
4585           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4586           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4587           aopPut (IC_RESULT (ic), "a", 1);
4588         }
4589       goto release;
4590     }
4591
4592   /* if the lower bytes of a literal are zero skip the addition */
4593   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4594     {
4595        while ((0 == ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4596               (skip_bytes+1 < size))
4597          {
4598            skip_bytes++;
4599          }
4600        if (skip_bytes)
4601          D(emitcode (";", "genPlus shortcut"));
4602     }
4603
4604   while (size--)
4605     {
4606       if( offset >= skip_bytes )
4607         {
4608           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4609             {
4610               bool pushedB;
4611               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4612               pushedB = pushB ();
4613               emitcode("xch", "a,b");
4614               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4615               emitcode (add, "a,b");
4616               popB (pushedB);
4617             }
4618           else if (aopGetUsesAcc (leftOp, offset))
4619             {
4620               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4621               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4622             }
4623           else
4624             {
4625               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4626               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4627             }
4628           aopPut (IC_RESULT (ic), "a", offset);
4629           add = "addc";  /* further adds must propagate carry */
4630         }
4631       else
4632         {
4633           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4634               isOperandVolatile (IC_RESULT (ic), FALSE))
4635             {
4636               /* just move */
4637               aopPut (IC_RESULT (ic),
4638                       aopGet (leftOp, offset, FALSE, FALSE),
4639                       offset);
4640             }
4641         }
4642       offset++;
4643     }
4644
4645   adjustArithmeticResult (ic);
4646
4647 release:
4648   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4649   if (!swappedLR)
4650     {
4651       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4652       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4653     }
4654   else
4655     {
4656       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4657       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4658     }
4659 }
4660
4661 /*-----------------------------------------------------------------*/
4662 /* genMinusDec :- does subtraction with decrement if possible      */
4663 /*-----------------------------------------------------------------*/
4664 static bool
4665 genMinusDec (iCode * ic)
4666 {
4667   unsigned int icount;
4668   unsigned int size = getDataSize (IC_RESULT (ic));
4669
4670   /* will try to generate an increment */
4671   /* if the right side is not a literal
4672      we cannot */
4673   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4674     return FALSE;
4675
4676   /* if the literal value of the right hand side
4677      is greater than 4 then it is not worth it */
4678   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4679     return FALSE;
4680
4681   D (emitcode (";", "genMinusDec"));
4682
4683   /* if decrement >=16 bits in register or direct space */
4684   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4685         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4686         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4687       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4688       (size > 1) &&
4689       (icount == 1))
4690     {
4691       symbol *tlbl;
4692       int emitTlbl;
4693       int labelRange;
4694
4695       /* If the next instruction is a goto and the goto target
4696        * is <= 10 instructions previous to this, we can generate
4697        * jumps straight to that target.
4698        */
4699       if (ic->next && ic->next->op == GOTO
4700           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4701           && labelRange <= 10)
4702         {
4703           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4704           tlbl = IC_LABEL (ic->next);
4705           emitTlbl = 0;
4706         }
4707       else
4708         {
4709           tlbl = newiTempLabel (NULL);
4710           emitTlbl = 1;
4711         }
4712
4713       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4714       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4715           IS_AOP_PREG (IC_RESULT (ic)))
4716         emitcode ("cjne", "%s,#0xff,%05d$"
4717                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4718                   ,tlbl->key + 100);
4719       else
4720         {
4721           emitcode ("mov", "a,#0xff");
4722           emitcode ("cjne", "a,%s,%05d$"
4723                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4724                     ,tlbl->key + 100);
4725         }
4726       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4727       if (size > 2)
4728         {
4729           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4730               IS_AOP_PREG (IC_RESULT (ic)))
4731             emitcode ("cjne", "%s,#0xff,%05d$"
4732                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4733                       ,tlbl->key + 100);
4734           else
4735             {
4736               emitcode ("cjne", "a,%s,%05d$"
4737                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4738                         ,tlbl->key + 100);
4739             }
4740           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4741         }
4742       if (size > 3)
4743         {
4744           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4745               IS_AOP_PREG (IC_RESULT (ic)))
4746             emitcode ("cjne", "%s,#0xff,%05d$"
4747                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4748                       ,tlbl->key + 100);
4749           else
4750             {
4751               emitcode ("cjne", "a,%s,%05d$"
4752                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4753                         ,tlbl->key + 100);
4754             }
4755           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4756         }
4757       if (emitTlbl)
4758         {
4759           emitLabel (tlbl);
4760         }
4761       return TRUE;
4762     }
4763
4764   /* if the sizes are greater than 1 then we cannot */
4765   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4766       AOP_SIZE (IC_LEFT (ic)) > 1)
4767     return FALSE;
4768
4769   /* we can if the aops of the left & result match or
4770      if they are in registers and the registers are the
4771      same */
4772   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4773     {
4774       char *l;
4775
4776       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4777         {
4778           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4779           l = "a";
4780         }
4781       else
4782         {
4783           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4784         }
4785
4786       while (icount--)
4787         {
4788           emitcode ("dec", "%s", l);
4789         }
4790
4791       if (AOP_NEEDSACC (IC_RESULT (ic)))
4792         aopPut (IC_RESULT (ic), "a", 0);
4793
4794       return TRUE;
4795     }
4796
4797   if (icount == 1)
4798     {
4799       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4800       emitcode ("dec", "a");
4801       aopPut (IC_RESULT (ic), "a", 0);
4802       return TRUE;
4803     }
4804
4805   return FALSE;
4806 }
4807
4808 /*-----------------------------------------------------------------*/
4809 /* addSign - complete with sign                                    */
4810 /*-----------------------------------------------------------------*/
4811 static void
4812 addSign (operand * result, int offset, int sign)
4813 {
4814   int size = (getDataSize (result) - offset);
4815   if (size > 0)
4816     {
4817       if (sign)
4818         {
4819           emitcode ("rlc", "a");
4820           emitcode ("subb", "a,acc");
4821           while (size--)
4822             {
4823               aopPut (result, "a", offset++);
4824             }
4825         }
4826       else
4827         {
4828           while (size--)
4829             {
4830               aopPut (result, zero, offset++);
4831             }
4832         }
4833     }
4834 }
4835
4836 /*-----------------------------------------------------------------*/
4837 /* genMinusBits - generates code for subtraction  of two bits      */
4838 /*-----------------------------------------------------------------*/
4839 static void
4840 genMinusBits (iCode * ic)
4841 {
4842   symbol *lbl = newiTempLabel (NULL);
4843
4844   D (emitcode (";", "genMinusBits"));
4845
4846   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4847     {
4848       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4849       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4850       emitcode ("cpl", "c");
4851       emitLabel (lbl);
4852       outBitC (IC_RESULT (ic));
4853     }
4854   else
4855     {
4856       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4857       emitcode ("subb", "a,acc");
4858       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4859       emitcode ("inc", "a");
4860       emitLabel (lbl);
4861       aopPut (IC_RESULT (ic), "a", 0);
4862       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4863     }
4864 }
4865
4866 /*-----------------------------------------------------------------*/
4867 /* genMinus - generates code for subtraction                       */
4868 /*-----------------------------------------------------------------*/
4869 static void
4870 genMinus (iCode * ic)
4871 {
4872   int size, offset = 0;
4873
4874   D (emitcode (";", "genMinus"));
4875
4876   aopOp (IC_LEFT (ic), ic, FALSE);
4877   aopOp (IC_RIGHT (ic), ic, FALSE);
4878   aopOp (IC_RESULT (ic), ic, TRUE);
4879
4880   /* special cases :- */
4881   /* if both left & right are in bit space */
4882   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4883       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4884     {
4885       genMinusBits (ic);
4886       goto release;
4887     }
4888
4889   /* if I can do an decrement instead
4890      of subtract then GOOD for ME */
4891   if (genMinusDec (ic) == TRUE)
4892     goto release;
4893
4894   size = getDataSize (IC_RESULT (ic));
4895
4896   /* if literal, add a,#-lit, else normal subb */
4897   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4898     {
4899       unsigned long lit = 0L;
4900       bool useCarry = FALSE;
4901
4902       lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4903       lit = -(long) lit;
4904
4905       while (size--)
4906         {
4907           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4908             {
4909               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4910               if (!offset && !size && lit== (unsigned long) -1)
4911                 {
4912                   emitcode ("dec", "a");
4913                 }
4914               else if (!useCarry)
4915                 {
4916                   /* first add without previous c */
4917                   emitcode ("add", "a,#0x%02x",
4918                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4919                   useCarry = TRUE;
4920                 }
4921               else
4922                 {
4923                   emitcode ("addc", "a,#0x%02x",
4924                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4925                 }
4926               aopPut (IC_RESULT (ic), "a", offset++);
4927             }
4928           else
4929             {
4930               /* no need to add zeroes */
4931               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4932                 {
4933                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4934                           offset);
4935                 }
4936               offset++;
4937             }
4938         }
4939     }
4940   else
4941     {
4942       operand *leftOp, *rightOp;
4943
4944       leftOp = IC_LEFT(ic);
4945       rightOp = IC_RIGHT(ic);
4946
4947       while (size--)
4948         {
4949           if (aopGetUsesAcc(rightOp, offset)) {
4950             if (aopGetUsesAcc(leftOp, offset)) {
4951               bool pushedB;
4952
4953               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4954               pushedB = pushB ();
4955               emitcode ("mov", "b,a");
4956               if (offset == 0)
4957                 CLRC;
4958               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4959               emitcode ("subb", "a,b");
4960               popB (pushedB);
4961             } else {
4962               /* reverse subtraction with 2's complement */
4963               if (offset == 0)
4964                 emitcode( "setb", "c");
4965               else
4966                 emitcode( "cpl", "c");
4967               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4968               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4969               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4970               emitcode("cpl", "a");
4971               if (size) /* skip if last byte */
4972                 emitcode( "cpl", "c");
4973             }
4974           } else {
4975             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4976             if (offset == 0)
4977               CLRC;
4978             emitcode ("subb", "a,%s",
4979                       aopGet(rightOp, offset, FALSE, TRUE));
4980           }
4981
4982           aopPut (IC_RESULT (ic), "a", offset++);
4983         }
4984     }
4985
4986   adjustArithmeticResult (ic);
4987
4988 release:
4989   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4990   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4991   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4992 }
4993
4994
4995 /*-----------------------------------------------------------------*/
4996 /* genMultbits :- multiplication of bits                           */
4997 /*-----------------------------------------------------------------*/
4998 static void
4999 genMultbits (operand * left,
5000              operand * right,
5001              operand * result)
5002 {
5003   D (emitcode (";", "genMultbits"));
5004
5005   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5006   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5007   outBitC (result);
5008 }
5009
5010 /*-----------------------------------------------------------------*/
5011 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5012 /*-----------------------------------------------------------------*/
5013 static void
5014 genMultOneByte (operand * left,
5015                 operand * right,
5016                 operand * result)
5017 {
5018   symbol *lbl;
5019   int size = AOP_SIZE (result);
5020   bool runtimeSign, compiletimeSign;
5021   bool lUnsigned, rUnsigned, pushedB;
5022
5023   D (emitcode (";", "genMultOneByte"));
5024
5025   if (size < 1 || size > 2)
5026     {
5027       /* this should never happen */
5028       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5029                AOP_SIZE(result), __FILE__, lineno);
5030       exit (1);
5031     }
5032
5033   /* (if two literals: the value is computed before) */
5034   /* if one literal, literal on the right */
5035   if (AOP_TYPE (left) == AOP_LIT)
5036     {
5037       operand *t = right;
5038       right = left;
5039       left = t;
5040       /* emitcode (";", "swapped left and right"); */
5041     }
5042   /* if no literal, unsigned on the right: shorter code */
5043   if (   AOP_TYPE (right) != AOP_LIT
5044       && SPEC_USIGN (getSpec (operandType (left))))
5045     {
5046       operand *t = right;
5047       right = left;
5048       left = t;
5049     }
5050
5051   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5052   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5053
5054   pushedB = pushB ();
5055
5056   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5057                    no need to take care about the signedness! */
5058       || (lUnsigned && rUnsigned))
5059     {
5060       /* just an unsigned 8 * 8 = 8 multiply
5061          or 8u * 8u = 16u */
5062       /* emitcode (";","unsigned"); */
5063       /* TODO: check for accumulator clash between left & right aops? */
5064
5065       if (AOP_TYPE (right) == AOP_LIT)
5066         {
5067           /* moving to accumulator first helps peepholes */
5068           MOVA (aopGet (left, 0, FALSE, FALSE));
5069           MOVB (aopGet (right, 0, FALSE, FALSE));
5070         }
5071       else
5072         {
5073           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5074           MOVA (aopGet (left, 0, FALSE, FALSE));
5075         }
5076
5077       emitcode ("mul", "ab");
5078       aopPut (result, "a", 0);
5079       if (size == 2)
5080         aopPut (result, "b", 1);
5081
5082       popB (pushedB);
5083       return;
5084     }
5085
5086   /* we have to do a signed multiply */
5087   /* emitcode (";", "signed"); */
5088
5089   /* now sign adjust for both left & right */
5090
5091   /* let's see what's needed: */
5092   /* apply negative sign during runtime */
5093   runtimeSign = FALSE;
5094   /* negative sign from literals */
5095   compiletimeSign = FALSE;
5096
5097   if (!lUnsigned)
5098     {
5099       if (AOP_TYPE(left) == AOP_LIT)
5100         {
5101           /* signed literal */
5102           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5103           if (val < 0)
5104             compiletimeSign = TRUE;
5105         }
5106       else
5107         /* signed but not literal */
5108         runtimeSign = TRUE;
5109     }
5110
5111   if (!rUnsigned)
5112     {
5113       if (AOP_TYPE(right) == AOP_LIT)
5114         {
5115           /* signed literal */
5116           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5117           if (val < 0)
5118             compiletimeSign ^= TRUE;
5119         }
5120       else
5121         /* signed but not literal */
5122         runtimeSign = TRUE;
5123     }
5124
5125   /* initialize F0, which stores the runtime sign */
5126   if (runtimeSign)
5127     {
5128       if (compiletimeSign)
5129         emitcode ("setb", "F0"); /* set sign flag */
5130       else
5131         emitcode ("clr", "F0"); /* reset sign flag */
5132     }
5133
5134   /* save the signs of the operands */
5135   if (AOP_TYPE(right) == AOP_LIT)
5136     {
5137       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5138
5139       if (!rUnsigned && val < 0)
5140         emitcode ("mov", "b,#0x%02x", -val);
5141       else
5142         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5143     }
5144   else /* ! literal */
5145     {
5146       if (rUnsigned)  /* emitcode (";", "signed"); */
5147         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5148       else
5149         {
5150           MOVA (aopGet (right, 0, FALSE, FALSE));
5151           lbl = newiTempLabel (NULL);
5152           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5153           emitcode ("cpl", "F0"); /* complement sign flag */
5154           emitcode ("cpl", "a");  /* 2's complement */
5155           emitcode ("inc", "a");
5156           emitLabel (lbl);
5157           emitcode ("mov", "b,a");
5158         }
5159     }
5160
5161   if (AOP_TYPE(left) == AOP_LIT)
5162     {
5163       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5164
5165       if (!lUnsigned && val < 0)
5166         emitcode ("mov", "a,#0x%02x", -val);
5167       else
5168         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5169     }
5170   else /* ! literal */
5171     {
5172       MOVA (aopGet (left, 0, FALSE, FALSE));
5173
5174       if (!lUnsigned)
5175         {
5176           lbl = newiTempLabel (NULL);
5177           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5178           emitcode ("cpl", "F0"); /* complement sign flag */
5179           emitcode ("cpl", "a"); /* 2's complement */
5180           emitcode ("inc", "a");
5181           emitLabel (lbl);
5182         }
5183     }
5184
5185   /* now the multiplication */
5186   emitcode ("mul", "ab");
5187   if (runtimeSign || compiletimeSign)
5188     {
5189       lbl = newiTempLabel (NULL);
5190       if (runtimeSign)
5191         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5192       emitcode ("cpl", "a"); /* lsb 2's complement */
5193       if (size != 2)
5194         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5195       else
5196         {
5197           emitcode ("add", "a,#0x01"); /* this sets carry flag */
5198           emitcode ("xch", "a,b");
5199           emitcode ("cpl", "a"); /* msb 2's complement */
5200           emitcode ("addc", "a,#0x00");
5201           emitcode ("xch", "a,b");
5202         }
5203       emitLabel (lbl);
5204     }
5205   aopPut (result, "a", 0);
5206   if (size == 2)
5207     aopPut (result, "b", 1);
5208
5209   popB (pushedB);
5210 }
5211
5212 /*-----------------------------------------------------------------*/
5213 /* genMult - generates code for multiplication                     */
5214 /*-----------------------------------------------------------------*/
5215 static void
5216 genMult (iCode * ic)
5217 {
5218   operand *left = IC_LEFT (ic);
5219   operand *right = IC_RIGHT (ic);
5220   operand *result = IC_RESULT (ic);
5221
5222   D (emitcode (";", "genMult"));
5223
5224   /* assign the asmops */
5225   aopOp (left, ic, FALSE);
5226   aopOp (right, ic, FALSE);
5227   aopOp (result, ic, TRUE);
5228
5229   /* special cases first */
5230   /* both are bits */
5231   if (AOP_TYPE (left) == AOP_CRY &&
5232       AOP_TYPE (right) == AOP_CRY)
5233     {
5234       genMultbits (left, right, result);
5235       goto release;
5236     }
5237
5238   /* if both are of size == 1 */
5239 #if 0 // one of them can be a sloc shared with the result
5240     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5241 #else
5242   if (getSize(operandType(left)) == 1 &&
5243       getSize(operandType(right)) == 1)
5244 #endif
5245     {
5246       genMultOneByte (left, right, result);
5247       goto release;
5248     }
5249
5250   /* should have been converted to function call */
5251     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5252              getSize(OP_SYMBOL(right)->type));
5253   assert (0);
5254
5255 release:
5256   freeAsmop (result, NULL, ic, TRUE);
5257   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5258   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5259 }
5260
5261 /*-----------------------------------------------------------------*/
5262 /* genDivbits :- division of bits                                  */
5263 /*-----------------------------------------------------------------*/
5264 static void
5265 genDivbits (operand * left,
5266             operand * right,
5267             operand * result)
5268 {
5269   char *l;
5270   bool pushedB;
5271
5272   D(emitcode (";", "genDivbits"));
5273
5274   pushedB = pushB ();
5275
5276   /* the result must be bit */
5277   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5278   l = aopGet (left, 0, FALSE, FALSE);
5279
5280   MOVA (l);
5281
5282   emitcode ("div", "ab");
5283   emitcode ("rrc", "a");
5284
5285   popB (pushedB);
5286
5287   aopPut (result, "c", 0);
5288 }
5289
5290 /*-----------------------------------------------------------------*/
5291 /* genDivOneByte : 8 bit division                                  */
5292 /*-----------------------------------------------------------------*/
5293 static void
5294 genDivOneByte (operand * left,
5295                operand * right,
5296                operand * result)
5297 {
5298   bool lUnsigned, rUnsigned, pushedB;
5299   bool runtimeSign, compiletimeSign;
5300   bool accuse = FALSE;
5301   bool pushedA = FALSE;
5302   symbol *lbl;
5303   int size, offset;
5304
5305   D(emitcode (";", "genDivOneByte"));
5306
5307   /* Why is it necessary that genDivOneByte() can return an int result?
5308      Have a look at:
5309
5310         volatile unsigned char uc;
5311         volatile signed char sc1, sc2;
5312         volatile int i;
5313
5314         uc  = 255;
5315         sc1 = -1;
5316         i = uc / sc1;
5317
5318      Or:
5319
5320         sc1 = -128;
5321         sc2 = -1;
5322         i = sc1 / sc2;
5323
5324      In all cases a one byte result would overflow, the following cast to int
5325      would return the wrong result.
5326
5327      Two possible solution:
5328         a) cast operands to int, if ((unsigned) / (signed)) or
5329            ((signed) / (signed))
5330         b) return an 16 bit signed int; this is what we're doing here!
5331   */
5332
5333   size = AOP_SIZE (result) - 1;
5334   offset = 1;
5335   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5336   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5337
5338   pushedB = pushB ();
5339
5340   /* signed or unsigned */
5341   if (lUnsigned && rUnsigned)
5342     {
5343       /* unsigned is easy */
5344       MOVB (aopGet (right, 0, FALSE, FALSE));
5345       MOVA (aopGet (left, 0, FALSE, FALSE));
5346       emitcode ("div", "ab");
5347       aopPut (result, "a", 0);
5348       while (size--)
5349         aopPut (result, zero, offset++);
5350
5351       popB (pushedB);
5352       return;
5353     }
5354
5355   /* signed is a little bit more difficult */
5356
5357   /* now sign adjust for both left & right */
5358
5359   /* let's see what's needed: */
5360   /* apply negative sign during runtime */
5361   runtimeSign = FALSE;
5362   /* negative sign from literals */
5363   compiletimeSign = FALSE;
5364
5365   if (!lUnsigned)
5366     {
5367       if (AOP_TYPE(left) == AOP_LIT)
5368         {
5369           /* signed literal */
5370           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5371           if (val < 0)
5372             compiletimeSign = TRUE;
5373         }
5374       else
5375         /* signed but not literal */
5376         runtimeSign = TRUE;
5377     }
5378
5379   if (!rUnsigned)
5380     {
5381       if (AOP_TYPE(right) == AOP_LIT)
5382         {
5383           /* signed literal */
5384           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5385           if (val < 0)
5386             compiletimeSign ^= TRUE;
5387         }
5388       else
5389         /* signed but not literal */
5390         runtimeSign = TRUE;
5391     }
5392
5393   /* initialize F0, which stores the runtime sign */
5394   if (runtimeSign)
5395     {
5396       if (compiletimeSign)
5397         emitcode ("setb", "F0"); /* set sign flag */
5398       else
5399         emitcode ("clr", "F0"); /* reset sign flag */
5400     }
5401
5402   /* save the signs of the operands */
5403   if (AOP_TYPE(right) == AOP_LIT)
5404     {
5405       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5406
5407       if (!rUnsigned && val < 0)
5408         emitcode ("mov", "b,#0x%02x", -val);
5409       else
5410         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5411     }
5412   else /* ! literal */
5413     {
5414       if (rUnsigned)
5415         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5416       else
5417         {
5418           MOVA (aopGet (right, 0, FALSE, FALSE));
5419           lbl = newiTempLabel (NULL);
5420           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5421           emitcode ("cpl", "F0"); /* complement sign flag */
5422           emitcode ("cpl", "a");  /* 2's complement */
5423           emitcode ("inc", "a");
5424           emitLabel (lbl);
5425           emitcode ("mov", "b,a");
5426         }
5427     }
5428
5429   if (AOP_TYPE(left) == AOP_LIT)
5430     {
5431       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5432
5433       if (!lUnsigned && val < 0)
5434         emitcode ("mov", "a,#0x%02x", -val);
5435       else
5436         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5437     }
5438   else /* ! literal */
5439     {
5440       MOVA (aopGet (left, 0, FALSE, FALSE));
5441
5442       if (!lUnsigned)
5443         {
5444           lbl = newiTempLabel (NULL);
5445           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5446           emitcode ("cpl", "F0"); /* complement sign flag */
5447           emitcode ("cpl", "a");  /* 2's complement */
5448           emitcode ("inc", "a");
5449           emitLabel (lbl);
5450         }
5451     }
5452
5453   /* now the division */
5454   emitcode ("div", "ab");
5455
5456   if (runtimeSign || compiletimeSign)
5457     {
5458       lbl = newiTempLabel (NULL);
5459       if (runtimeSign)
5460         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5461       emitcode ("cpl", "a"); /* lsb 2's complement */
5462       emitcode ("inc", "a");
5463       emitLabel (lbl);
5464
5465       accuse = aopPut (result, "a", 0);
5466       if (size > 0)
5467         {
5468           /* msb is 0x00 or 0xff depending on the sign */
5469           if (runtimeSign)
5470             {
5471               if (accuse)
5472                 {
5473                   emitcode ("push", "acc");
5474                   pushedA = TRUE;
5475                 }
5476               emitcode ("mov", "c,F0");
5477               emitcode ("subb", "a,acc");
5478               while (size--)
5479                 aopPut (result, "a", offset++);
5480             }
5481           else /* compiletimeSign */
5482             {
5483               if (aopPutUsesAcc (result, "#0xff", offset))
5484                 {
5485                   emitcode ("push", "acc");
5486                   pushedA = TRUE;
5487                 }
5488               while (size--)
5489                 aopPut (result, "#0xff", offset++);
5490             }
5491         }
5492     }
5493   else
5494     {
5495       aopPut (result, "a", 0);
5496       while (size--)
5497         aopPut (result, zero, offset++);
5498     }
5499
5500   if (pushedA)
5501     emitcode ("pop", "acc");
5502   popB (pushedB);
5503 }
5504
5505 /*-----------------------------------------------------------------*/
5506 /* genDiv - generates code for division                            */
5507 /*-----------------------------------------------------------------*/
5508 static void
5509 genDiv (iCode * ic)
5510 {
5511   operand *left = IC_LEFT (ic);
5512   operand *right = IC_RIGHT (ic);
5513   operand *result = IC_RESULT (ic);
5514
5515   D (emitcode (";", "genDiv"));
5516
5517   /* assign the asmops */
5518   aopOp (left, ic, FALSE);
5519   aopOp (right, ic, FALSE);
5520   aopOp (result, ic, TRUE);
5521
5522   /* special cases first */
5523   /* both are bits */
5524   if (AOP_TYPE (left) == AOP_CRY &&
5525       AOP_TYPE (right) == AOP_CRY)
5526     {
5527       genDivbits (left, right, result);
5528       goto release;
5529     }
5530
5531   /* if both are of size == 1 */
5532   if (AOP_SIZE (left) == 1 &&
5533       AOP_SIZE (right) == 1)
5534     {
5535       genDivOneByte (left, right, result);
5536       goto release;
5537     }
5538
5539   /* should have been converted to function call */
5540   assert (0);
5541 release:
5542   freeAsmop (result, NULL, ic, TRUE);
5543   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5544   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5545 }
5546
5547 /*-----------------------------------------------------------------*/
5548 /* genModbits :- modulus of bits                                   */
5549 /*-----------------------------------------------------------------*/
5550 static void
5551 genModbits (operand * left,
5552             operand * right,
5553             operand * result)
5554 {
5555   char *l;
5556   bool pushedB;
5557
5558   D (emitcode (";", "genModbits"));
5559
5560   pushedB = pushB ();
5561
5562   /* the result must be bit */
5563   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5564   l = aopGet (left, 0, FALSE, FALSE);
5565
5566   MOVA (l);
5567
5568   emitcode ("div", "ab");
5569   emitcode ("mov", "a,b");
5570   emitcode ("rrc", "a");
5571
5572   popB (pushedB);
5573
5574   aopPut (result, "c", 0);
5575 }
5576
5577 /*-----------------------------------------------------------------*/
5578 /* genModOneByte : 8 bit modulus                                   */
5579 /*-----------------------------------------------------------------*/
5580 static void
5581 genModOneByte (operand * left,
5582                operand * right,
5583                operand * result)
5584 {
5585   bool lUnsigned, rUnsigned, pushedB;
5586   bool runtimeSign, compiletimeSign;
5587   symbol *lbl;
5588   int size, offset;
5589
5590   D (emitcode (";", "genModOneByte"));
5591
5592   size = AOP_SIZE (result) - 1;
5593   offset = 1;
5594   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5595   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5596
5597   /* if right is a literal, check it for 2^n */
5598   if (AOP_TYPE(right) == AOP_LIT)
5599     {
5600       unsigned char val = abs((int) operandLitValue(right));
5601       symbol *lbl2 = NULL;
5602
5603       switch (val)
5604         {
5605           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5606           case 2:
5607           case 4:
5608           case 8:
5609           case 16:
5610           case 32:
5611           case 64:
5612           case 128:
5613             if (lUnsigned)
5614               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5615                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5616               /* because iCode should have been changed to genAnd  */
5617               /* see file "SDCCopt.c", function "convertToFcall()" */
5618
5619             MOVA (aopGet (left, 0, FALSE, FALSE));
5620             emitcode ("mov", "c,acc.7");
5621             emitcode ("anl", "a,#0x%02x", val - 1);
5622             lbl = newiTempLabel (NULL);
5623             emitcode ("jz", "%05d$", (lbl->key + 100));
5624             emitcode ("jnc", "%05d$", (lbl->key + 100));
5625             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5626             if (size)
5627               {
5628                 int size2 = size;
5629                 int offs2 = offset;
5630
5631                 aopPut (result, "a", 0);
5632                 while (size2--)
5633                   aopPut (result, "#0xff", offs2++);
5634                 lbl2 = newiTempLabel (NULL);
5635                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5636               }
5637             emitLabel (lbl);
5638             aopPut (result, "a", 0);
5639             while (size--)
5640               aopPut (result, zero, offset++);
5641             if (lbl2)
5642               {
5643                 emitLabel (lbl2);
5644               }
5645             return;
5646
5647           default:
5648             break;
5649         }
5650     }
5651
5652   pushedB = pushB ();
5653
5654   /* signed or unsigned */
5655   if (lUnsigned && rUnsigned)
5656     {
5657       /* unsigned is easy */
5658       MOVB (aopGet (right, 0, FALSE, FALSE));
5659       MOVA (aopGet (left, 0, FALSE, FALSE));
5660       emitcode ("div", "ab");
5661       aopPut (result, "b", 0);
5662       while (size--)
5663         aopPut (result, zero, offset++);
5664
5665       popB (pushedB);
5666       return;
5667     }
5668
5669   /* signed is a little bit more difficult */
5670
5671   /* now sign adjust for both left & right */
5672
5673   /* modulus: sign of the right operand has no influence on the result! */
5674   if (AOP_TYPE(right) == AOP_LIT)
5675     {
5676       signed char val = (char) operandLitValue(right);
5677
5678       if (!rUnsigned && val < 0)
5679         emitcode ("mov", "b,#0x%02x", -val);
5680       else
5681         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5682     }
5683   else /* not literal */
5684     {
5685       if (rUnsigned)
5686         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5687       else
5688         {
5689           MOVA (aopGet (right, 0, FALSE, FALSE));
5690           lbl = newiTempLabel (NULL);
5691           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5692           emitcode ("cpl", "a"); /* 2's complement */
5693           emitcode ("inc", "a");
5694           emitLabel (lbl);
5695           emitcode ("mov", "b,a");
5696         }
5697     }
5698
5699   /* let's see what's needed: */
5700   /* apply negative sign during runtime */
5701   runtimeSign = FALSE;
5702   /* negative sign from literals */
5703   compiletimeSign = FALSE;
5704
5705   /* sign adjust left side */
5706   if (AOP_TYPE(left) == AOP_LIT)
5707     {
5708       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5709
5710       if (!lUnsigned && val < 0)
5711         {
5712           compiletimeSign = TRUE; /* set sign flag */
5713           emitcode ("mov", "a,#0x%02x", -val);
5714         }
5715       else
5716         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5717     }
5718   else /* ! literal */
5719     {
5720       MOVA (aopGet (left, 0, FALSE, FALSE));
5721
5722       if (!lUnsigned)
5723         {
5724           runtimeSign = TRUE;
5725           emitcode ("clr", "F0"); /* clear sign flag */
5726
5727           lbl = newiTempLabel (NULL);
5728           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5729           emitcode ("setb", "F0"); /* set sign flag */
5730           emitcode ("cpl", "a");   /* 2's complement */
5731           emitcode ("inc", "a");
5732           emitLabel (lbl);
5733         }
5734     }
5735
5736   /* now the modulus */
5737   emitcode ("div", "ab");
5738
5739   if (runtimeSign || compiletimeSign)
5740     {
5741       emitcode ("mov", "a,b");
5742       lbl = newiTempLabel (NULL);
5743       if (runtimeSign)
5744         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5745       emitcode ("cpl", "a"); /* 2's complement */
5746       emitcode ("inc", "a");
5747       emitLabel (lbl);
5748
5749       aopPut (result, "a", 0);
5750       if (size > 0)
5751         {
5752           /* msb is 0x00 or 0xff depending on the sign */
5753           if (runtimeSign)
5754             {
5755               emitcode ("mov", "c,F0");
5756               emitcode ("subb", "a,acc");
5757               while (size--)
5758                 aopPut (result, "a", offset++);
5759             }
5760           else /* compiletimeSign */
5761             while (size--)
5762               aopPut (result, "#0xff", offset++);
5763         }
5764     }
5765   else
5766     {
5767       aopPut (result, "b", 0);
5768       while (size--)
5769         aopPut (result, zero, offset++);
5770     }
5771
5772   popB (pushedB);
5773 }
5774
5775 /*-----------------------------------------------------------------*/
5776 /* genMod - generates code for division                            */
5777 /*-----------------------------------------------------------------*/
5778 static void
5779 genMod (iCode * ic)
5780 {
5781   operand *left = IC_LEFT (ic);
5782   operand *right = IC_RIGHT (ic);
5783   operand *result = IC_RESULT (ic);
5784
5785   D (emitcode (";", "genMod"));
5786
5787   /* assign the asmops */
5788   aopOp (left, ic, FALSE);
5789   aopOp (right, ic, FALSE);
5790   aopOp (result, ic, TRUE);
5791
5792   /* special cases first */
5793   /* both are bits */
5794   if (AOP_TYPE (left) == AOP_CRY &&
5795       AOP_TYPE (right) == AOP_CRY)
5796     {
5797       genModbits (left, right, result);
5798       goto release;
5799     }
5800
5801   /* if both are of size == 1 */
5802   if (AOP_SIZE (left) == 1 &&
5803       AOP_SIZE (right) == 1)
5804     {
5805       genModOneByte (left, right, result);
5806       goto release;
5807     }
5808
5809   /* should have been converted to function call */
5810   assert (0);
5811
5812 release:
5813   freeAsmop (result, NULL, ic, TRUE);
5814   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5815   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5816 }
5817
5818 /*-----------------------------------------------------------------*/
5819 /* genIfxJump :- will create a jump depending on the ifx           */
5820 /*-----------------------------------------------------------------*/
5821 static void
5822 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5823 {
5824   symbol *jlbl;
5825   symbol *tlbl = newiTempLabel (NULL);
5826   char *inst;
5827
5828   D (emitcode (";", "genIfxJump"));
5829
5830   /* if true label then we jump if condition
5831      supplied is true */
5832   if (IC_TRUE (ic))
5833     {
5834       jlbl = IC_TRUE (ic);
5835       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5836                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5837     }
5838   else
5839     {
5840       /* false label is present */
5841       jlbl = IC_FALSE (ic);
5842       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5843                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5844     }
5845   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5846     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5847   else
5848     emitcode (inst, "%05d$", tlbl->key + 100);
5849   freeForBranchAsmop (result);
5850   freeForBranchAsmop (right);
5851   freeForBranchAsmop (left);
5852   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5853   emitLabel (tlbl);
5854
5855   /* mark the icode as generated */
5856   ic->generated = 1;
5857 }
5858
5859 /*-----------------------------------------------------------------*/
5860 /* genCmp :- greater or less than comparison                       */
5861 /*-----------------------------------------------------------------*/
5862 static void
5863 genCmp (operand * left, operand * right,
5864         operand * result, iCode * ifx, int sign, iCode *ic)
5865 {
5866   int size, offset = 0;
5867   unsigned long lit = 0L;
5868   bool rightInB;
5869
5870   D (emitcode (";", "genCmp"));
5871
5872   /* if left & right are bit variables */
5873   if (AOP_TYPE (left) == AOP_CRY &&
5874       AOP_TYPE (right) == AOP_CRY)
5875     {
5876       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5877       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5878     }
5879   else
5880     {
5881       /* subtract right from left if at the
5882          end the carry flag is set then we know that
5883          left is greater than right */
5884       size = max (AOP_SIZE (left), AOP_SIZE (right));
5885
5886       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5887       if ((size == 1) && !sign &&
5888           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5889         {
5890           symbol *lbl = newiTempLabel (NULL);
5891           emitcode ("cjne", "%s,%s,%05d$",
5892                     aopGet (left, offset, FALSE, FALSE),
5893                     aopGet (right, offset, FALSE, FALSE),
5894                     lbl->key + 100);
5895           emitLabel (lbl);
5896         }
5897       else
5898         {
5899           if (AOP_TYPE (right) == AOP_LIT)
5900             {
5901               lit = ulFromVal (AOP (right)->aopu.aop_lit);
5902               /* optimize if(x < 0) or if(x >= 0) */
5903               if (lit == 0L)
5904                 {
5905                   if (!sign)
5906                     {
5907                       CLRC;
5908                     }
5909                   else
5910                     {
5911                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5912                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5913                         {
5914                           genIfxJump (ifx, "acc.7", left, right, result);
5915                           freeAsmop (right, NULL, ic, TRUE);
5916                           freeAsmop (left, NULL, ic, TRUE);
5917
5918                           return;
5919                         }
5920                       else
5921                         {
5922                           emitcode ("rlc", "a");
5923                         }
5924                     }
5925                   goto release;
5926                 }
5927               else
5928                 {//nonzero literal
5929                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5930                   while (size && (bytelit == 0))
5931                     {
5932                       offset++;
5933                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5934                       size--;
5935                     }
5936                   CLRC;
5937                   while (size--)
5938                     {
5939                       MOVA (aopGet (left, offset, FALSE, FALSE));
5940                       if (sign && size == 0)
5941                         {
5942                           emitcode ("xrl", "a,#0x80");
5943                           emitcode ("subb", "a,#0x%02x",
5944                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5945                         }
5946                       else
5947                         {
5948                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5949                         }
5950                       offset++;
5951                     }
5952                   goto release;
5953                 }
5954             }
5955           CLRC;
5956           while (size--)
5957             {
5958               bool pushedB = FALSE;
5959               rightInB = aopGetUsesAcc(right, offset);
5960               if (rightInB)
5961                 {
5962                   pushedB = pushB ();
5963                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5964                 }
5965               MOVA (aopGet (left, offset, FALSE, FALSE));
5966               if (sign && size == 0)
5967                 {
5968                   emitcode ("xrl", "a,#0x80");
5969                   if (!rightInB)
5970                     {
5971                       pushedB = pushB ();
5972                       rightInB++;
5973                       MOVB (aopGet (right, offset, FALSE, FALSE));
5974                     }
5975                   emitcode ("xrl", "b,#0x80");
5976                   emitcode ("subb", "a,b");
5977                 }
5978               else
5979                 {
5980                   if (rightInB)
5981                     emitcode ("subb", "a,b");
5982                   else
5983                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5984                 }
5985               if (rightInB)
5986                 popB (pushedB);
5987               offset++;
5988             }
5989         }
5990     }
5991
5992 release:
5993   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5994   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5995   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5996     {
5997       outBitC (result);
5998     }
5999   else
6000     {
6001       /* if the result is used in the next
6002          ifx conditional branch then generate
6003          code a little differently */
6004       if (ifx)
6005         {
6006           genIfxJump (ifx, "c", NULL, NULL, result);
6007         }
6008       else
6009         {
6010           outBitC (result);
6011         }
6012       /* leave the result in acc */
6013     }
6014 }
6015
6016 /*-----------------------------------------------------------------*/
6017 /* genCmpGt :- greater than comparison                             */
6018 /*-----------------------------------------------------------------*/
6019 static void
6020 genCmpGt (iCode * ic, iCode * ifx)
6021 {
6022   operand *left, *right, *result;
6023   sym_link *letype, *retype;
6024   int sign;
6025
6026   D (emitcode (";", "genCmpGt"));
6027
6028   left = IC_LEFT (ic);
6029   right = IC_RIGHT (ic);
6030   result = IC_RESULT (ic);
6031
6032   letype = getSpec (operandType (left));
6033   retype = getSpec (operandType (right));
6034   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6035            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6036   /* assign the asmops */
6037   aopOp (result, ic, TRUE);
6038   aopOp (left, ic, FALSE);
6039   aopOp (right, ic, FALSE);
6040
6041   genCmp (right, left, result, ifx, sign, ic);
6042
6043   freeAsmop (result, NULL, ic, TRUE);
6044 }
6045
6046 /*-----------------------------------------------------------------*/
6047 /* genCmpLt - less than comparisons                                */
6048 /*-----------------------------------------------------------------*/
6049 static void
6050 genCmpLt (iCode * ic, iCode * ifx)
6051 {
6052   operand *left, *right, *result;
6053   sym_link *letype, *retype;
6054   int sign;
6055
6056   D (emitcode (";", "genCmpLt"));
6057
6058   left = IC_LEFT (ic);
6059   right = IC_RIGHT (ic);
6060   result = IC_RESULT (ic);
6061
6062   letype = getSpec (operandType (left));
6063   retype = getSpec (operandType (right));
6064   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6065            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6066   /* assign the asmops */
6067   aopOp (result, ic, TRUE);
6068   aopOp (left, ic, FALSE);
6069   aopOp (right, ic, FALSE);
6070
6071   genCmp (left, right, result, ifx, sign, ic);
6072
6073   freeAsmop (result, NULL, ic, TRUE);
6074 }
6075
6076 /*-----------------------------------------------------------------*/
6077 /* gencjneshort - compare and jump if not equal                    */
6078 /*-----------------------------------------------------------------*/
6079 static void
6080 gencjneshort (operand * left, operand * right, symbol * lbl)
6081 {
6082   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6083   int offset = 0;
6084   unsigned long lit = 0L;
6085
6086   D (emitcode (";", "gencjneshort"));
6087
6088   /* if the left side is a literal or
6089      if the right is in a pointer register and left
6090      is not */
6091   if ((AOP_TYPE (left) == AOP_LIT)  ||
6092       (AOP_TYPE (left) == AOP_IMMD) ||
6093       (AOP_TYPE (left) == AOP_DIR)  ||
6094       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6095     {
6096       operand *t = right;
6097       right = left;
6098       left = t;
6099     }
6100
6101   if (AOP_TYPE (right) == AOP_LIT)
6102     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6103
6104   /* if the right side is a literal then anything goes */
6105   if (AOP_TYPE (right) == AOP_LIT &&
6106       AOP_TYPE (left) != AOP_DIR  &&
6107       AOP_TYPE (left) != AOP_IMMD)
6108     {
6109       while (size--)
6110         {
6111           emitcode ("cjne", "%s,%s,%05d$",
6112                     aopGet (left, offset, FALSE, FALSE),
6113                     aopGet (right, offset, FALSE, FALSE),
6114                     lbl->key + 100);
6115           offset++;
6116         }
6117     }
6118
6119   /* if the right side is in a register or in direct space or
6120      if the left is a pointer register & right is not */
6121   else if (AOP_TYPE (right) == AOP_REG ||
6122            AOP_TYPE (right) == AOP_DIR ||
6123            AOP_TYPE (right) == AOP_LIT ||
6124            AOP_TYPE (right) == AOP_IMMD ||
6125            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6126            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6127     {
6128       while (size--)
6129         {
6130           MOVA (aopGet (left, offset, FALSE, FALSE));
6131           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6132               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6133             emitcode ("jnz", "%05d$", lbl->key + 100);
6134           else
6135             emitcode ("cjne", "a,%s,%05d$",
6136                       aopGet (right, offset, FALSE, TRUE),
6137                       lbl->key + 100);
6138           offset++;
6139         }
6140     }
6141   else
6142     {
6143       /* right is a pointer reg need both a & b */
6144       while (size--)
6145         {
6146           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6147           wassertl(!BINUSE, "B was in use");
6148           MOVB (aopGet (left, offset, FALSE, FALSE));
6149           MOVA (aopGet (right, offset, FALSE, FALSE));
6150           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6151           offset++;
6152         }
6153     }
6154 }
6155
6156 /*-----------------------------------------------------------------*/
6157 /* gencjne - compare and jump if not equal                         */
6158 /*-----------------------------------------------------------------*/
6159 static void
6160 gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
6161 {
6162   symbol *tlbl = newiTempLabel (NULL);
6163
6164   D (emitcode (";", "gencjne"));
6165
6166   gencjneshort (left, right, lbl);
6167
6168   if (useCarry)
6169       SETC;
6170   else
6171       MOVA (one);
6172   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6173   emitLabel (lbl);
6174   if (useCarry)
6175       CLRC;
6176   else
6177       MOVA (zero);
6178   emitLabel (tlbl);
6179 }
6180
6181 /*-----------------------------------------------------------------*/
6182 /* genCmpEq - generates code for equal to                          */
6183 /*-----------------------------------------------------------------*/
6184 static void
6185 genCmpEq (iCode * ic, iCode * ifx)
6186 {
6187   bool swappedLR = FALSE;
6188   operand *left, *right, *result;
6189
6190   D (emitcode (";", "genCmpEq"));
6191
6192   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6193   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6194   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6195
6196   /* if literal, literal on the right or
6197      if the right is in a pointer register and left
6198      is not */
6199   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6200       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6201     {
6202       operand *t = IC_RIGHT (ic);
6203       IC_RIGHT (ic) = IC_LEFT (ic);
6204       IC_LEFT (ic) = t;
6205       swappedLR = TRUE;
6206     }
6207
6208   if (ifx && !AOP_SIZE (result))
6209     {
6210       symbol *tlbl;
6211       /* if they are both bit variables */
6212       if (AOP_TYPE (left) == AOP_CRY &&
6213           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6214         {
6215           if (AOP_TYPE (right) == AOP_LIT)
6216             {
6217               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6218               if (lit == 0L)
6219                 {
6220                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6221                   emitcode ("cpl", "c");
6222                 }
6223               else if (lit == 1L)
6224                 {
6225                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6226                 }
6227               else
6228                 {
6229                   emitcode ("clr", "c");
6230                 }
6231               /* AOP_TYPE(right) == AOP_CRY */
6232             }
6233           else
6234             {
6235               symbol *lbl = newiTempLabel (NULL);
6236               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6237               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6238               emitcode ("cpl", "c");
6239               emitLabel (lbl);
6240             }
6241           /* if true label then we jump if condition
6242              supplied is true */
6243           tlbl = newiTempLabel (NULL);
6244           if (IC_TRUE (ifx))
6245             {
6246               emitcode ("jnc", "%05d$", tlbl->key + 100);
6247               freeForBranchAsmop (result);
6248               freeForBranchAsmop (right);
6249               freeForBranchAsmop (left);
6250               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6251             }
6252           else
6253             {
6254               emitcode ("jc", "%05d$", tlbl->key + 100);
6255               freeForBranchAsmop (result);
6256               freeForBranchAsmop (right);
6257               freeForBranchAsmop (left);
6258               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6259             }
6260           emitLabel (tlbl);
6261         }
6262       else
6263         {
6264           tlbl = newiTempLabel (NULL);
6265           gencjneshort (left, right, tlbl);
6266           if (IC_TRUE (ifx))
6267             {
6268               freeForBranchAsmop (result);
6269               freeForBranchAsmop (right);
6270               freeForBranchAsmop (left);
6271               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6272               emitLabel (tlbl);
6273             }
6274           else
6275             {
6276               symbol *lbl = newiTempLabel (NULL);
6277               emitcode ("sjmp", "%05d$", lbl->key + 100);
6278               emitLabel (tlbl);
6279               freeForBranchAsmop (result);
6280               freeForBranchAsmop (right);
6281               freeForBranchAsmop (left);
6282               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6283               emitLabel (lbl);
6284             }
6285         }
6286       /* mark the icode as generated */
6287       ifx->generated = 1;
6288       goto release;
6289     }
6290
6291   /* if they are both bit variables */
6292   if (AOP_TYPE (left) == AOP_CRY &&
6293       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6294     {
6295       if (AOP_TYPE (right) == AOP_LIT)
6296         {
6297           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6298           if (lit == 0L)
6299             {
6300               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6301               emitcode ("cpl", "c");
6302             }
6303           else if (lit == 1L)
6304             {
6305               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6306             }
6307           else
6308             {
6309               emitcode ("clr", "c");
6310             }
6311           /* AOP_TYPE(right) == AOP_CRY */
6312         }
6313       else
6314         {
6315           symbol *lbl = newiTempLabel (NULL);
6316           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6317           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6318           emitcode ("cpl", "c");
6319           emitLabel (lbl);
6320         }
6321       /* c = 1 if egal */
6322       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6323         {
6324           outBitC (result);
6325           goto release;
6326         }
6327       if (ifx)
6328         {
6329           genIfxJump (ifx, "c", left, right, result);
6330           goto release;
6331         }
6332       /* if the result is used in an arithmetic operation
6333          then put the result in place */
6334       outBitC (result);
6335     }
6336   else
6337     {
6338       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6339         {
6340           gencjne (left, right, newiTempLabel (NULL), TRUE);
6341           aopPut (result, "c", 0);
6342           goto release;
6343         }
6344       gencjne (left, right, newiTempLabel (NULL), FALSE);
6345       if (ifx)
6346         {
6347           genIfxJump (ifx, "a", left, right, result);
6348           goto release;
6349         }
6350       /* if the result is used in an arithmetic operation
6351          then put the result in place */
6352       if (AOP_TYPE (result) != AOP_CRY)
6353         outAcc (result);
6354       /* leave the result in acc */
6355     }
6356
6357 release:
6358   freeAsmop (result, NULL, ic, TRUE);
6359   if (!swappedLR)
6360     {
6361       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6362       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6363     }
6364   else
6365     {
6366       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6367       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6368     }
6369 }
6370
6371 /*-----------------------------------------------------------------*/
6372 /* ifxForOp - returns the icode containing the ifx for operand     */
6373 /*-----------------------------------------------------------------*/
6374 static iCode *
6375 ifxForOp (operand * op, iCode * ic)
6376 {
6377   /* if true symbol then needs to be assigned */
6378   if (IS_TRUE_SYMOP (op))
6379     return NULL;
6380
6381   /* if this has register type condition and
6382      the next instruction is ifx with the same operand
6383      and live to of the operand is upto the ifx only then */
6384   if (ic->next &&
6385       ic->next->op == IFX &&
6386       IC_COND (ic->next)->key == op->key &&
6387       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6388     return ic->next;
6389
6390   return NULL;
6391 }
6392
6393 /*-----------------------------------------------------------------*/
6394 /* hasInc - operand is incremented before any other use            */
6395 /*-----------------------------------------------------------------*/
6396 static iCode *
6397 hasInc (operand *op, iCode *ic, int osize)
6398 {
6399   sym_link *type = operandType(op);
6400   sym_link *retype = getSpec (type);
6401   iCode *lic = ic->next;
6402   int isize ;
6403
6404   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6405   if (!IS_SYMOP(op)) return NULL;
6406
6407   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6408   if (IS_AGGREGATE(type->next)) return NULL;
6409   if (osize != (isize = getSize(type->next))) return NULL;
6410
6411   while (lic) {
6412     /* if operand of the form op = op + <sizeof *op> */
6413     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6414         isOperandEqual(IC_RESULT(lic),op) &&
6415         isOperandLiteral(IC_RIGHT(lic)) &&
6416         operandLitValue(IC_RIGHT(lic)) == isize) {
6417       return lic;
6418     }
6419     /* if the operand used or deffed */
6420     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6421       return NULL;
6422     }
6423     /* if GOTO or IFX */
6424     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6425     lic = lic->next;
6426   }
6427   return NULL;
6428 }
6429
6430 /*-----------------------------------------------------------------*/
6431 /* genAndOp - for && operation                                     */
6432 /*-----------------------------------------------------------------*/
6433 static void
6434 genAndOp (iCode * ic)
6435 {
6436   operand *left, *right, *result;
6437   symbol *tlbl;
6438
6439   D (emitcode (";", "genAndOp"));
6440
6441   /* note here that && operations that are in an
6442      if statement are taken away by backPatchLabels
6443      only those used in arthmetic operations remain */
6444   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6445   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6446   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6447
6448   /* if both are bit variables */
6449   if (AOP_TYPE (left) == AOP_CRY &&
6450       AOP_TYPE (right) == AOP_CRY)
6451     {
6452       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6453       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6454       outBitC (result);
6455     }
6456   else
6457     {
6458       tlbl = newiTempLabel (NULL);
6459       toBoolean (left);
6460       emitcode ("jz", "%05d$", tlbl->key + 100);
6461       toBoolean (right);
6462       emitLabel (tlbl);
6463       outBitAcc (result);
6464     }
6465
6466   freeAsmop (result, NULL, ic, TRUE);
6467   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6468   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6469 }
6470
6471
6472 /*-----------------------------------------------------------------*/
6473 /* genOrOp - for || operation                                      */
6474 /*-----------------------------------------------------------------*/
6475 static void
6476 genOrOp (iCode * ic)
6477 {
6478   operand *left, *right, *result;
6479   symbol *tlbl;
6480
6481   D (emitcode (";", "genOrOp"));
6482
6483   /* note here that || operations that are in an
6484      if statement are taken away by backPatchLabels
6485      only those used in arthmetic operations remain */
6486   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6487   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6488   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6489
6490   /* if both are bit variables */
6491   if (AOP_TYPE (left) == AOP_CRY &&
6492       AOP_TYPE (right) == AOP_CRY)
6493     {
6494       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6495       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6496       outBitC (result);
6497     }
6498   else
6499     {
6500       tlbl = newiTempLabel (NULL);
6501       toBoolean (left);
6502       emitcode ("jnz", "%05d$", tlbl->key + 100);
6503       toBoolean (right);
6504       emitLabel (tlbl);
6505       outBitAcc (result);
6506     }
6507
6508   freeAsmop (result, NULL, ic, TRUE);
6509   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6510   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6511 }
6512
6513 /*-----------------------------------------------------------------*/
6514 /* isLiteralBit - test if lit == 2^n                               */
6515 /*-----------------------------------------------------------------*/
6516 static int
6517 isLiteralBit (unsigned long lit)
6518 {
6519   unsigned long pw[32] =
6520   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6521    0x100L, 0x200L, 0x400L, 0x800L,
6522    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6523    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6524    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6525    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6526    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6527   int idx;
6528
6529   for (idx = 0; idx < 32; idx++)
6530     if (lit == pw[idx])
6531       return idx + 1;
6532   return 0;
6533 }
6534
6535 /*-----------------------------------------------------------------*/
6536 /* continueIfTrue -                                                */
6537 /*-----------------------------------------------------------------*/
6538 static void
6539 continueIfTrue (iCode * ic)
6540 {
6541   if (IC_TRUE (ic))
6542     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6543   ic->generated = 1;
6544 }
6545
6546 /*-----------------------------------------------------------------*/
6547 /* jmpIfTrue -                                                     */
6548 /*-----------------------------------------------------------------*/
6549 static void
6550 jumpIfTrue (iCode * ic)
6551 {
6552   if (!IC_TRUE (ic))
6553     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6554   ic->generated = 1;
6555 }
6556
6557 /*-----------------------------------------------------------------*/
6558 /* jmpTrueOrFalse -                                                */
6559 /*-----------------------------------------------------------------*/
6560 static void
6561 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6562 {
6563   // ugly but optimized by peephole
6564   if (IC_TRUE (ic))
6565     {
6566       symbol *nlbl = newiTempLabel (NULL);
6567       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6568       emitLabel (tlbl);
6569       freeForBranchAsmop (result);
6570       freeForBranchAsmop (right);
6571       freeForBranchAsmop (left);
6572       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6573       emitLabel (nlbl);
6574     }
6575   else
6576     {
6577       freeForBranchAsmop (result);
6578       freeForBranchAsmop (right);
6579       freeForBranchAsmop (left);
6580       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6581       emitLabel (tlbl);
6582     }
6583   ic->generated = 1;
6584 }
6585
6586 /*-----------------------------------------------------------------*/
6587 /* genAnd  - code for and                                          */
6588 /*-----------------------------------------------------------------*/
6589 static void
6590 genAnd (iCode * ic, iCode * ifx)
6591 {
6592   operand *left, *right, *result;
6593   int size, offset = 0;
6594   unsigned long lit = 0L;
6595   int bytelit = 0;
6596   char buffer[10];
6597
6598   D (emitcode (";", "genAnd"));
6599
6600   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6601   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6602   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6603
6604 #ifdef DEBUG_TYPE
6605   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6606             AOP_TYPE (result),
6607             AOP_TYPE (left), AOP_TYPE (right));
6608   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6609             AOP_SIZE (result),
6610             AOP_SIZE (left), AOP_SIZE (right));
6611 #endif
6612
6613   /* if left is a literal & right is not then exchange them */
6614   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6615       AOP_NEEDSACC (left))
6616     {
6617       operand *tmp = right;
6618       right = left;
6619       left = tmp;
6620     }
6621
6622   /* if result = right then exchange left and right */
6623   if (sameRegs (AOP (result), AOP (right)))
6624     {
6625       operand *tmp = right;
6626       right = left;
6627       left = tmp;
6628     }
6629
6630   /* if right is bit then exchange them */
6631   if (AOP_TYPE (right) == AOP_CRY &&
6632       AOP_TYPE (left) != AOP_CRY)
6633     {
6634       operand *tmp = right;
6635       right = left;
6636       left = tmp;
6637     }
6638   if (AOP_TYPE (right) == AOP_LIT)
6639     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6640
6641   size = AOP_SIZE (result);
6642
6643   // if(bit & yy)
6644   // result = bit & yy;
6645   if (AOP_TYPE (left) == AOP_CRY)
6646     {
6647       // c = bit & literal;
6648       if (AOP_TYPE (right) == AOP_LIT)
6649         {
6650           if (lit & 1)
6651             {
6652               if (size && sameRegs (AOP (result), AOP (left)))
6653                 // no change
6654                 goto release;
6655               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6656             }
6657           else
6658             {
6659               // bit(result) = 0;
6660               if (size && (AOP_TYPE (result) == AOP_CRY))
6661                 {
6662                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6663                   goto release;
6664                 }
6665               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6666                 {
6667                   jumpIfTrue (ifx);
6668                   goto release;
6669                 }
6670               emitcode ("clr", "c");
6671             }
6672         }
6673       else
6674         {
6675           if (AOP_TYPE (right) == AOP_CRY)
6676             {
6677               // c = bit & bit;
6678               if (IS_OP_ACCUSE (left))
6679                 {
6680                   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6681                 }
6682               else
6683                 {
6684                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6685                   emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6686                 }
6687             }
6688           else
6689             {
6690               // c = bit & val;
6691               MOVA (aopGet (right, 0, FALSE, FALSE));
6692               // c = lsb
6693               emitcode ("rrc", "a");
6694               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6695             }
6696         }
6697       // bit = c
6698       // val = c
6699       if (size)
6700         outBitC (result);
6701       // if(bit & ...)
6702       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6703         genIfxJump (ifx, "c", left, right, result);
6704       goto release;
6705     }
6706
6707   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6708   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6709   if ((AOP_TYPE (right) == AOP_LIT) &&
6710       (AOP_TYPE (result) == AOP_CRY) &&
6711       (AOP_TYPE (left) != AOP_CRY))
6712     {
6713       int posbit = isLiteralBit (lit);
6714       /* left &  2^n */
6715       if (posbit)
6716         {
6717           posbit--;
6718           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6719           // bit = left & 2^n
6720           if (size)
6721             {
6722               switch (posbit & 0x07)
6723                 {
6724                   case 0: emitcode ("rrc", "a");
6725                           break;
6726                   case 7: emitcode ("rlc", "a");
6727                           break;
6728                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6729                           break;
6730                 }
6731             }
6732           // if(left &  2^n)
6733           else
6734             {
6735               if (ifx)
6736                 {
6737                   SNPRINTF (buffer, sizeof(buffer),
6738                             "acc.%d", posbit & 0x07);
6739                   genIfxJump (ifx, buffer, left, right, result);
6740                 }
6741               else
6742                 {// what is this case? just found it in ds390/gen.c
6743                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6744                 }
6745               goto release;
6746             }
6747         }
6748       else
6749         {
6750           symbol *tlbl = newiTempLabel (NULL);
6751           int sizel = AOP_SIZE (left);
6752           if (size)
6753             emitcode ("setb", "c");
6754           while (sizel--)
6755             {
6756               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6757                 {
6758                   MOVA (aopGet (left, offset, FALSE, FALSE));
6759                   // byte ==  2^n ?
6760                   if ((posbit = isLiteralBit (bytelit)) != 0)
6761                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6762                   else
6763                     {
6764                       if (bytelit != 0x0FFL)
6765                         emitcode ("anl", "a,%s",
6766                                   aopGet (right, offset, FALSE, TRUE));
6767                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6768                     }
6769                 }
6770               offset++;
6771             }
6772           // bit = left & literal
6773           if (size)
6774             {
6775               emitcode ("clr", "c");
6776               emitLabel (tlbl);
6777             }
6778           // if(left & literal)
6779           else
6780             {
6781               if (ifx)
6782                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6783               else
6784                 emitLabel (tlbl);
6785               goto release;
6786             }
6787         }
6788       outBitC (result);
6789       goto release;
6790     }
6791
6792   /* if left is same as result */
6793   if (sameRegs (AOP (result), AOP (left)))
6794     {
6795       for (; size--; offset++)
6796         {
6797           if (AOP_TYPE (right) == AOP_LIT)
6798             {
6799               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6800               if (bytelit == 0x0FF)
6801                 {
6802                   /* dummy read of volatile operand */
6803                   if (isOperandVolatile (left, FALSE))
6804                     MOVA (aopGet (left, offset, FALSE, FALSE));
6805                   else
6806                     continue;
6807                 }
6808               else if (bytelit == 0)
6809                 {
6810                   aopPut (result, zero, offset);
6811                 }
6812               else if (IS_AOP_PREG (result))
6813                 {
6814                   MOVA (aopGet (left, offset, FALSE, TRUE));
6815                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6816                   aopPut (result, "a", offset);
6817                 }
6818               else
6819                 emitcode ("anl", "%s,%s",
6820                           aopGet (left, offset, FALSE, TRUE),
6821                           aopGet (right, offset, FALSE, FALSE));
6822             }
6823           else
6824             {
6825               if (AOP_TYPE (left) == AOP_ACC)
6826                 {
6827                   if (offset)
6828                     emitcode("mov", "a,b");
6829                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6830                 }
6831               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6832                 {
6833                   MOVB (aopGet (left, offset, FALSE, FALSE));
6834                   MOVA (aopGet (right, offset, FALSE, FALSE));
6835                   emitcode ("anl", "a,b");
6836                   aopPut (result, "a", offset);
6837                 }
6838               else if (aopGetUsesAcc (left, offset))
6839                 {
6840                   MOVA (aopGet (left, offset, FALSE, FALSE));
6841                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6842                   aopPut (result, "a", offset);
6843                 }
6844               else
6845                 {
6846                   MOVA (aopGet (right, offset, FALSE, FALSE));
6847                   if (IS_AOP_PREG (result))
6848                     {
6849                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6850                       aopPut (result, "a", offset);
6851                     }
6852                   else
6853                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6854                 }
6855             }
6856         }
6857     }
6858   else
6859     {
6860       // left & result in different registers
6861       if (AOP_TYPE (result) == AOP_CRY)
6862         {
6863           // result = bit
6864           // if(size), result in bit
6865           // if(!size && ifx), conditional oper: if(left & right)
6866           symbol *tlbl = newiTempLabel (NULL);
6867           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6868           if (size)
6869             emitcode ("setb", "c");
6870           while (sizer--)
6871             {
6872               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6873                   && AOP_TYPE(left)==AOP_ACC)
6874                 {
6875                   if (offset)
6876                     emitcode("mov", "a,b");
6877                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6878                 }
6879               else if (AOP_TYPE(left)==AOP_ACC)
6880                 {
6881                   if (!offset)
6882                     {
6883                       bool pushedB = pushB ();
6884                       emitcode("mov", "b,a");
6885                       MOVA (aopGet (right, offset, FALSE, FALSE));
6886                       emitcode("anl", "a,b");
6887                       popB (pushedB);
6888                     }
6889                   else
6890                     {
6891                       MOVA (aopGet (right, offset, FALSE, FALSE));
6892                       emitcode("anl", "a,b");
6893                     }
6894                 }
6895               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6896                 {
6897                   MOVB (aopGet (left, offset, FALSE, FALSE));
6898                   MOVA (aopGet (right, offset, FALSE, FALSE));
6899                   emitcode ("anl", "a,b");
6900                 }
6901               else if (aopGetUsesAcc (left, offset))
6902                 {
6903                   MOVA (aopGet (left, offset, FALSE, FALSE));
6904                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6905                     }
6906               else
6907                 {
6908                   MOVA (aopGet (right, offset, FALSE, FALSE));
6909                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6910                 }
6911
6912               emitcode ("jnz", "%05d$", tlbl->key + 100);
6913               offset++;
6914             }
6915           if (size)
6916             {
6917               CLRC;
6918               emitLabel (tlbl);
6919               outBitC (result);
6920             }
6921           else if (ifx)
6922             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6923           else
6924             emitLabel (tlbl);
6925         }
6926       else
6927         {
6928           for (; (size--); offset++)
6929             {
6930               // normal case
6931               // result = left & right
6932               if (AOP_TYPE (right) == AOP_LIT)
6933                 {
6934                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6935                   if (bytelit == 0x0FF)
6936                     {
6937                       aopPut (result,
6938                               aopGet (left, offset, FALSE, FALSE),
6939                               offset);
6940                       continue;
6941                     }
6942                   else if (bytelit == 0)
6943                     {
6944                       /* dummy read of volatile operand */
6945                       if (isOperandVolatile (left, FALSE))
6946                         MOVA (aopGet (left, offset, FALSE, FALSE));
6947                       aopPut (result, zero, offset);
6948                       continue;
6949                     }
6950                   else if (AOP_TYPE (left) == AOP_ACC)
6951                     {
6952                       if (!offset)
6953                         {
6954                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6955                           aopPut (result, "a", offset);
6956                           continue;
6957                         }
6958                       else
6959                         {
6960                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6961                           aopPut (result, "b", offset);
6962                           continue;
6963                         }
6964                     }
6965                 }
6966               // faster than result <- left, anl result,right
6967               // and better if result is SFR
6968               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6969                   && AOP_TYPE(left)==AOP_ACC)
6970                 {
6971                   if (offset)
6972                     emitcode("mov", "a,b");
6973                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6974                 }
6975               else if (AOP_TYPE(left)==AOP_ACC)
6976                 {
6977                   if (!offset)
6978                     {
6979                       bool pushedB = pushB ();
6980                       emitcode("mov", "b,a");
6981                       MOVA (aopGet (right, offset, FALSE, FALSE));
6982                       emitcode("anl", "a,b");
6983                       popB (pushedB);
6984                     }
6985                   else
6986                     {
6987                       MOVA (aopGet (right, offset, FALSE, FALSE));
6988                       emitcode("anl", "a,b");
6989                     }
6990                 }
6991               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6992                 {
6993                   MOVB (aopGet (left, offset, FALSE, FALSE));
6994                   MOVA (aopGet (right, offset, FALSE, FALSE));
6995                   emitcode ("anl", "a,b");
6996                 }
6997               else if (aopGetUsesAcc (left, offset))
6998                 {
6999                   MOVA (aopGet (left, offset, FALSE, FALSE));
7000                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7001                 }
7002               else
7003                 {
7004                   MOVA (aopGet (right, offset, FALSE, FALSE));
7005                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7006                 }
7007               aopPut (result, "a", offset);
7008             }
7009         }
7010     }
7011
7012 release:
7013   freeAsmop (result, NULL, ic, TRUE);
7014   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7015   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7016 }
7017
7018 /*-----------------------------------------------------------------*/
7019 /* genOr  - code for or                                            */
7020 /*-----------------------------------------------------------------*/
7021 static void
7022 genOr (iCode * ic, iCode * ifx)
7023 {
7024   operand *left, *right, *result;
7025   int size, offset = 0;
7026   unsigned long lit = 0L;
7027   int bytelit = 0;
7028
7029   D (emitcode (";", "genOr"));
7030
7031   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7032   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7033   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7034
7035 #ifdef DEBUG_TYPE
7036   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7037             AOP_TYPE (result),
7038             AOP_TYPE (left), AOP_TYPE (right));
7039   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7040             AOP_SIZE (result),
7041             AOP_SIZE (left), AOP_SIZE (right));
7042 #endif
7043
7044   /* if left is a literal & right is not then exchange them */
7045   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7046       AOP_NEEDSACC (left))
7047     {
7048       operand *tmp = right;
7049       right = left;
7050       left = tmp;
7051     }
7052
7053   /* if result = right then exchange them */
7054   if (sameRegs (AOP (result), AOP (right)))
7055     {
7056       operand *tmp = right;
7057       right = left;
7058       left = tmp;
7059     }
7060
7061   /* if right is bit then exchange them */
7062   if (AOP_TYPE (right) == AOP_CRY &&
7063       AOP_TYPE (left) != AOP_CRY)
7064     {
7065       operand *tmp = right;
7066       right = left;
7067       left = tmp;
7068     }
7069   if (AOP_TYPE (right) == AOP_LIT)
7070     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7071
7072   size = AOP_SIZE (result);
7073
7074   // if(bit | yy)
7075   // xx = bit | yy;
7076   if (AOP_TYPE (left) == AOP_CRY)
7077     {
7078       if (AOP_TYPE (right) == AOP_LIT)
7079         {
7080           // c = bit | literal;
7081           if (lit)
7082             {
7083               // lit != 0 => result = 1
7084               if (AOP_TYPE (result) == AOP_CRY)
7085                 {
7086                   if (size)
7087                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7088                   else if (ifx)
7089                     continueIfTrue (ifx);
7090                   goto release;
7091                 }
7092               emitcode ("setb", "c");
7093             }
7094           else
7095             {
7096               // lit == 0 => result = left
7097               if (size && sameRegs (AOP (result), AOP (left)))
7098                 goto release;
7099               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7100             }
7101         }
7102       else
7103         {
7104           if (AOP_TYPE (right) == AOP_CRY)
7105             {
7106               // c = bit | bit;
7107               if (IS_OP_ACCUSE (left))
7108                 {
7109                   emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7110                 }
7111               else
7112                 {
7113                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7114                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7115                 }
7116             }
7117           else
7118             {
7119               // c = bit | val;
7120               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7121                 {
7122                   symbol *tlbl = newiTempLabel (NULL);
7123                   emitcode ("jb", "%s,%05d$",
7124                             AOP (left)->aopu.aop_dir, tlbl->key + 100);
7125                   toBoolean (right);
7126                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7127                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7128                   goto release;
7129                 }
7130               else
7131                 {
7132                   toCarry (right);
7133                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7134                 }
7135             }
7136         }
7137       // bit = c
7138       // val = c
7139       if (size)
7140         outBitC (result);
7141       // if(bit | ...)
7142       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7143         genIfxJump (ifx, "c", left, right, result);
7144       goto release;
7145     }
7146
7147   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7148   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7149   if ((AOP_TYPE (right) == AOP_LIT) &&
7150       (AOP_TYPE (result) == AOP_CRY) &&
7151       (AOP_TYPE (left) != AOP_CRY))
7152     {
7153       if (lit)
7154         {
7155           // result = 1
7156           if (size)
7157             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7158           else
7159             continueIfTrue (ifx);
7160           goto release;
7161         }
7162       else
7163         {
7164           // lit = 0, result = boolean(left)
7165           if (size)
7166             emitcode ("setb", "c");
7167           toBoolean (right);
7168           if (size)
7169             {
7170               symbol *tlbl = newiTempLabel (NULL);
7171               emitcode ("jnz", "%05d$", tlbl->key + 100);
7172               CLRC;
7173               emitLabel (tlbl);
7174             }
7175           else
7176             {
7177               genIfxJump (ifx, "a", left, right, result);
7178               goto release;
7179             }
7180         }
7181       outBitC (result);
7182       goto release;
7183     }
7184
7185   /* if left is same as result */
7186   if (sameRegs (AOP (result), AOP (left)))
7187     {
7188       for (; size--; offset++)
7189         {
7190           if (AOP_TYPE (right) == AOP_LIT)
7191             {
7192               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7193               if (bytelit == 0)
7194                 {
7195                   /* dummy read of volatile operand */
7196                   if (isOperandVolatile (left, FALSE))
7197                     MOVA (aopGet (left, offset, FALSE, FALSE));
7198                   else
7199                     continue;
7200                 }
7201               else if (bytelit == 0x0FF)
7202                 {
7203                   aopPut (result, "#0xff", offset);
7204                 }
7205               else if (IS_AOP_PREG (left))
7206                 {
7207                   MOVA (aopGet (left, offset, FALSE, TRUE));
7208                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7209                   aopPut (result, "a", offset);
7210                 }
7211               else
7212                 {
7213                   emitcode ("orl", "%s,%s",
7214                             aopGet (left, offset, FALSE, TRUE),
7215                             aopGet (right, offset, FALSE, FALSE));
7216                 }
7217             }
7218           else
7219             {
7220               if (AOP_TYPE (left) == AOP_ACC)
7221                 {
7222                   if (offset)
7223                     emitcode("mov", "a,b");
7224                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7225                 }
7226               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7227                 {
7228                   MOVB (aopGet (left, offset, FALSE, FALSE));
7229                   MOVA (aopGet (right, offset, FALSE, FALSE));
7230                   emitcode ("orl", "a,b");
7231                   aopPut (result, "a", offset);
7232                 }
7233               else if (aopGetUsesAcc (left, offset))
7234                 {
7235                   MOVA (aopGet (left, offset, FALSE, FALSE));
7236                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7237                   aopPut (result, "a", offset);
7238                 }
7239               else
7240                 {
7241                   MOVA (aopGet (right, offset, FALSE, FALSE));
7242                   if (IS_AOP_PREG (left))
7243                     {
7244                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7245                       aopPut (result, "a", offset);
7246                     }
7247                   else
7248                     {
7249                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7250                     }
7251                 }
7252             }
7253         }
7254     }
7255   else
7256     {
7257       // left & result in different registers
7258       if (AOP_TYPE (result) == AOP_CRY)
7259         {
7260           // result = bit
7261           // if(size), result in bit
7262           // if(!size && ifx), conditional oper: if(left | right)
7263           symbol *tlbl = newiTempLabel (NULL);
7264           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7265           if (size)
7266             emitcode ("setb", "c");
7267           while (sizer--)
7268             {
7269               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7270                   && AOP_TYPE(left)==AOP_ACC)
7271                 {
7272                   if (offset)
7273                     emitcode("mov", "a,b");
7274                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7275                 }
7276               else if (AOP_TYPE(left)==AOP_ACC)
7277                 {
7278                   if (!offset)
7279                     {
7280                       bool pushedB = pushB ();
7281                       emitcode("mov", "b,a");
7282                       MOVA (aopGet (right, offset, FALSE, FALSE));
7283                       emitcode("orl", "a,b");
7284                       popB (pushedB);
7285                     }
7286                   else
7287                     {
7288                       MOVA (aopGet (right, offset, FALSE, FALSE));
7289                       emitcode("orl", "a,b");
7290                     }
7291                 }
7292               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7293                 {
7294                   MOVB (aopGet (left, offset, FALSE, FALSE));
7295                   MOVA (aopGet (right, offset, FALSE, FALSE));
7296                   emitcode ("orl", "a,b");
7297                 }
7298               else if (aopGetUsesAcc (left, offset))
7299                 {
7300                   MOVA (aopGet (left, offset, FALSE, FALSE));
7301                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7302                 }
7303               else
7304                 {
7305                   MOVA (aopGet (right, offset, FALSE, FALSE));
7306                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7307               }
7308
7309               emitcode ("jnz", "%05d$", tlbl->key + 100);
7310               offset++;
7311             }
7312           if (size)
7313             {
7314               CLRC;
7315               emitLabel (tlbl);
7316               outBitC (result);
7317             }
7318           else if (ifx)
7319             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7320           else
7321             emitLabel (tlbl);
7322         }
7323       else
7324         {
7325           for (; (size--); offset++)
7326             {
7327               // normal case
7328               // result = left | right
7329               if (AOP_TYPE (right) == AOP_LIT)
7330                 {
7331                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7332                   if (bytelit == 0)
7333                     {
7334                       aopPut (result,
7335                               aopGet (left, offset, FALSE, FALSE),
7336                               offset);
7337                       continue;
7338                     }
7339                   else if (bytelit == 0x0FF)
7340                     {
7341                       /* dummy read of volatile operand */
7342                       if (isOperandVolatile (left, FALSE))
7343                         MOVA (aopGet (left, offset, FALSE, FALSE));
7344                       aopPut (result, "#0xff", offset);
7345                       continue;
7346                     }
7347                 }
7348               // faster than result <- left, orl result,right
7349               // and better if result is SFR
7350               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7351                   && AOP_TYPE(left)==AOP_ACC)
7352                 {
7353                   if (offset)
7354                     emitcode("mov", "a,b");
7355                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7356                 }
7357               else if (AOP_TYPE(left)==AOP_ACC)
7358                 {
7359                   if (!offset)
7360                     {
7361                       bool pushedB = pushB ();
7362                       emitcode("mov", "b,a");
7363                       MOVA (aopGet (right, offset, FALSE, FALSE));
7364                       emitcode("orl", "a,b");
7365                       popB (pushedB);
7366                     }
7367                   else
7368                     {
7369                       MOVA (aopGet (right, offset, FALSE, FALSE));
7370                       emitcode("orl", "a,b");
7371                     }
7372                 }
7373               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7374                 {
7375                   MOVB (aopGet (left, offset, FALSE, FALSE));
7376                   MOVA (aopGet (right, offset, FALSE, FALSE));
7377                   emitcode ("orl", "a,b");
7378                 }
7379               else if (aopGetUsesAcc (left, offset))
7380                 {
7381                   MOVA (aopGet (left, offset, FALSE, FALSE));
7382                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7383                 }
7384               else
7385                 {
7386                   MOVA (aopGet (right, offset, FALSE, FALSE));
7387                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7388                 }
7389               aopPut (result, "a", offset);
7390             }
7391         }
7392     }
7393
7394 release:
7395   freeAsmop (result, NULL, ic, TRUE);
7396   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7397   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7398 }
7399
7400 /*-----------------------------------------------------------------*/
7401 /* genXor - code for xclusive or                                   */
7402 /*-----------------------------------------------------------------*/
7403 static void
7404 genXor (iCode * ic, iCode * ifx)
7405 {
7406   operand *left, *right, *result;
7407   int size, offset = 0;
7408   unsigned long lit = 0L;
7409   int bytelit = 0;
7410
7411   D (emitcode (";", "genXor"));
7412
7413   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7414   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7415   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7416
7417 #ifdef DEBUG_TYPE
7418   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7419             AOP_TYPE (result),
7420             AOP_TYPE (left), AOP_TYPE (right));
7421   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7422             AOP_SIZE (result),
7423             AOP_SIZE (left), AOP_SIZE (right));
7424 #endif
7425
7426   /* if left is a literal & right is not ||
7427      if left needs acc & right does not */
7428   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7429       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7430     {
7431       operand *tmp = right;
7432       right = left;
7433       left = tmp;
7434     }
7435
7436   /* if result = right then exchange them */
7437   if (sameRegs (AOP (result), AOP (right)))
7438     {
7439       operand *tmp = right;
7440       right = left;
7441       left = tmp;
7442     }
7443
7444   /* if right is bit then exchange them */
7445   if (AOP_TYPE (right) == AOP_CRY &&
7446       AOP_TYPE (left) != AOP_CRY)
7447     {
7448       operand *tmp = right;
7449       right = left;
7450       left = tmp;
7451     }
7452
7453   if (AOP_TYPE (right) == AOP_LIT)
7454     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7455
7456   size = AOP_SIZE (result);
7457
7458   // if(bit ^ yy)
7459   // xx = bit ^ yy;
7460   if (AOP_TYPE (left) == AOP_CRY)
7461     {
7462       if (AOP_TYPE (right) == AOP_LIT)
7463         {
7464           // c = bit & literal;
7465           if (lit >> 1)
7466             {
7467               // lit>>1  != 0 => result = 1
7468               if (AOP_TYPE (result) == AOP_CRY)
7469                 {
7470                   if (size)
7471                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7472                   else if (ifx)
7473                     continueIfTrue (ifx);
7474                   goto release;
7475                 }
7476               emitcode ("setb", "c");
7477             }
7478           else
7479             {
7480               // lit == (0 or 1)
7481               if (lit == 0)
7482                 {
7483                   // lit == 0, result = left
7484                   if (size && sameRegs (AOP (result), AOP (left)))
7485                     goto release;
7486                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7487                 }
7488               else
7489                 {
7490                   // lit == 1, result = not(left)
7491                   if (size && sameRegs (AOP (result), AOP (left)))
7492                     {
7493                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7494                       goto release;
7495                     }
7496                   else
7497                     {
7498                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7499                       emitcode ("cpl", "c");
7500                     }
7501                 }
7502             }
7503         }
7504       else
7505         {
7506           // right != literal
7507           symbol *tlbl = newiTempLabel (NULL);
7508           if (AOP_TYPE (right) == AOP_CRY)
7509             {
7510               // c = bit ^ bit;
7511               if (IS_OP_ACCUSE (left))
7512                 {// left already is in the carry
7513                   operand *tmp = right;
7514                   right = left;
7515                   left = tmp;
7516                 }
7517               else
7518                 {
7519                   toCarry (right);
7520                 }
7521             }
7522           else
7523             {
7524               // c = bit ^ val
7525               toCarry (right);
7526             }
7527           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7528           emitcode ("cpl", "c");
7529           emitLabel (tlbl);
7530         }
7531       // bit = c
7532       // val = c
7533       if (size)
7534         outBitC (result);
7535       // if(bit ^ ...)
7536       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7537         genIfxJump (ifx, "c", left, right, result);
7538       goto release;
7539     }
7540
7541   /* if left is same as result */
7542   if (sameRegs (AOP (result), AOP (left)))
7543     {
7544       for (; size--; offset++)
7545         {
7546           if (AOP_TYPE (right) == AOP_LIT)
7547             {
7548               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7549               if (bytelit == 0)
7550                 {
7551                   /* dummy read of volatile operand */
7552                   if (isOperandVolatile (left, FALSE))
7553                     MOVA (aopGet (left, offset, FALSE, FALSE));
7554                   else
7555                     continue;
7556                 }
7557               else if (IS_AOP_PREG (left))
7558                 {
7559                   MOVA (aopGet (left, offset, FALSE, TRUE));
7560                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7561                   aopPut (result, "a", offset);
7562                 }
7563               else
7564                 {
7565                   emitcode ("xrl", "%s,%s",
7566                             aopGet (left, offset, FALSE, TRUE),
7567                             aopGet (right, offset, FALSE, FALSE));
7568                 }
7569             }
7570           else
7571             {
7572               if (AOP_TYPE (left) == AOP_ACC)
7573                 {
7574                   if (offset)
7575                     emitcode("mov", "a,b");
7576                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7577                 }
7578               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7579                 {
7580                   MOVB (aopGet (left, offset, FALSE, FALSE));
7581                   MOVA (aopGet (right, offset, FALSE, FALSE));
7582                   emitcode ("xrl", "a,b");
7583                   aopPut (result, "a", offset);
7584                 }
7585               else if (aopGetUsesAcc (left, offset))
7586                 {
7587                   MOVA (aopGet (left, offset, FALSE, FALSE));
7588                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7589                   aopPut (result, "a", offset);
7590                 }
7591               else
7592                 {
7593                   MOVA (aopGet (right, offset, FALSE, FALSE));
7594                   if (IS_AOP_PREG (left))
7595                     {
7596                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7597                       aopPut (result, "a", offset);
7598                     }
7599                   else
7600                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7601                 }
7602             }
7603         }
7604     }
7605   else
7606     {
7607       // left & result in different registers
7608       if (AOP_TYPE (result) == AOP_CRY)
7609         {
7610           // result = bit
7611           // if(size), result in bit
7612           // if(!size && ifx), conditional oper: if(left ^ right)
7613           symbol *tlbl = newiTempLabel (NULL);
7614           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7615
7616           if (size)
7617             emitcode ("setb", "c");
7618           while (sizer--)
7619             {
7620               if ((AOP_TYPE (right) == AOP_LIT) &&
7621                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7622                 {
7623                   MOVA (aopGet (left, offset, FALSE, FALSE));
7624                 }
7625               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7626                   && AOP_TYPE(left)==AOP_ACC)
7627                 {
7628                   if (offset)
7629                     emitcode("mov", "a,b");
7630                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7631                 }
7632               else if (AOP_TYPE(left)==AOP_ACC)
7633                 {
7634                   if (!offset)
7635                     {
7636                       bool pushedB = pushB ();
7637                       emitcode("mov", "b,a");
7638                       MOVA (aopGet (right, offset, FALSE, FALSE));
7639                       emitcode("xrl", "a,b");
7640                       popB (pushedB);
7641                     }
7642                   else
7643                     {
7644                       MOVA (aopGet (right, offset, FALSE, FALSE));
7645                       emitcode("xrl", "a,b");
7646                     }
7647                 }
7648               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7649                 {
7650                   MOVB (aopGet (left, offset, FALSE, FALSE));
7651                   MOVA (aopGet (right, offset, FALSE, FALSE));
7652                   emitcode ("xrl", "a,b");
7653                 }
7654               else if (aopGetUsesAcc (left, offset))
7655                 {
7656                   MOVA (aopGet (left, offset, FALSE, FALSE));
7657                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7658                 }
7659               else
7660                 {
7661                   MOVA (aopGet (right, offset, FALSE, FALSE));
7662                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7663                 }
7664
7665               emitcode ("jnz", "%05d$", tlbl->key + 100);
7666               offset++;
7667             }
7668           if (size)
7669             {
7670               CLRC;
7671               emitLabel (tlbl);
7672               outBitC (result);
7673             }
7674           else if (ifx)
7675             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7676         }
7677       else
7678         {
7679           for (; (size--); offset++)
7680             {
7681               // normal case
7682               // result = left ^ right
7683               if (AOP_TYPE (right) == AOP_LIT)
7684                 {
7685                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7686                   if (bytelit == 0)
7687                     {
7688                       aopPut (result,
7689                               aopGet (left, offset, FALSE, FALSE),
7690                               offset);
7691                       continue;
7692                     }
7693                 }
7694               // faster than result <- left, xrl result,right
7695               // and better if result is SFR
7696               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7697                   && AOP_TYPE(left)==AOP_ACC)
7698                 {
7699                   if (offset)
7700                     emitcode("mov", "a,b");
7701                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7702                 }
7703               else if (AOP_TYPE(left)==AOP_ACC)
7704                 {
7705                   if (!offset)
7706                     {
7707                       bool pushedB = pushB ();
7708                       emitcode("mov", "b,a");
7709                       MOVA (aopGet (right, offset, FALSE, FALSE));
7710                       emitcode("xrl", "a,b");
7711                       popB (pushedB);
7712                     }
7713                   else
7714                     {
7715                       MOVA (aopGet (right, offset, FALSE, FALSE));
7716                       emitcode("xrl", "a,b");
7717                     }
7718                 }
7719               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7720                 {
7721                   MOVB (aopGet (left, offset, FALSE, FALSE));
7722                   MOVA (aopGet (right, offset, FALSE, FALSE));
7723                   emitcode ("xrl", "a,b");
7724                 }
7725               else if (aopGetUsesAcc (left, offset))
7726                 {
7727                   MOVA (aopGet (left, offset, FALSE, FALSE));
7728                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7729                 }
7730               else
7731                 {
7732                   MOVA (aopGet (right, offset, FALSE, FALSE));
7733                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7734                 }
7735               aopPut (result, "a", offset);
7736             }
7737         }
7738     }
7739
7740 release:
7741   freeAsmop (result, NULL, ic, TRUE);
7742   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7743   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7744 }
7745
7746 /*-----------------------------------------------------------------*/
7747 /* genInline - write the inline code out                           */
7748 /*-----------------------------------------------------------------*/
7749 static void
7750 genInline (iCode * ic)
7751 {
7752   char *buffer, *bp, *bp1;
7753   bool inComment = FALSE;
7754
7755   D (emitcode (";", "genInline"));
7756
7757   _G.inLine += (!options.asmpeep);
7758
7759   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7760
7761   /* emit each line as a code */
7762   while (*bp)
7763     {
7764       switch (*bp)
7765         {
7766         case ';':
7767           inComment = TRUE;
7768           ++bp;
7769           break;
7770
7771         case '\n':
7772           inComment = FALSE;
7773           *bp++ = '\0';
7774           emitcode (bp1, "");
7775           bp1 = bp;
7776           break;
7777
7778         default:
7779           /* Add \n for labels, not dirs such as c:\mydir */
7780           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7781             {
7782               ++bp;
7783               *bp = '\0';
7784               ++bp;
7785               emitcode (bp1, "");
7786               bp1 = bp;
7787             }
7788           else
7789             ++bp;
7790           break;
7791         }
7792     }
7793   if (bp1 != bp)
7794     emitcode (bp1, "");
7795
7796   Safe_free (buffer);
7797
7798   _G.inLine -= (!options.asmpeep);
7799 }
7800
7801 /*-----------------------------------------------------------------*/
7802 /* genRRC - rotate right with carry                                */
7803 /*-----------------------------------------------------------------*/
7804 static void
7805 genRRC (iCode * ic)
7806 {
7807   operand *left, *result;
7808   int size, offset;
7809   char *l;
7810
7811   D (emitcode (";", "genRRC"));
7812
7813   /* rotate right with carry */
7814   left = IC_LEFT (ic);
7815   result = IC_RESULT (ic);
7816   aopOp (left, ic, FALSE);
7817   aopOp (result, ic, FALSE);
7818
7819   /* move it to the result */
7820   size = AOP_SIZE (result);
7821   offset = size - 1;
7822   if (size == 1) { /* special case for 1 byte */
7823       l = aopGet (left, offset, FALSE, FALSE);
7824       MOVA (l);
7825       emitcode ("rr", "a");
7826       goto release;
7827   }
7828   /* no need to clear carry, bit7 will be written later */
7829   while (size--)
7830     {
7831       l = aopGet (left, offset, FALSE, FALSE);
7832       MOVA (l);
7833       emitcode ("rrc", "a");
7834       if (AOP_SIZE (result) > 1)
7835         aopPut (result, "a", offset--);
7836     }
7837   /* now we need to put the carry into the
7838      highest order byte of the result */
7839   if (AOP_SIZE (result) > 1)
7840     {
7841       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7842       MOVA (l);
7843     }
7844   emitcode ("mov", "acc.7,c");
7845  release:
7846   aopPut (result, "a", AOP_SIZE (result) - 1);
7847   freeAsmop (result, NULL, ic, TRUE);
7848   freeAsmop (left, NULL, ic, TRUE);
7849 }
7850
7851 /*-----------------------------------------------------------------*/
7852 /* genRLC - generate code for rotate left with carry               */
7853 /*-----------------------------------------------------------------*/
7854 static void
7855 genRLC (iCode * ic)
7856 {
7857   operand *left, *result;
7858   int size, offset;
7859   char *l;
7860
7861   D (emitcode (";", "genRLC"));
7862
7863   /* rotate right with carry */
7864   left = IC_LEFT (ic);
7865   result = IC_RESULT (ic);
7866   aopOp (left, ic, FALSE);
7867   aopOp (result, ic, FALSE);
7868
7869   /* move it to the result */
7870   size = AOP_SIZE (result);
7871   offset = 0;
7872   if (size--)
7873     {
7874       l = aopGet (left, offset, FALSE, FALSE);
7875       MOVA (l);
7876       if (size == 0) { /* special case for 1 byte */
7877               emitcode("rl","a");
7878               goto release;
7879       }
7880       emitcode("rlc","a"); /* bit0 will be written later */
7881       if (AOP_SIZE (result) > 1)
7882         {
7883           aopPut (result, "a", offset++);
7884         }
7885
7886       while (size--)
7887         {
7888           l = aopGet (left, offset, FALSE, FALSE);
7889           MOVA (l);
7890           emitcode ("rlc", "a");
7891           if (AOP_SIZE (result) > 1)
7892             aopPut (result, "a", offset++);
7893         }
7894     }
7895   /* now we need to put the carry into the
7896      highest order byte of the result */
7897   if (AOP_SIZE (result) > 1)
7898     {
7899       l = aopGet (result, 0, FALSE, FALSE);
7900       MOVA (l);
7901     }
7902   emitcode ("mov", "acc.0,c");
7903  release:
7904   aopPut (result, "a", 0);
7905   freeAsmop (result, NULL, ic, TRUE);
7906   freeAsmop (left, NULL, ic, TRUE);
7907 }
7908
7909 /*-----------------------------------------------------------------*/
7910 /* genGetHbit - generates code get highest order bit               */
7911 /*-----------------------------------------------------------------*/
7912 static void
7913 genGetHbit (iCode * ic)
7914 {
7915   operand *left, *result;
7916
7917   D (emitcode (";", "genGetHbit"));
7918
7919   left = IC_LEFT (ic);
7920   result = IC_RESULT (ic);
7921   aopOp (left, ic, FALSE);
7922   aopOp (result, ic, FALSE);
7923
7924   /* get the highest order byte into a */
7925   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7926   if (AOP_TYPE (result) == AOP_CRY)
7927     {
7928       emitcode ("rlc", "a");
7929       outBitC (result);
7930     }
7931   else
7932     {
7933       emitcode ("rl", "a");
7934       emitcode ("anl", "a,#0x01");
7935       outAcc (result);
7936     }
7937
7938   freeAsmop (result, NULL, ic, TRUE);
7939   freeAsmop (left, NULL, ic, TRUE);
7940 }
7941
7942 /*-----------------------------------------------------------------*/
7943 /* genGetAbit - generates code get a single bit                    */
7944 /*-----------------------------------------------------------------*/
7945 static void
7946 genGetAbit (iCode * ic)
7947 {
7948   operand *left, *right, *result;
7949   int shCount;
7950
7951   D (emitcode (";", "genGetAbit"));
7952
7953   left = IC_LEFT (ic);
7954   right = IC_RIGHT (ic);
7955   result = IC_RESULT (ic);
7956   aopOp (left, ic, FALSE);
7957   aopOp (right, ic, FALSE);
7958   aopOp (result, ic, FALSE);
7959
7960   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7961
7962   /* get the needed byte into a */
7963   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7964   shCount %= 8;
7965   if (AOP_TYPE (result) == AOP_CRY)
7966     {
7967       if ((shCount) == 7)
7968           emitcode ("rlc", "a");
7969       else if ((shCount) == 0)
7970           emitcode ("rrc", "a");
7971       else
7972           emitcode ("mov", "c,acc[%d]", shCount);
7973       outBitC (result);
7974     }
7975   else
7976     {
7977       switch (shCount)
7978         {
7979         case 2:
7980           emitcode ("rr", "a");
7981           //fallthrough
7982         case 1:
7983           emitcode ("rr", "a");
7984           //fallthrough
7985         case 0:
7986           emitcode ("anl", "a,#0x01");
7987           break;
7988         case 3:
7989         case 5:
7990           emitcode ("mov", "c,acc[%d]", shCount);
7991           emitcode ("clr", "a");
7992           emitcode ("rlc", "a");
7993           break;
7994         case 4:
7995           emitcode ("swap", "a");
7996           emitcode ("anl", "a,#0x01");
7997           break;
7998         case 6:
7999           emitcode ("rl", "a");
8000           //fallthrough
8001         case 7:
8002           emitcode ("rl", "a");
8003           emitcode ("anl", "a,#0x01");
8004           break;
8005         }
8006       outAcc (result);
8007     }
8008
8009   freeAsmop (result, NULL, ic, TRUE);
8010   freeAsmop (right, NULL, ic, TRUE);
8011   freeAsmop (left, NULL, ic, TRUE);
8012 }
8013
8014 /*-----------------------------------------------------------------*/
8015 /* genGetByte - generates code get a single byte                   */
8016 /*-----------------------------------------------------------------*/
8017 static void
8018 genGetByte (iCode * ic)
8019 {
8020   operand *left, *right, *result;
8021   int offset;
8022
8023   D (emitcode (";", "genGetByte"));
8024
8025   left = IC_LEFT (ic);
8026   right = IC_RIGHT (ic);
8027   result = IC_RESULT (ic);
8028   aopOp (left, ic, FALSE);
8029   aopOp (right, ic, FALSE);
8030   aopOp (result, ic, FALSE);
8031
8032   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8033   aopPut (result,
8034           aopGet (left, offset, FALSE, FALSE),
8035           0);
8036
8037   freeAsmop (result, NULL, ic, TRUE);
8038   freeAsmop (right, NULL, ic, TRUE);
8039   freeAsmop (left, NULL, ic, TRUE);
8040 }
8041
8042 /*-----------------------------------------------------------------*/
8043 /* genGetWord - generates code get two bytes                       */
8044 /*-----------------------------------------------------------------*/
8045 static void
8046 genGetWord (iCode * ic)
8047 {
8048   operand *left, *right, *result;
8049   int offset;
8050
8051   D (emitcode (";", "genGetWord"));
8052
8053   left = IC_LEFT (ic);
8054   right = IC_RIGHT (ic);
8055   result = IC_RESULT (ic);
8056   aopOp (left, ic, FALSE);
8057   aopOp (right, ic, FALSE);
8058   aopOp (result, ic, FALSE);
8059
8060   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8061   aopPut (result,
8062           aopGet (left, offset, FALSE, FALSE),
8063           0);
8064   aopPut (result,
8065           aopGet (left, offset+1, FALSE, FALSE),
8066           1);
8067
8068   freeAsmop (result, NULL, ic, TRUE);
8069   freeAsmop (right, NULL, ic, TRUE);
8070   freeAsmop (left, NULL, ic, TRUE);
8071 }
8072
8073 /*-----------------------------------------------------------------*/
8074 /* genSwap - generates code to swap nibbles or bytes               */
8075 /*-----------------------------------------------------------------*/
8076 static void
8077 genSwap (iCode * ic)
8078 {
8079   operand *left, *result;
8080
8081   D(emitcode (";", "genSwap"));
8082
8083   left = IC_LEFT (ic);
8084   result = IC_RESULT (ic);
8085   aopOp (left, ic, FALSE);
8086   aopOp (result, ic, FALSE);
8087
8088   switch (AOP_SIZE (left))
8089     {
8090     case 1: /* swap nibbles in byte */
8091       MOVA (aopGet (left, 0, FALSE, FALSE));
8092       emitcode ("swap", "a");
8093       aopPut (result, "a", 0);
8094       break;
8095     case 2: /* swap bytes in word */
8096       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8097         {
8098           MOVA (aopGet (left, 0, FALSE, FALSE));
8099           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8100           aopPut (result, "a", 1);
8101         }
8102       else if (operandsEqu (left, result))
8103         {
8104           char * reg = "a";
8105           bool pushedB = FALSE, leftInB = FALSE;
8106
8107           MOVA (aopGet (left, 0, FALSE, FALSE));
8108           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8109             {
8110               pushedB = pushB ();
8111               emitcode ("mov", "b,a");
8112               reg = "b";
8113               leftInB = TRUE;
8114             }
8115           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8116           aopPut (result, reg, 1);
8117
8118           if (leftInB)
8119             popB (pushedB);
8120         }
8121       else
8122         {
8123           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8124           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8125         }
8126       break;
8127     default:
8128       wassertl(FALSE, "unsupported SWAP operand size");
8129     }
8130
8131   freeAsmop (result, NULL, ic, TRUE);
8132   freeAsmop (left, NULL, ic, TRUE);
8133 }
8134
8135 /*-----------------------------------------------------------------*/
8136 /* AccRol - rotate left accumulator by known count                 */
8137 /*-----------------------------------------------------------------*/
8138 static void
8139 AccRol (int shCount)
8140 {
8141   shCount &= 0x0007;            // shCount : 0..7
8142
8143   switch (shCount)
8144     {
8145     case 0:
8146       break;
8147     case 1:
8148       emitcode ("rl", "a");
8149       break;
8150     case 2:
8151       emitcode ("rl", "a");
8152       emitcode ("rl", "a");
8153       break;
8154     case 3:
8155       emitcode ("swap", "a");
8156       emitcode ("rr", "a");
8157       break;
8158     case 4:
8159       emitcode ("swap", "a");
8160       break;
8161     case 5:
8162       emitcode ("swap", "a");
8163       emitcode ("rl", "a");
8164       break;
8165     case 6:
8166       emitcode ("rr", "a");
8167       emitcode ("rr", "a");
8168       break;
8169     case 7:
8170       emitcode ("rr", "a");
8171       break;
8172     }
8173 }
8174
8175 /*-----------------------------------------------------------------*/
8176 /* AccLsh - left shift accumulator by known count                  */
8177 /*-----------------------------------------------------------------*/
8178 static void
8179 AccLsh (int shCount)
8180 {
8181   if (shCount != 0)
8182     {
8183       if (shCount == 1)
8184         emitcode ("add", "a,acc");
8185       else if (shCount == 2)
8186         {
8187           emitcode ("add", "a,acc");
8188           emitcode ("add", "a,acc");
8189         }
8190       else
8191         {
8192           /* rotate left accumulator */
8193           AccRol (shCount);
8194           /* and kill the lower order bits */
8195           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8196         }
8197     }
8198 }
8199
8200 /*-----------------------------------------------------------------*/
8201 /* AccRsh - right shift accumulator by known count                 */
8202 /*-----------------------------------------------------------------*/
8203 static void
8204 AccRsh (int shCount)
8205 {
8206   if (shCount != 0)
8207     {
8208       if (shCount == 1)
8209         {
8210           CLRC;
8211           emitcode ("rrc", "a");
8212         }
8213       else
8214         {
8215           /* rotate right accumulator */
8216           AccRol (8 - shCount);
8217           /* and kill the higher order bits */
8218           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8219         }
8220     }
8221 }
8222
8223 /*-----------------------------------------------------------------*/
8224 /* AccSRsh - signed right shift accumulator by known count                 */
8225 /*-----------------------------------------------------------------*/
8226 static void
8227 AccSRsh (int shCount)
8228 {
8229   symbol *tlbl;
8230   if (shCount != 0)
8231     {
8232       if (shCount == 1)
8233         {
8234           emitcode ("mov", "c,acc.7");
8235           emitcode ("rrc", "a");
8236         }
8237       else if (shCount == 2)
8238         {
8239           emitcode ("mov", "c,acc.7");
8240           emitcode ("rrc", "a");
8241           emitcode ("mov", "c,acc.7");
8242           emitcode ("rrc", "a");
8243         }
8244       else
8245         {
8246           tlbl = newiTempLabel (NULL);
8247           /* rotate right accumulator */
8248           AccRol (8 - shCount);
8249           /* and kill the higher order bits */
8250           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8251           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8252           emitcode ("orl", "a,#0x%02x",
8253                     (unsigned char) ~SRMask[shCount]);
8254           emitLabel (tlbl);
8255         }
8256     }
8257 }
8258
8259 /*-----------------------------------------------------------------*/
8260 /* shiftR1Left2Result - shift right one byte from left to result   */
8261 /*-----------------------------------------------------------------*/
8262 static void
8263 shiftR1Left2Result (operand * left, int offl,
8264                     operand * result, int offr,
8265                     int shCount, int sign)
8266 {
8267   MOVA (aopGet (left, offl, FALSE, FALSE));
8268   /* shift right accumulator */
8269   if (sign)
8270     AccSRsh (shCount);
8271   else
8272     AccRsh (shCount);
8273   aopPut (result, "a", offr);
8274 }
8275
8276 /*-----------------------------------------------------------------*/
8277 /* shiftL1Left2Result - shift left one byte from left to result    */
8278 /*-----------------------------------------------------------------*/
8279 static void
8280 shiftL1Left2Result (operand * left, int offl,
8281                     operand * result, int offr, int shCount)
8282 {
8283   char *l;
8284   l = aopGet (left, offl, FALSE, FALSE);
8285   MOVA (l);
8286   /* shift left accumulator */
8287   AccLsh (shCount);
8288   aopPut (result, "a", offr);
8289 }
8290
8291 /*-----------------------------------------------------------------*/
8292 /* movLeft2Result - move byte from left to result                  */
8293 /*-----------------------------------------------------------------*/
8294 static void
8295 movLeft2Result (operand * left, int offl,
8296                 operand * result, int offr, int sign)
8297 {
8298   char *l;
8299   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8300     {
8301       l = aopGet (left, offl, FALSE, FALSE);
8302
8303       if (*l == '@' && (IS_AOP_PREG (result)))
8304         {
8305           emitcode ("mov", "a,%s", l);
8306           aopPut (result, "a", offr);
8307         }
8308       else
8309         {
8310           if (!sign)
8311             {
8312               aopPut (result, l, offr);
8313             }
8314           else
8315             {
8316               /* MSB sign in acc.7 ! */
8317               if (getDataSize (left) == offl + 1)
8318                 {
8319                   MOVA (l);
8320                   aopPut (result, "a", offr);
8321                 }
8322             }
8323         }
8324     }
8325 }
8326
8327 /*-----------------------------------------------------------------*/
8328 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8329 /*-----------------------------------------------------------------*/
8330 static void
8331 AccAXRrl1 (char *x)
8332 {
8333   emitcode ("rrc", "a");
8334   emitcode ("xch", "a,%s", x);
8335   emitcode ("rrc", "a");
8336   emitcode ("xch", "a,%s", x);
8337 }
8338
8339 /*-----------------------------------------------------------------*/
8340 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8341 /*-----------------------------------------------------------------*/
8342 static void
8343 AccAXLrl1 (char *x)
8344 {
8345   emitcode ("xch", "a,%s", x);
8346   emitcode ("rlc", "a");
8347   emitcode ("xch", "a,%s", x);
8348   emitcode ("rlc", "a");
8349 }
8350
8351 /*-----------------------------------------------------------------*/
8352 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8353 /*-----------------------------------------------------------------*/
8354 static void
8355 AccAXLsh1 (char *x)
8356 {
8357   emitcode ("xch", "a,%s", x);
8358   emitcode ("add", "a,acc");
8359   emitcode ("xch", "a,%s", x);
8360   emitcode ("rlc", "a");
8361 }
8362
8363 /*-----------------------------------------------------------------*/
8364 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8365 /*-----------------------------------------------------------------*/
8366 static void
8367 AccAXLsh (char *x, int shCount)
8368 {
8369   switch (shCount)
8370     {
8371     case 0:
8372       break;
8373     case 1:
8374       AccAXLsh1 (x);
8375       break;
8376     case 2:
8377       AccAXLsh1 (x);
8378       AccAXLsh1 (x);
8379       break;
8380     case 3:
8381     case 4:
8382     case 5:                     // AAAAABBB:CCCCCDDD
8383
8384       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8385
8386       emitcode ("anl", "a,#0x%02x",
8387                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8388
8389       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8390
8391       AccRol (shCount);         // DDDCCCCC:BBB00000
8392
8393       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8394
8395       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8396
8397       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8398
8399       emitcode ("anl", "a,#0x%02x",
8400                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8401
8402       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8403
8404       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8405
8406       break;
8407     case 6:                     // AAAAAABB:CCCCCCDD
8408       emitcode ("anl", "a,#0x%02x",
8409                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8410       emitcode ("mov", "c,acc.0");      // c = B
8411       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8412 #if 0 // REMOVE ME
8413       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8414       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8415 #else
8416       emitcode("rrc","a");
8417       emitcode("xch","a,%s", x);
8418       emitcode("rrc","a");
8419       emitcode("mov","c,acc.0"); //<< get correct bit
8420       emitcode("xch","a,%s", x);
8421
8422       emitcode("rrc","a");
8423       emitcode("xch","a,%s", x);
8424       emitcode("rrc","a");
8425       emitcode("xch","a,%s", x);
8426 #endif
8427       break;
8428     case 7:                     // a:x <<= 7
8429
8430       emitcode ("anl", "a,#0x%02x",
8431                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8432
8433       emitcode ("mov", "c,acc.0");      // c = B
8434
8435       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8436
8437       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8438
8439       break;
8440     default:
8441       break;
8442     }
8443 }
8444
8445 /*-----------------------------------------------------------------*/
8446 /* AccAXRsh - right shift a:x known count (0..7)                   */
8447 /*-----------------------------------------------------------------*/
8448 static void
8449 AccAXRsh (char *x, int shCount)
8450 {
8451   switch (shCount)
8452     {
8453     case 0:
8454       break;
8455     case 1:
8456       CLRC;
8457       AccAXRrl1 (x);            // 0->a:x
8458
8459       break;
8460     case 2:
8461       CLRC;
8462       AccAXRrl1 (x);            // 0->a:x
8463
8464       CLRC;
8465       AccAXRrl1 (x);            // 0->a:x
8466
8467       break;
8468     case 3:
8469     case 4:
8470     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8471
8472       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8473
8474       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8475
8476       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8477
8478       emitcode ("anl", "a,#0x%02x",
8479                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8480
8481       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8482
8483       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8484
8485       emitcode ("anl", "a,#0x%02x",
8486                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8487
8488       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8489
8490       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8491
8492       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8493
8494       break;
8495     case 6:                     // AABBBBBB:CCDDDDDD
8496
8497       emitcode ("mov", "c,acc.7");
8498       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8499
8500       emitcode ("mov", "c,acc.7");
8501       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8502
8503       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8504
8505       emitcode ("anl", "a,#0x%02x",
8506                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8507
8508       break;
8509     case 7:                     // ABBBBBBB:CDDDDDDD
8510
8511       emitcode ("mov", "c,acc.7");      // c = A
8512
8513       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8514
8515       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8516
8517       emitcode ("anl", "a,#0x%02x",
8518                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8519
8520       break;
8521     default:
8522       break;
8523     }
8524 }
8525
8526 /*-----------------------------------------------------------------*/
8527 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8528 /*-----------------------------------------------------------------*/
8529 static void
8530 AccAXRshS (char *x, int shCount)
8531 {
8532   symbol *tlbl;
8533   switch (shCount)
8534     {
8535     case 0:
8536       break;
8537     case 1:
8538       emitcode ("mov", "c,acc.7");
8539       AccAXRrl1 (x);            // s->a:x
8540
8541       break;
8542     case 2:
8543       emitcode ("mov", "c,acc.7");
8544       AccAXRrl1 (x);            // s->a:x
8545
8546       emitcode ("mov", "c,acc.7");
8547       AccAXRrl1 (x);            // s->a:x
8548
8549       break;
8550     case 3:
8551     case 4:
8552     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8553
8554       tlbl = newiTempLabel (NULL);
8555       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8556
8557       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8558
8559       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8560
8561       emitcode ("anl", "a,#0x%02x",
8562                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8563
8564       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8565
8566       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8567
8568       emitcode ("anl", "a,#0x%02x",
8569                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8570
8571       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8572
8573       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8574
8575       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8576
8577       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8578       emitcode ("orl", "a,#0x%02x",
8579                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8580
8581       emitLabel (tlbl);
8582       break;                    // SSSSAAAA:BBBCCCCC
8583
8584     case 6:                     // AABBBBBB:CCDDDDDD
8585
8586       tlbl = newiTempLabel (NULL);
8587       emitcode ("mov", "c,acc.7");
8588       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8589
8590       emitcode ("mov", "c,acc.7");
8591       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8592
8593       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8594
8595       emitcode ("anl", "a,#0x%02x",
8596                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8597
8598       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8599       emitcode ("orl", "a,#0x%02x",
8600                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8601
8602       emitLabel (tlbl);
8603       break;
8604     case 7:                     // ABBBBBBB:CDDDDDDD
8605
8606       tlbl = newiTempLabel (NULL);
8607       emitcode ("mov", "c,acc.7");      // c = A
8608
8609       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8610
8611       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8612
8613       emitcode ("anl", "a,#0x%02x",
8614                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8615
8616       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8617       emitcode ("orl", "a,#0x%02x",
8618                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8619
8620       emitLabel (tlbl);
8621       break;
8622     default:
8623       break;
8624     }
8625 }
8626
8627 /*-----------------------------------------------------------------*/
8628 /* shiftL2Left2Result - shift left two bytes from left to result   */
8629 /*-----------------------------------------------------------------*/
8630 static void
8631 shiftL2Left2Result (operand * left, int offl,
8632                     operand * result, int offr, int shCount)
8633 {
8634   char * x;
8635   bool pushedB = FALSE;
8636   bool usedB = FALSE;
8637
8638   if (sameRegs (AOP (result), AOP (left)) &&
8639       ((offl + MSB16) == offr))
8640     {
8641       /* don't crash result[offr] */
8642       MOVA (aopGet (left, offl, FALSE, FALSE));
8643       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8644       usedB = !strncmp(x, "b", 1);
8645     }
8646   else if (aopGetUsesAcc (result, offr))
8647     {
8648       movLeft2Result (left, offl, result, offr, 0);
8649       pushedB = pushB ();
8650       usedB = TRUE;
8651       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8652       MOVA (aopGet (result, offr, FALSE, FALSE));
8653       emitcode ("xch", "a,b");
8654       x = "b";
8655     }
8656   else
8657     {
8658       movLeft2Result (left, offl, result, offr, 0);
8659       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8660       x = aopGet (result, offr, FALSE, FALSE);
8661     }
8662   /* ax << shCount (x = lsb(result)) */
8663   AccAXLsh (x, shCount);
8664   if (usedB)
8665     {
8666       emitcode ("xch", "a,b");
8667       aopPut (result, "a", offr);
8668       aopPut (result, "b", offr + MSB16);
8669       popB (pushedB);
8670     }
8671   else
8672     {
8673       aopPut (result, "a", offr + MSB16);
8674     }
8675 }
8676
8677
8678 /*-----------------------------------------------------------------*/
8679 /* shiftR2Left2Result - shift right two bytes from left to result  */
8680 /*-----------------------------------------------------------------*/
8681 static void
8682 shiftR2Left2Result (operand * left, int offl,
8683                     operand * result, int offr,
8684                     int shCount, int sign)
8685 {
8686   char * x;
8687   bool pushedB = FALSE;
8688   bool usedB = FALSE;
8689
8690   if (sameRegs (AOP (result), AOP (left)) &&
8691       ((offl + MSB16) == offr))
8692     {
8693       /* don't crash result[offr] */
8694       MOVA (aopGet (left, offl, FALSE, FALSE));
8695       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8696       usedB = !strncmp(x, "b", 1);
8697     }
8698   else if (aopGetUsesAcc (result, offr))
8699     {
8700       movLeft2Result (left, offl, result, offr, 0);
8701       pushedB = pushB ();
8702       usedB = TRUE;
8703       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8704       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8705       x = "b";
8706     }
8707   else
8708     {
8709       movLeft2Result (left, offl, result, offr, 0);
8710       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8711       x = aopGet (result, offr, FALSE, FALSE);
8712     }
8713   /* a:x >> shCount (x = lsb(result)) */
8714   if (sign)
8715     AccAXRshS (x, shCount);
8716   else
8717     AccAXRsh (x, shCount);
8718   if (usedB)
8719     {
8720       emitcode ("xch", "a,b");
8721       aopPut (result, "a", offr);
8722       emitcode ("xch", "a,b");
8723       popB (pushedB);
8724     }
8725   if (getDataSize (result) > 1)
8726     aopPut (result, "a", offr + MSB16);
8727 }
8728
8729 /*-----------------------------------------------------------------*/
8730 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8731 /*-----------------------------------------------------------------*/
8732 static void
8733 shiftLLeftOrResult (operand * left, int offl,
8734                     operand * result, int offr, int shCount)
8735 {
8736   MOVA (aopGet (left, offl, FALSE, FALSE));
8737   /* shift left accumulator */
8738   AccLsh (shCount);
8739   /* or with result */
8740   if (aopGetUsesAcc (result, offr))
8741     {
8742       emitcode ("xch", "a,b");
8743       MOVA (aopGet (result, offr, FALSE, FALSE));
8744       emitcode ("orl", "a,b");
8745     }
8746   else
8747     {
8748       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8749     }
8750   /* back to result */
8751   aopPut (result, "a", offr);
8752 }
8753
8754 /*-----------------------------------------------------------------*/
8755 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8756 /*-----------------------------------------------------------------*/
8757 static void
8758 shiftRLeftOrResult (operand * left, int offl,
8759                     operand * result, int offr, int shCount)
8760 {
8761   MOVA (aopGet (left, offl, FALSE, FALSE));
8762   /* shift right accumulator */
8763   AccRsh (shCount);
8764   /* or with result */
8765   if (aopGetUsesAcc(result, offr))
8766     {
8767       emitcode ("xch", "a,b");
8768       MOVA (aopGet (result, offr, FALSE, FALSE));
8769       emitcode ("orl", "a,b");
8770     }
8771   else
8772     {
8773       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8774     }
8775   /* back to result */
8776   aopPut (result, "a", offr);
8777 }
8778
8779 /*-----------------------------------------------------------------*/
8780 /* genlshOne - left shift a one byte quantity by known count       */
8781 /*-----------------------------------------------------------------*/
8782 static void
8783 genlshOne (operand * result, operand * left, int shCount)
8784 {
8785   D (emitcode (";", "genlshOne"));
8786
8787   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8788 }
8789
8790 /*-----------------------------------------------------------------*/
8791 /* genlshTwo - left shift two bytes by known amount != 0           */
8792 /*-----------------------------------------------------------------*/
8793 static void
8794 genlshTwo (operand * result, operand * left, int shCount)
8795 {
8796   int size;
8797
8798   D (emitcode (";", "genlshTwo"));
8799
8800   size = getDataSize (result);
8801
8802   /* if shCount >= 8 */
8803   if (shCount >= 8)
8804     {
8805       shCount -= 8;
8806
8807       if (size > 1)
8808         {
8809           if (shCount)
8810             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8811           else
8812             movLeft2Result (left, LSB, result, MSB16, 0);
8813         }
8814       aopPut (result, zero, LSB);
8815     }
8816
8817   /*  1 <= shCount <= 7 */
8818   else
8819     {
8820       if (size == 1)
8821         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8822       else
8823         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8824     }
8825 }
8826
8827 /*-----------------------------------------------------------------*/
8828 /* shiftLLong - shift left one long from left to result            */
8829 /* offl = LSB or MSB16                                             */
8830 /*-----------------------------------------------------------------*/
8831 static void
8832 shiftLLong (operand * left, operand * result, int offr)
8833 {
8834   char *l;
8835   int size = AOP_SIZE (result);
8836
8837   if (size >= LSB + offr)
8838     {
8839       l = aopGet (left, LSB, FALSE, FALSE);
8840       MOVA (l);
8841       emitcode ("add", "a,acc");
8842       if (sameRegs (AOP (left), AOP (result)) &&
8843           size >= MSB16 + offr && offr != LSB)
8844         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8845       else
8846         aopPut (result, "a", LSB + offr);
8847     }
8848
8849   if (size >= MSB16 + offr)
8850     {
8851       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8852         {
8853           l = aopGet (left, MSB16, FALSE, FALSE);
8854           MOVA (l);
8855         }
8856       emitcode ("rlc", "a");
8857       if (sameRegs (AOP (left), AOP (result)) &&
8858           size >= MSB24 + offr && offr != LSB)
8859         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8860       else
8861         aopPut (result, "a", MSB16 + offr);
8862     }
8863
8864   if (size >= MSB24 + offr)
8865     {
8866       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8867         {
8868           l = aopGet (left, MSB24, FALSE, FALSE);
8869           MOVA (l);
8870         }
8871       emitcode ("rlc", "a");
8872       if (sameRegs (AOP (left), AOP (result)) &&
8873           size >= MSB32 + offr && offr != LSB)
8874         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8875       else
8876         aopPut (result, "a", MSB24 + offr);
8877     }
8878
8879   if (size > MSB32 + offr)
8880     {
8881       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8882         {
8883           l = aopGet (left, MSB32, FALSE, FALSE);
8884           MOVA (l);
8885         }
8886       emitcode ("rlc", "a");
8887       aopPut (result, "a", MSB32 + offr);
8888     }
8889   if (offr != LSB)
8890     aopPut (result, zero, LSB);
8891 }
8892
8893 /*-----------------------------------------------------------------*/
8894 /* genlshFour - shift four byte by a known amount != 0             */
8895 /*-----------------------------------------------------------------*/
8896 static void
8897 genlshFour (operand * result, operand * left, int shCount)
8898 {
8899   int size;
8900
8901   D (emitcode (";", "genlshFour"));
8902
8903   size = AOP_SIZE (result);
8904
8905   /* if shifting more that 3 bytes */
8906   if (shCount >= 24)
8907     {
8908       shCount -= 24;
8909       if (shCount)
8910         /* lowest order of left goes to the highest
8911            order of the destination */
8912         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8913       else
8914         movLeft2Result (left, LSB, result, MSB32, 0);
8915       aopPut (result, zero, LSB);
8916       aopPut (result, zero, MSB16);
8917       aopPut (result, zero, MSB24);
8918       return;
8919     }
8920
8921   /* more than two bytes */
8922   else if (shCount >= 16)
8923     {
8924       /* lower order two bytes goes to higher order two bytes */
8925       shCount -= 16;
8926       /* if some more remaining */
8927       if (shCount)
8928         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8929       else
8930         {
8931           movLeft2Result (left, MSB16, result, MSB32, 0);
8932           movLeft2Result (left, LSB, result, MSB24, 0);
8933         }
8934       aopPut (result, zero, MSB16);
8935       aopPut (result, zero, LSB);
8936       return;
8937     }
8938
8939   /* if more than 1 byte */
8940   else if (shCount >= 8)
8941     {
8942       /* lower order three bytes goes to higher order  three bytes */
8943       shCount -= 8;
8944       if (size == 2)
8945         {
8946           if (shCount)
8947             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8948           else
8949             movLeft2Result (left, LSB, result, MSB16, 0);
8950         }
8951       else
8952         {                       /* size = 4 */
8953           if (shCount == 0)
8954             {
8955               movLeft2Result (left, MSB24, result, MSB32, 0);
8956               movLeft2Result (left, MSB16, result, MSB24, 0);
8957               movLeft2Result (left, LSB, result, MSB16, 0);
8958               aopPut (result, zero, LSB);
8959             }
8960           else if (shCount == 1)
8961             shiftLLong (left, result, MSB16);
8962           else
8963             {
8964               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8965               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8966               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8967               aopPut (result, zero, LSB);
8968             }
8969         }
8970     }
8971
8972   /* 1 <= shCount <= 7 */
8973   else if (shCount <= 2)
8974     {
8975       shiftLLong (left, result, LSB);
8976       if (shCount == 2)
8977         shiftLLong (result, result, LSB);
8978     }
8979   /* 3 <= shCount <= 7, optimize */
8980   else
8981     {
8982       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8983       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8984       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8985     }
8986 }
8987
8988 /*-----------------------------------------------------------------*/
8989 /* genLeftShiftLiteral - left shifting by known count              */
8990 /*-----------------------------------------------------------------*/
8991 static void
8992 genLeftShiftLiteral (operand * left,
8993                      operand * right,
8994                      operand * result,
8995                      iCode * ic)
8996 {
8997   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
8998   int size;
8999
9000   D (emitcode (";", "genLeftShiftLiteral"));
9001
9002   freeAsmop (right, NULL, ic, TRUE);
9003
9004   aopOp (left, ic, FALSE);
9005   aopOp (result, ic, FALSE);
9006
9007   size = getSize (operandType (result));
9008
9009 #if VIEW_SIZE
9010   emitcode ("; shift left ", "result %d, left %d", size,
9011             AOP_SIZE (left));
9012 #endif
9013
9014   /* I suppose that the left size >= result size */
9015   if (shCount == 0)
9016     {
9017       while (size--)
9018         {
9019           movLeft2Result (left, size, result, size, 0);
9020         }
9021     }
9022   else if (shCount >= (size * 8))
9023     {
9024       while (size--)
9025         {
9026           aopPut (result, zero, size);
9027         }
9028     }
9029   else
9030     {
9031       switch (size)
9032         {
9033         case 1:
9034           genlshOne (result, left, shCount);
9035           break;
9036
9037         case 2:
9038           genlshTwo (result, left, shCount);
9039           break;
9040
9041         case 4:
9042           genlshFour (result, left, shCount);
9043           break;
9044         default:
9045           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9046                   "*** ack! mystery literal shift!\n");
9047           break;
9048         }
9049     }
9050   freeAsmop (result, NULL, ic, TRUE);
9051   freeAsmop (left, NULL, ic, TRUE);
9052 }
9053
9054 /*-----------------------------------------------------------------*/
9055 /* genLeftShift - generates code for left shifting                 */
9056 /*-----------------------------------------------------------------*/
9057 static void
9058 genLeftShift (iCode * ic)
9059 {
9060   operand *left, *right, *result;
9061   int size, offset;
9062   char *l;
9063   symbol *tlbl, *tlbl1;
9064   bool pushedB;
9065
9066   D (emitcode (";", "genLeftShift"));
9067
9068   right = IC_RIGHT (ic);
9069   left = IC_LEFT (ic);
9070   result = IC_RESULT (ic);
9071
9072   aopOp (right, ic, FALSE);
9073
9074   /* if the shift count is known then do it
9075      as efficiently as possible */
9076   if (AOP_TYPE (right) == AOP_LIT)
9077     {
9078       genLeftShiftLiteral (left, right, result, ic);
9079       return;
9080     }
9081
9082   /* shift count is unknown then we have to form
9083      a loop get the loop count in B : Note: we take
9084      only the lower order byte since shifting
9085      more that 32 bits make no sense anyway, ( the
9086      largest size of an object can be only 32 bits ) */
9087
9088   pushedB = pushB ();
9089   MOVB (aopGet (right, 0, FALSE, FALSE));
9090   emitcode ("inc", "b");
9091   freeAsmop (right, NULL, ic, TRUE);
9092   aopOp (left, ic, FALSE);
9093   aopOp (result, ic, FALSE);
9094
9095   /* now move the left to the result if they are not the same */
9096   if (!sameRegs (AOP (left), AOP (result)) &&
9097       AOP_SIZE (result) > 1)
9098     {
9099
9100       size = AOP_SIZE (result);
9101       offset = 0;
9102       while (size--)
9103         {
9104           l = aopGet (left, offset, FALSE, TRUE);
9105           if (*l == '@' && (IS_AOP_PREG (result)))
9106             {
9107
9108               emitcode ("mov", "a,%s", l);
9109               aopPut (result, "a", offset);
9110             }
9111           else
9112             aopPut (result, l, offset);
9113           offset++;
9114         }
9115     }
9116
9117   tlbl = newiTempLabel (NULL);
9118   size = AOP_SIZE (result);
9119   offset = 0;
9120   tlbl1 = newiTempLabel (NULL);
9121
9122   /* if it is only one byte then */
9123   if (size == 1)
9124     {
9125       symbol *tlbl1 = newiTempLabel (NULL);
9126
9127       l = aopGet (left, 0, FALSE, FALSE);
9128       MOVA (l);
9129       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9130       emitLabel (tlbl);
9131       emitcode ("add", "a,acc");
9132       emitLabel (tlbl1);
9133       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9134       popB (pushedB);
9135       aopPut (result, "a", 0);
9136       goto release;
9137     }
9138
9139   reAdjustPreg (AOP (result));
9140
9141   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9142   emitLabel (tlbl);
9143   l = aopGet (result, offset, FALSE, FALSE);
9144   MOVA (l);
9145   emitcode ("add", "a,acc");
9146   aopPut (result, "a", offset++);
9147   while (--size)
9148     {
9149       l = aopGet (result, offset, FALSE, FALSE);
9150       MOVA (l);
9151       emitcode ("rlc", "a");
9152       aopPut (result, "a", offset++);
9153     }
9154   reAdjustPreg (AOP (result));
9155
9156   emitLabel (tlbl1);
9157   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9158   popB (pushedB);
9159 release:
9160   freeAsmop (result, NULL, ic, TRUE);
9161   freeAsmop (left, NULL, ic, TRUE);
9162 }
9163
9164 /*-----------------------------------------------------------------*/
9165 /* genrshOne - right shift a one byte quantity by known count      */
9166 /*-----------------------------------------------------------------*/
9167 static void
9168 genrshOne (operand * result, operand * left,
9169            int shCount, int sign)
9170 {
9171   D (emitcode (";", "genrshOne"));
9172
9173   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9174 }
9175
9176 /*-----------------------------------------------------------------*/
9177 /* genrshTwo - right shift two bytes by known amount != 0          */
9178 /*-----------------------------------------------------------------*/
9179 static void
9180 genrshTwo (operand * result, operand * left,
9181            int shCount, int sign)
9182 {
9183   D (emitcode (";", "genrshTwo"));
9184
9185   /* if shCount >= 8 */
9186   if (shCount >= 8)
9187     {
9188       shCount -= 8;
9189       if (shCount)
9190         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9191       else
9192         movLeft2Result (left, MSB16, result, LSB, sign);
9193       addSign (result, MSB16, sign);
9194     }
9195
9196   /*  1 <= shCount <= 7 */
9197   else
9198     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9199 }
9200
9201 /*-----------------------------------------------------------------*/
9202 /* shiftRLong - shift right one long from left to result           */
9203 /* offl = LSB or MSB16                                             */
9204 /*-----------------------------------------------------------------*/
9205 static void
9206 shiftRLong (operand * left, int offl,
9207             operand * result, int sign)
9208 {
9209   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9210
9211   if (overlapping && offl>1)
9212     {
9213       // we are in big trouble, but this shouldn't happen
9214       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9215     }
9216
9217   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9218
9219   if (offl==MSB16)
9220     {
9221       // shift is > 8
9222       if (sign)
9223         {
9224           emitcode ("rlc", "a");
9225           emitcode ("subb", "a,acc");
9226           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9227             {
9228               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9229             }
9230           else
9231             {
9232               aopPut (result, "a", MSB32);
9233               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9234             }
9235         }
9236       else
9237         {
9238           if (aopPutUsesAcc (result, zero, MSB32))
9239             {
9240               emitcode("xch", "a,b");
9241               aopPut (result, zero, MSB32);
9242               emitcode("xch", "a,b");
9243             }
9244           else
9245             {
9246               aopPut (result, zero, MSB32);
9247             }
9248         }
9249     }
9250
9251   if (!sign)
9252     {
9253       emitcode ("clr", "c");
9254     }
9255   else
9256     {
9257       emitcode ("mov", "c,acc.7");
9258     }
9259
9260   emitcode ("rrc", "a");
9261
9262   if (overlapping && offl==MSB16 &&
9263       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9264     {
9265       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9266     }
9267   else
9268     {
9269       aopPut (result, "a", MSB32 - offl);
9270       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9271     }
9272
9273   emitcode ("rrc", "a");
9274   if (overlapping && offl==MSB16 &&
9275       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9276     {
9277       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9278     }
9279   else
9280     {
9281       aopPut (result, "a", MSB24 - offl);
9282       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9283     }
9284
9285   emitcode ("rrc", "a");
9286   if (offl != LSB)
9287     {
9288       aopPut (result, "a", MSB16 - offl);
9289     }
9290   else
9291     {
9292       if (overlapping &&
9293           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9294         {
9295           xch_a_aopGet (left, LSB, FALSE, FALSE);
9296         }
9297       else
9298         {
9299           aopPut (result, "a", MSB16 - offl);
9300           MOVA (aopGet (left, LSB, FALSE, FALSE));
9301         }
9302       emitcode ("rrc", "a");
9303       aopPut (result, "a", LSB);
9304     }
9305 }
9306
9307 /*-----------------------------------------------------------------*/
9308 /* genrshFour - shift four byte by a known amount != 0             */
9309 /*-----------------------------------------------------------------*/
9310 static void
9311 genrshFour (operand * result, operand * left,
9312             int shCount, int sign)
9313 {
9314   D (emitcode (";", "genrshFour"));
9315
9316   /* if shifting more that 3 bytes */
9317   if (shCount >= 24)
9318     {
9319       shCount -= 24;
9320       if (shCount)
9321         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9322       else
9323         movLeft2Result (left, MSB32, result, LSB, sign);
9324       addSign (result, MSB16, sign);
9325     }
9326   else if (shCount >= 16)
9327     {
9328       shCount -= 16;
9329       if (shCount)
9330         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9331       else
9332         {
9333           movLeft2Result (left, MSB24, result, LSB, 0);
9334           movLeft2Result (left, MSB32, result, MSB16, sign);
9335         }
9336       addSign (result, MSB24, sign);
9337     }
9338   else if (shCount >= 8)
9339     {
9340       shCount -= 8;
9341       if (shCount == 1)
9342         {
9343           shiftRLong (left, MSB16, result, sign);
9344         }
9345       else if (shCount == 0)
9346         {
9347           movLeft2Result (left, MSB16, result, LSB, 0);
9348           movLeft2Result (left, MSB24, result, MSB16, 0);
9349           movLeft2Result (left, MSB32, result, MSB24, sign);
9350           addSign (result, MSB32, sign);
9351         }
9352       else
9353         {
9354           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9355           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9356           /* the last shift is signed */
9357           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9358           addSign (result, MSB32, sign);
9359         }
9360     }
9361   else
9362     {
9363       /* 1 <= shCount <= 7 */
9364       if (shCount <= 2)
9365         {
9366           shiftRLong (left, LSB, result, sign);
9367           if (shCount == 2)
9368             shiftRLong (result, LSB, result, sign);
9369         }
9370       else
9371         {
9372           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9373           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9374           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9375         }
9376     }
9377 }
9378
9379 /*-----------------------------------------------------------------*/
9380 /* genRightShiftLiteral - right shifting by known count            */
9381 /*-----------------------------------------------------------------*/
9382 static void
9383 genRightShiftLiteral (operand * left,
9384                       operand * right,
9385                       operand * result,
9386                       iCode * ic,
9387                       int sign)
9388 {
9389   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9390   int size;
9391
9392   D (emitcode (";", "genRightShiftLiteral"));
9393
9394   freeAsmop (right, NULL, ic, TRUE);
9395
9396   aopOp (left, ic, FALSE);
9397   aopOp (result, ic, FALSE);
9398
9399 #if VIEW_SIZE
9400   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9401             AOP_SIZE (left));
9402 #endif
9403
9404   size = getDataSize (left);
9405   /* test the LEFT size !!! */
9406
9407   /* I suppose that the left size >= result size */
9408   if (shCount == 0)
9409     {
9410       size = getDataSize (result);
9411       while (size--)
9412         movLeft2Result (left, size, result, size, 0);
9413     }
9414
9415   else if (shCount >= (size * 8))
9416     {
9417       if (sign)
9418         {
9419           /* get sign in acc.7 */
9420           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9421         }
9422       addSign (result, LSB, sign);
9423     }
9424   else
9425     {
9426       switch (size)
9427         {
9428         case 1:
9429           genrshOne (result, left, shCount, sign);
9430           break;
9431
9432         case 2:
9433           genrshTwo (result, left, shCount, sign);
9434           break;
9435
9436         case 4:
9437           genrshFour (result, left, shCount, sign);
9438           break;
9439         default:
9440           break;
9441         }
9442     }
9443   freeAsmop (result, NULL, ic, TRUE);
9444   freeAsmop (left, NULL, ic, TRUE);
9445 }
9446
9447 /*-----------------------------------------------------------------*/
9448 /* genSignedRightShift - right shift of signed number              */
9449 /*-----------------------------------------------------------------*/
9450 static void
9451 genSignedRightShift (iCode * ic)
9452 {
9453   operand *right, *left, *result;
9454   int size, offset;
9455   char *l;
9456   symbol *tlbl, *tlbl1;
9457   bool pushedB;
9458
9459   D (emitcode (";", "genSignedRightShift"));
9460
9461   /* we do it the hard way put the shift count in b
9462      and loop thru preserving the sign */
9463
9464   right = IC_RIGHT (ic);
9465   left = IC_LEFT (ic);
9466   result = IC_RESULT (ic);
9467
9468   aopOp (right, ic, FALSE);
9469
9470
9471   if (AOP_TYPE (right) == AOP_LIT)
9472     {
9473       genRightShiftLiteral (left, right, result, ic, 1);
9474       return;
9475     }
9476   /* shift count is unknown then we have to form
9477      a loop get the loop count in B : Note: we take
9478      only the lower order byte since shifting
9479      more that 32 bits make no sense anyway, ( the
9480      largest size of an object can be only 32 bits ) */
9481
9482   pushedB = pushB ();
9483   MOVB (aopGet (right, 0, FALSE, FALSE));
9484   emitcode ("inc", "b");
9485   freeAsmop (right, NULL, ic, TRUE);
9486   aopOp (left, ic, FALSE);
9487   aopOp (result, ic, FALSE);
9488
9489   /* now move the left to the result if they are not the
9490      same */
9491   if (!sameRegs (AOP (left), AOP (result)) &&
9492       AOP_SIZE (result) > 1)
9493     {
9494
9495       size = AOP_SIZE (result);
9496       offset = 0;
9497       while (size--)
9498         {
9499           l = aopGet (left, offset, FALSE, TRUE);
9500           if (*l == '@' && IS_AOP_PREG (result))
9501             {
9502
9503               emitcode ("mov", "a,%s", l);
9504               aopPut (result, "a", offset);
9505             }
9506           else
9507             aopPut (result, l, offset);
9508           offset++;
9509         }
9510     }
9511
9512   /* mov the highest order bit to OVR */
9513   tlbl = newiTempLabel (NULL);
9514   tlbl1 = newiTempLabel (NULL);
9515
9516   size = AOP_SIZE (result);
9517   offset = size - 1;
9518   MOVA (aopGet (left, offset, FALSE, FALSE));
9519   emitcode ("rlc", "a");
9520   emitcode ("mov", "ov,c");
9521   /* if it is only one byte then */
9522   if (size == 1)
9523     {
9524       l = aopGet (left, 0, FALSE, FALSE);
9525       MOVA (l);
9526       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9527       emitLabel (tlbl);
9528       emitcode ("mov", "c,ov");
9529       emitcode ("rrc", "a");
9530       emitLabel (tlbl1);
9531       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9532       popB (pushedB);
9533       aopPut (result, "a", 0);
9534       goto release;
9535     }
9536
9537   reAdjustPreg (AOP (result));
9538   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9539   emitLabel (tlbl);
9540   emitcode ("mov", "c,ov");
9541   while (size--)
9542     {
9543       l = aopGet (result, offset, FALSE, FALSE);
9544       MOVA (l);
9545       emitcode ("rrc", "a");
9546       aopPut (result, "a", offset--);
9547     }
9548   reAdjustPreg (AOP (result));
9549   emitLabel (tlbl1);
9550   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9551   popB (pushedB);
9552
9553 release:
9554   freeAsmop (result, NULL, ic, TRUE);
9555   freeAsmop (left, NULL, ic, TRUE);
9556 }
9557
9558 /*-----------------------------------------------------------------*/
9559 /* genRightShift - generate code for right shifting                */
9560 /*-----------------------------------------------------------------*/
9561 static void
9562 genRightShift (iCode * ic)
9563 {
9564   operand *right, *left, *result;
9565   sym_link *letype;
9566   int size, offset;
9567   char *l;
9568   symbol *tlbl, *tlbl1;
9569   bool pushedB;
9570
9571   D (emitcode (";", "genRightShift"));
9572
9573   /* if signed then we do it the hard way preserve the
9574      sign bit moving it inwards */
9575   letype = getSpec (operandType (IC_LEFT (ic)));
9576
9577   if (!SPEC_USIGN (letype))
9578     {
9579       genSignedRightShift (ic);
9580       return;
9581     }
9582
9583   /* signed & unsigned types are treated the same : i.e. the
9584      signed is NOT propagated inwards : quoting from the
9585      ANSI - standard : "for E1 >> E2, is equivalent to division
9586      by 2**E2 if unsigned or if it has a non-negative value,
9587      otherwise the result is implementation defined ", MY definition
9588      is that the sign does not get propagated */
9589
9590   right = IC_RIGHT (ic);
9591   left = IC_LEFT (ic);
9592   result = IC_RESULT (ic);
9593
9594   aopOp (right, ic, FALSE);
9595
9596   /* if the shift count is known then do it
9597      as efficiently as possible */
9598   if (AOP_TYPE (right) == AOP_LIT)
9599     {
9600       genRightShiftLiteral (left, right, result, ic, 0);
9601       return;
9602     }
9603
9604   /* shift count is unknown then we have to form
9605      a loop get the loop count in B : Note: we take
9606      only the lower order byte since shifting
9607      more that 32 bits make no sense anyway, ( the
9608      largest size of an object can be only 32 bits ) */
9609
9610   pushedB = pushB ();
9611   MOVB (aopGet (right, 0, FALSE, FALSE));
9612   emitcode ("inc", "b");
9613   freeAsmop (right, NULL, ic, TRUE);
9614   aopOp (left, ic, FALSE);
9615   aopOp (result, ic, FALSE);
9616
9617   /* now move the left to the result if they are not the
9618      same */
9619   if (!sameRegs (AOP (left), AOP (result)) &&
9620       AOP_SIZE (result) > 1)
9621     {
9622       size = AOP_SIZE (result);
9623       offset = 0;
9624       while (size--)
9625         {
9626           l = aopGet (left, offset, FALSE, TRUE);
9627           if (*l == '@' && IS_AOP_PREG (result))
9628             {
9629
9630               emitcode ("mov", "a,%s", l);
9631               aopPut (result, "a", offset);
9632             }
9633           else
9634             aopPut (result, l, offset);
9635           offset++;
9636         }
9637     }
9638
9639   tlbl = newiTempLabel (NULL);
9640   tlbl1 = newiTempLabel (NULL);
9641   size = AOP_SIZE (result);
9642   offset = size - 1;
9643
9644   /* if it is only one byte then */
9645   if (size == 1)
9646     {
9647       l = aopGet (left, 0, FALSE, FALSE);
9648       MOVA (l);
9649       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9650       emitLabel (tlbl);
9651       CLRC;
9652       emitcode ("rrc", "a");
9653       emitLabel (tlbl1);
9654       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9655       popB (pushedB);
9656       aopPut (result, "a", 0);
9657       goto release;
9658     }
9659
9660   reAdjustPreg (AOP (result));
9661   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9662   emitLabel (tlbl);
9663   CLRC;
9664   while (size--)
9665     {
9666       l = aopGet (result, offset, FALSE, FALSE);
9667       MOVA (l);
9668       emitcode ("rrc", "a");
9669       aopPut (result, "a", offset--);
9670     }
9671   reAdjustPreg (AOP (result));
9672
9673   emitLabel (tlbl1);
9674   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9675   popB (pushedB);
9676
9677 release:
9678   freeAsmop (result, NULL, ic, TRUE);
9679   freeAsmop (left, NULL, ic, TRUE);
9680 }
9681
9682 /*-----------------------------------------------------------------*/
9683 /* emitPtrByteGet - emits code to get a byte into A through a      */
9684 /*                  pointer register (R0, R1, or DPTR). The        */
9685 /*                  original value of A can be preserved in B.     */
9686 /*-----------------------------------------------------------------*/
9687 static void
9688 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9689 {
9690   switch (p_type)
9691     {
9692     case IPOINTER:
9693     case POINTER:
9694       if (preserveAinB)
9695         emitcode ("mov", "b,a");
9696       emitcode ("mov", "a,@%s", rname);
9697       break;
9698
9699     case PPOINTER:
9700       if (preserveAinB)
9701         emitcode ("mov", "b,a");
9702       emitcode ("movx", "a,@%s", rname);
9703       break;
9704
9705     case FPOINTER:
9706       if (preserveAinB)
9707         emitcode ("mov", "b,a");
9708       emitcode ("movx", "a,@dptr");
9709       break;
9710
9711     case CPOINTER:
9712       if (preserveAinB)
9713         emitcode ("mov", "b,a");
9714       emitcode ("clr", "a");
9715       emitcode ("movc", "a,@a+dptr");
9716       break;
9717
9718     case GPOINTER:
9719       if (preserveAinB)
9720         {
9721           emitcode ("push", "b");
9722           emitcode ("push", "acc");
9723         }
9724       emitcode ("lcall", "__gptrget");
9725       if (preserveAinB)
9726         emitcode ("pop", "b");
9727       break;
9728     }
9729 }
9730
9731 /*-----------------------------------------------------------------*/
9732 /* emitPtrByteSet - emits code to set a byte from src through a    */
9733 /*                  pointer register (R0, R1, or DPTR).            */
9734 /*-----------------------------------------------------------------*/
9735 static void
9736 emitPtrByteSet (char *rname, int p_type, char *src)
9737 {
9738   switch (p_type)
9739     {
9740     case IPOINTER:
9741     case POINTER:
9742       if (*src=='@')
9743         {
9744           MOVA (src);
9745           emitcode ("mov", "@%s,a", rname);
9746         }
9747       else
9748         emitcode ("mov", "@%s,%s", rname, src);
9749       break;
9750
9751     case PPOINTER:
9752       MOVA (src);
9753       emitcode ("movx", "@%s,a", rname);
9754       break;
9755
9756     case FPOINTER:
9757       MOVA (src);
9758       emitcode ("movx", "@dptr,a");
9759       break;
9760
9761     case GPOINTER:
9762       MOVA (src);
9763       emitcode ("lcall", "__gptrput");
9764       break;
9765     }
9766 }
9767
9768 /*-----------------------------------------------------------------*/
9769 /* genUnpackBits - generates code for unpacking bits               */
9770 /*-----------------------------------------------------------------*/
9771 static char*
9772 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9773 {
9774   int offset = 0;       /* result byte offset */
9775   int rsize;            /* result size */
9776   int rlen = 0;         /* remaining bitfield length */
9777   sym_link *etype;      /* bitfield type information */
9778   int blen;             /* bitfield length */
9779   int bstr;             /* bitfield starting bit within byte */
9780   static char* const accBits[] = {"acc.0", "acc.1", "acc.2", "acc.3",
9781                                   "acc.4", "acc.5", "acc.6", "acc.7"};
9782
9783   D(emitcode (";", "genUnpackBits"));
9784
9785   etype = getSpec (operandType (result));
9786   rsize = getSize (operandType (result));
9787   blen = SPEC_BLEN (etype);
9788   bstr = SPEC_BSTR (etype);
9789
9790   if (ifx && blen <= 8)
9791     {
9792       emitPtrByteGet (rname, ptype, FALSE);
9793       if (blen == 1)
9794         {
9795           return accBits[bstr];;
9796         }
9797       else
9798         {
9799           if (blen < 8)
9800             emitcode ("anl", "a,#0x%02x",
9801                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9802           return "a";
9803         }
9804     }
9805   wassert (!ifx);
9806
9807   /* If the bitfield length is less than a byte */
9808   if (blen < 8)
9809     {
9810       emitPtrByteGet (rname, ptype, FALSE);
9811       AccRol (8 - bstr);
9812       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9813       if (!SPEC_USIGN (etype))
9814         {
9815           /* signed bitfield */
9816           symbol *tlbl = newiTempLabel (NULL);
9817
9818           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9819           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9820           emitLabel (tlbl);
9821         }
9822       aopPut (result, "a", offset++);
9823       goto finish;
9824     }
9825
9826   /* Bit field did not fit in a byte. Copy all
9827      but the partial byte at the end.  */
9828   for (rlen=blen;rlen>=8;rlen-=8)
9829     {
9830       emitPtrByteGet (rname, ptype, FALSE);
9831       aopPut (result, "a", offset++);
9832       if (rlen>8)
9833         emitcode ("inc", "%s", rname);
9834     }
9835
9836   /* Handle the partial byte at the end */
9837   if (rlen)
9838     {
9839       emitPtrByteGet (rname, ptype, FALSE);
9840       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9841       if (!SPEC_USIGN (etype))
9842         {
9843           /* signed bitfield */
9844           symbol *tlbl = newiTempLabel (NULL);
9845
9846           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9847           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9848           emitLabel (tlbl);
9849         }
9850       aopPut (result, "a", offset++);
9851     }
9852
9853 finish:
9854   if (offset < rsize)
9855     {
9856       char *source;
9857
9858       if (SPEC_USIGN (etype))
9859         source = zero;
9860       else
9861         {
9862           /* signed bitfield: sign extension with 0x00 or 0xff */
9863           emitcode ("rlc", "a");
9864           emitcode ("subb", "a,acc");
9865
9866           source = "a";
9867         }
9868       rsize -= offset;
9869       while (rsize--)
9870         aopPut (result, source, offset++);
9871     }
9872   return NULL;
9873 }
9874
9875
9876 /*-----------------------------------------------------------------*/
9877 /* genDataPointerGet - generates code when ptr offset is known     */
9878 /*-----------------------------------------------------------------*/
9879 static void
9880 genDataPointerGet (operand * left,
9881                    operand * result,
9882                    iCode * ic)
9883 {
9884   char *l;
9885   char buffer[256];
9886   int size, offset = 0;
9887
9888   D (emitcode (";", "genDataPointerGet"));
9889
9890   aopOp (result, ic, TRUE);
9891
9892   /* get the string representation of the name */
9893   l = aopGet (left, 0, FALSE, TRUE);
9894   l++; // remove #
9895   size = AOP_SIZE (result);
9896   while (size--)
9897     {
9898       if (offset)
9899         {
9900           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9901         }
9902       else
9903         {
9904           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9905         }
9906       aopPut (result, buffer, offset++);
9907     }
9908
9909   freeAsmop (result, NULL, ic, TRUE);
9910   freeAsmop (left, NULL, ic, TRUE);
9911 }
9912
9913 /*-----------------------------------------------------------------*/
9914 /* genNearPointerGet - emitcode for near pointer fetch             */
9915 /*-----------------------------------------------------------------*/
9916 static void
9917 genNearPointerGet (operand * left,
9918                    operand * result,
9919                    iCode * ic,
9920                    iCode * pi,
9921                    iCode * ifx)
9922 {
9923   asmop *aop = NULL;
9924   regs *preg = NULL;
9925   char *rname;
9926   char *ifxCond = "a";
9927   sym_link *rtype, *retype;
9928   sym_link *ltype = operandType (left);
9929
9930   D (emitcode (";", "genNearPointerGet"));
9931
9932   rtype = operandType (result);
9933   retype = getSpec (rtype);
9934
9935   aopOp (left, ic, FALSE);
9936
9937   /* if left is rematerialisable and
9938      result is not bitfield variable type and
9939      the left is pointer to data space i.e
9940      lower 128 bytes of space */
9941   if (AOP_TYPE (left) == AOP_IMMD &&
9942       !IS_BITFIELD (retype) &&
9943       DCL_TYPE (ltype) == POINTER)
9944     {
9945       genDataPointerGet (left, result, ic);
9946       return;
9947     }
9948
9949   //aopOp (result, ic, FALSE);
9950   aopOp (result, ic, result?TRUE:FALSE);
9951
9952  /* if the value is already in a pointer register
9953      then don't need anything more */
9954   if (!AOP_INPREG (AOP (left)))
9955     {
9956       if (IS_AOP_PREG (left))
9957         {
9958           // Aha, it is a pointer, just in disguise.
9959           rname = aopGet (left, 0, FALSE, FALSE);
9960           if (*rname != '@')
9961             {
9962               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9963                       __FILE__, __LINE__);
9964             }
9965           else
9966             {
9967               // Expected case.
9968               emitcode ("mov", "a%s,%s", rname + 1, rname);
9969               rname++;  // skip the '@'.
9970             }
9971         }
9972       else
9973         {
9974           /* otherwise get a free pointer register */
9975           aop = newAsmop (0);
9976           preg = getFreePtr (ic, &aop, FALSE);
9977           emitcode ("mov", "%s,%s",
9978                     preg->name,
9979                     aopGet (left, 0, FALSE, TRUE));
9980           rname = preg->name;
9981         }
9982     }
9983   else
9984     rname = aopGet (left, 0, FALSE, FALSE);
9985
9986   /* if bitfield then unpack the bits */
9987   if (IS_BITFIELD (retype))
9988     ifxCond = genUnpackBits (result, rname, POINTER, ifx);
9989   else
9990     {
9991       /* we have can just get the values */
9992       int size = AOP_SIZE (result);
9993       int offset = 0;
9994
9995       while (size--)
9996         {
9997           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9998             {
9999
10000               emitcode ("mov", "a,@%s", rname);
10001               if (!ifx)
10002                 aopPut (result, "a", offset);
10003             }
10004           else
10005             {
10006               char buffer[80];
10007
10008               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10009               aopPut (result, buffer, offset);
10010             }
10011           offset++;
10012           if (size || pi)
10013             emitcode ("inc", "%s", rname);
10014         }
10015     }
10016
10017   /* now some housekeeping stuff */
10018   if (aop)       /* we had to allocate for this iCode */
10019     {
10020       if (pi) { /* post increment present */
10021         aopPut (left, rname, 0);
10022       }
10023       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10024     }
10025   else
10026     {
10027       /* we did not allocate which means left
10028          already in a pointer register, then
10029          if size > 0 && this could be used again
10030          we have to point it back to where it
10031          belongs */
10032       if ((AOP_SIZE (result) > 1 &&
10033            !OP_SYMBOL (left)->remat &&
10034            (OP_SYMBOL (left)->liveTo > ic->seq ||
10035             ic->depth)) &&
10036           !pi)
10037         {
10038           int size = AOP_SIZE (result) - 1;
10039           while (size--)
10040             emitcode ("dec", "%s", rname);
10041         }
10042     }
10043
10044   if (ifx && !ifx->generated)
10045     {
10046       genIfxJump (ifx, ifxCond, left, NULL, result);
10047     }
10048
10049   /* done */
10050   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10051   freeAsmop (left, NULL, ic, TRUE);
10052   if (pi) pi->generated = 1;
10053 }
10054
10055 /*-----------------------------------------------------------------*/
10056 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10057 /*-----------------------------------------------------------------*/
10058 static void
10059 genPagedPointerGet (operand * left,
10060                     operand * result,
10061                     iCode * ic,
10062                     iCode *pi,
10063                     iCode *ifx)
10064 {
10065   asmop *aop = NULL;
10066   regs *preg = NULL;
10067   char *rname;
10068   char *ifxCond = "a";
10069   sym_link *rtype, *retype;
10070
10071   D (emitcode (";", "genPagedPointerGet"));
10072
10073   rtype = operandType (result);
10074   retype = getSpec (rtype);
10075
10076   aopOp (left, ic, FALSE);
10077
10078   aopOp (result, ic, FALSE);
10079
10080   /* if the value is already in a pointer register
10081      then don't need anything more */
10082   if (!AOP_INPREG (AOP (left)))
10083     {
10084       /* otherwise get a free pointer register */
10085       aop = newAsmop (0);
10086       preg = getFreePtr (ic, &aop, FALSE);
10087       emitcode ("mov", "%s,%s",
10088                 preg->name,
10089                 aopGet (left, 0, FALSE, TRUE));
10090       rname = preg->name;
10091     }
10092   else
10093     rname = aopGet (left, 0, FALSE, FALSE);
10094
10095   /* if bitfield then unpack the bits */
10096   if (IS_BITFIELD (retype))
10097     ifxCond = genUnpackBits (result, rname, PPOINTER, ifx);
10098   else
10099     {
10100       /* we have can just get the values */
10101       int size = AOP_SIZE (result);
10102       int offset = 0;
10103
10104       while (size--)
10105         {
10106
10107           emitcode ("movx", "a,@%s", rname);
10108           if (!ifx)
10109             aopPut (result, "a", offset);
10110
10111           offset++;
10112
10113           if (size || pi)
10114             emitcode ("inc", "%s", rname);
10115         }
10116     }
10117
10118   /* now some housekeeping stuff */
10119   if (aop) /* we had to allocate for this iCode */
10120     {
10121       if (pi)
10122         aopPut (left, rname, 0);
10123       freeAsmop (NULL, aop, ic, TRUE);
10124     }
10125   else
10126     {
10127       /* we did not allocate which means left
10128          already in a pointer register, then
10129          if size > 0 && this could be used again
10130          we have to point it back to where it
10131          belongs */
10132       if ((AOP_SIZE (result) > 1 &&
10133            !OP_SYMBOL (left)->remat &&
10134            (OP_SYMBOL (left)->liveTo > ic->seq ||
10135             ic->depth)) &&
10136           !pi)
10137         {
10138           int size = AOP_SIZE (result) - 1;
10139           while (size--)
10140             emitcode ("dec", "%s", rname);
10141         }
10142     }
10143
10144   if (ifx && !ifx->generated)
10145     {
10146       genIfxJump (ifx, ifxCond, left, NULL, result);
10147     }
10148
10149   /* done */
10150   freeAsmop (result, NULL, ic, TRUE);
10151   freeAsmop (left, NULL, ic, TRUE);
10152   if (pi) pi->generated = 1;
10153 }
10154
10155 /*--------------------------------------------------------------------*/
10156 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10157 /*--------------------------------------------------------------------*/
10158 static void
10159 loadDptrFromOperand (operand *op, bool loadBToo)
10160 {
10161   if (AOP_TYPE (op) != AOP_STR)
10162     {
10163       /* if this is rematerializable */
10164       if (AOP_TYPE (op) == AOP_IMMD)
10165         {
10166           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10167           if (loadBToo)
10168             {
10169               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10170                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10171               else
10172                 {
10173                   wassertl(FALSE, "need pointerCode");
10174                   emitcode (";", "mov b,???");
10175                   /* genPointerGet and genPointerSet originally did different
10176                   ** things for this case. Both seem wrong.
10177                   ** from genPointerGet:
10178                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10179                   ** from genPointerSet:
10180                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10181                   */
10182                 }
10183             }
10184         }
10185       else if (AOP_TYPE (op) == AOP_DPTR)
10186         {
10187           if (loadBToo)
10188             {
10189               MOVA (aopGet (op, 0, FALSE, FALSE));
10190               emitcode ("push", "acc");
10191               MOVA (aopGet (op, 1, FALSE, FALSE));
10192               emitcode ("push", "acc");
10193               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10194               emitcode ("pop", "dph");
10195               emitcode ("pop", "dpl");
10196             }
10197           else
10198             {
10199               MOVA (aopGet (op, 0, FALSE, FALSE));
10200               emitcode ("push", "acc");
10201               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10202               emitcode ("pop", "dpl");
10203             }
10204         }
10205       else
10206         {                       /* we need to get it byte by byte */
10207           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10208           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10209           if (loadBToo)
10210             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10211         }
10212     }
10213 }
10214
10215 /*-----------------------------------------------------------------*/
10216 /* genFarPointerGet - get value from far space                     */
10217 /*-----------------------------------------------------------------*/
10218 static void
10219 genFarPointerGet (operand * left,
10220                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10221 {
10222   int size, offset;
10223   char *ifxCond = "a";
10224   sym_link *retype = getSpec (operandType (result));
10225
10226   D (emitcode (";", "genFarPointerGet"));
10227
10228   aopOp (left, ic, FALSE);
10229   loadDptrFromOperand (left, FALSE);
10230
10231   /* so dptr now contains the address */
10232   aopOp (result, ic, FALSE);
10233
10234   /* if bit then unpack */
10235   if (IS_BITFIELD (retype))
10236     ifxCond = genUnpackBits (result, "dptr", FPOINTER, ifx);
10237   else
10238     {
10239       size = AOP_SIZE (result);
10240       offset = 0;
10241
10242       while (size--)
10243         {
10244           emitcode ("movx", "a,@dptr");
10245           if (!ifx)
10246             aopPut (result, "a", offset++);
10247           if (size || pi)
10248             emitcode ("inc", "dptr");
10249         }
10250     }
10251
10252   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10253     {
10254       aopPut (left, "dpl", 0);
10255       aopPut (left, "dph", 1);
10256       pi->generated = 1;
10257     }
10258
10259   if (ifx && !ifx->generated)
10260     {
10261       genIfxJump (ifx, ifxCond, left, NULL, result);
10262     }
10263
10264   freeAsmop (result, NULL, ic, TRUE);
10265   freeAsmop (left, NULL, ic, TRUE);
10266 }
10267
10268 /*-----------------------------------------------------------------*/
10269 /* genCodePointerGet - get value from code space                   */
10270 /*-----------------------------------------------------------------*/
10271 static void
10272 genCodePointerGet (operand * left,
10273                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10274 {
10275   int size, offset;
10276   char *ifxCond = "a";
10277   sym_link *retype = getSpec (operandType (result));
10278
10279   D (emitcode (";", "genCodePointerGet"));
10280
10281   aopOp (left, ic, FALSE);
10282   loadDptrFromOperand (left, FALSE);
10283
10284   /* so dptr now contains the address */
10285   aopOp (result, ic, FALSE);
10286
10287   /* if bit then unpack */
10288   if (IS_BITFIELD (retype))
10289     ifxCond = genUnpackBits (result, "dptr", CPOINTER, ifx);
10290   else
10291     {
10292       size = AOP_SIZE (result);
10293       offset = 0;
10294
10295       while (size--)
10296         {
10297           emitcode ("clr", "a");
10298           emitcode ("movc", "a,@a+dptr");
10299           if (!ifx)
10300             aopPut (result, "a", offset++);
10301           if (size || pi)
10302             emitcode ("inc", "dptr");
10303         }
10304     }
10305
10306   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10307     {
10308       aopPut (left, "dpl", 0);
10309       aopPut (left, "dph", 1);
10310       pi->generated = 1;
10311     }
10312
10313   if (ifx && !ifx->generated)
10314     {
10315       genIfxJump (ifx, ifxCond, left, NULL, result);
10316     }
10317
10318   freeAsmop (result, NULL, ic, TRUE);
10319   freeAsmop (left, NULL, ic, TRUE);
10320 }
10321
10322 /*-----------------------------------------------------------------*/
10323 /* genGenPointerGet - get value from generic pointer space         */
10324 /*-----------------------------------------------------------------*/
10325 static void
10326 genGenPointerGet (operand * left,
10327                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10328 {
10329   int size, offset;
10330   char *ifxCond = "a";
10331   sym_link *retype = getSpec (operandType (result));
10332
10333   D (emitcode (";", "genGenPointerGet"));
10334
10335   aopOp (left, ic, FALSE);
10336   loadDptrFromOperand (left, TRUE);
10337
10338   /* so dptr now contains the address */
10339   aopOp (result, ic, FALSE);
10340
10341   /* if bit then unpack */
10342   if (IS_BITFIELD (retype))
10343     {
10344       ifxCond = genUnpackBits (result, "dptr", GPOINTER, ifx);
10345     }
10346   else
10347     {
10348       size = AOP_SIZE (result);
10349       offset = 0;
10350
10351       while (size--)
10352         {
10353           emitcode ("lcall", "__gptrget");
10354           if (!ifx)
10355             aopPut (result, "a", offset++);
10356           if (size || pi)
10357             emitcode ("inc", "dptr");
10358         }
10359     }
10360
10361   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10362     {
10363       aopPut (left, "dpl", 0);
10364       aopPut (left, "dph", 1);
10365       pi->generated = 1;
10366     }
10367
10368   if (ifx && !ifx->generated)
10369     {
10370       genIfxJump (ifx, ifxCond, left, NULL, result);
10371     }
10372
10373   freeAsmop (result, NULL, ic, TRUE);
10374   freeAsmop (left, NULL, ic, TRUE);
10375 }
10376
10377 /*-----------------------------------------------------------------*/
10378 /* genPointerGet - generate code for pointer get                   */
10379 /*-----------------------------------------------------------------*/
10380 static void
10381 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10382 {
10383   operand *left, *result;
10384   sym_link *type, *etype;
10385   int p_type;
10386
10387   D (emitcode (";", "genPointerGet"));
10388
10389   left = IC_LEFT (ic);
10390   result = IC_RESULT (ic);
10391
10392   if (getSize (operandType (result))>1)
10393     ifx = NULL;
10394
10395   /* depending on the type of pointer we need to
10396      move it to the correct pointer register */
10397   type = operandType (left);
10398   etype = getSpec (type);
10399   /* if left is of type of pointer then it is simple */
10400   if (IS_PTR (type) && !IS_FUNC (type->next))
10401     {
10402       p_type = DCL_TYPE (type);
10403     }
10404   else
10405     {
10406       /* we have to go by the storage class */
10407       p_type = PTR_TYPE (SPEC_OCLS (etype));
10408     }
10409
10410   /* special case when cast remat */
10411   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10412       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10413     {
10414       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10415       type = operandType (left);
10416       p_type = DCL_TYPE (type);
10417     }
10418   /* now that we have the pointer type we assign
10419      the pointer values */
10420   switch (p_type)
10421     {
10422
10423     case POINTER:
10424     case IPOINTER:
10425       genNearPointerGet (left, result, ic, pi, ifx);
10426       break;
10427
10428     case PPOINTER:
10429       genPagedPointerGet (left, result, ic, pi, ifx);
10430       break;
10431
10432     case FPOINTER:
10433       genFarPointerGet (left, result, ic, pi, ifx);
10434       break;
10435
10436     case CPOINTER:
10437       genCodePointerGet (left, result, ic, pi, ifx);
10438       break;
10439
10440     case GPOINTER:
10441       genGenPointerGet (left, result, ic, pi, ifx);
10442       break;
10443     }
10444 }
10445
10446
10447 /*-----------------------------------------------------------------*/
10448 /* genPackBits - generates code for packed bit storage             */
10449 /*-----------------------------------------------------------------*/
10450 static void
10451 genPackBits (sym_link * etype,
10452              operand * right,
10453              char *rname, int p_type)
10454 {
10455   int offset = 0;       /* source byte offset */
10456   int rlen = 0;         /* remaining bitfield length */
10457   int blen;             /* bitfield length */
10458   int bstr;             /* bitfield starting bit within byte */
10459   int litval;           /* source literal value (if AOP_LIT) */
10460   unsigned char mask;   /* bitmask within current byte */
10461
10462   D(emitcode (";", "genPackBits"));
10463
10464   blen = SPEC_BLEN (etype);
10465   bstr = SPEC_BSTR (etype);
10466
10467   /* If the bitfield length is less than a byte */
10468   if (blen < 8)
10469     {
10470       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10471               (unsigned char) (0xFF >> (8 - bstr)));
10472
10473       if (AOP_TYPE (right) == AOP_LIT)
10474         {
10475           /* Case with a bitfield length <8 and literal source
10476           */
10477           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10478           litval <<= bstr;
10479           litval &= (~mask) & 0xff;
10480           emitPtrByteGet (rname, p_type, FALSE);
10481           if ((mask|litval)!=0xff)
10482             emitcode ("anl","a,#0x%02x", mask);
10483           if (litval)
10484             emitcode ("orl","a,#0x%02x", litval);
10485         }
10486       else
10487         {
10488           if ((blen==1) && (p_type!=GPOINTER))
10489             {
10490               /* Case with a bitfield length == 1 and no generic pointer
10491               */
10492               if (AOP_TYPE (right) == AOP_CRY)
10493                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10494               else
10495                 {
10496                   MOVA (aopGet (right, 0, FALSE, FALSE));
10497                   emitcode ("rrc","a");
10498                 }
10499               emitPtrByteGet (rname, p_type, FALSE);
10500               emitcode ("mov","acc.%d,c",bstr);
10501             }
10502           else
10503             {
10504               bool pushedB;
10505               /* Case with a bitfield length < 8 and arbitrary source
10506               */
10507               MOVA (aopGet (right, 0, FALSE, FALSE));
10508               /* shift and mask source value */
10509               AccLsh (bstr);
10510               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10511
10512               pushedB = pushB ();
10513               /* transfer A to B and get next byte */
10514               emitPtrByteGet (rname, p_type, TRUE);
10515
10516               emitcode ("anl", "a,#0x%02x", mask);
10517               emitcode ("orl", "a,b");
10518               if (p_type == GPOINTER)
10519                 emitcode ("pop", "b");
10520
10521               popB (pushedB);
10522            }
10523         }
10524
10525       emitPtrByteSet (rname, p_type, "a");
10526       return;
10527     }
10528
10529   /* Bit length is greater than 7 bits. In this case, copy  */
10530   /* all except the partial byte at the end                 */
10531   for (rlen=blen;rlen>=8;rlen-=8)
10532     {
10533       emitPtrByteSet (rname, p_type,
10534                       aopGet (right, offset++, FALSE, TRUE) );
10535       if (rlen>8)
10536         emitcode ("inc", "%s", rname);
10537     }
10538
10539   /* If there was a partial byte at the end */
10540   if (rlen)
10541     {
10542       mask = (((unsigned char) -1 << rlen) & 0xff);
10543
10544       if (AOP_TYPE (right) == AOP_LIT)
10545         {
10546           /* Case with partial byte and literal source
10547           */
10548           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10549           litval >>= (blen-rlen);
10550           litval &= (~mask) & 0xff;
10551           emitPtrByteGet (rname, p_type, FALSE);
10552           if ((mask|litval)!=0xff)
10553             emitcode ("anl","a,#0x%02x", mask);
10554           if (litval)
10555             emitcode ("orl","a,#0x%02x", litval);
10556         }
10557       else
10558         {
10559           bool pushedB;
10560           /* Case with partial byte and arbitrary source
10561           */
10562           MOVA (aopGet (right, offset++, FALSE, FALSE));
10563           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10564
10565           pushedB = pushB ();
10566           /* transfer A to B and get next byte */
10567           emitPtrByteGet (rname, p_type, TRUE);
10568
10569           emitcode ("anl", "a,#0x%02x", mask);
10570           emitcode ("orl", "a,b");
10571           if (p_type == GPOINTER)
10572             emitcode ("pop", "b");
10573
10574           popB (pushedB);
10575         }
10576       emitPtrByteSet (rname, p_type, "a");
10577     }
10578 }
10579
10580
10581 /*-----------------------------------------------------------------*/
10582 /* genDataPointerSet - remat pointer to data space                 */
10583 /*-----------------------------------------------------------------*/
10584 static void
10585 genDataPointerSet (operand * right,
10586                    operand * result,
10587                    iCode * ic)
10588 {
10589   int size, offset = 0;
10590   char *l, buffer[256];
10591
10592   D (emitcode (";", "genDataPointerSet"));
10593
10594   aopOp (right, ic, FALSE);
10595
10596   l = aopGet (result, 0, FALSE, TRUE);
10597   l++; //remove #
10598   size = max (AOP_SIZE (right), AOP_SIZE (result));
10599   while (size--)
10600     {
10601       if (offset)
10602         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10603       else
10604         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10605       emitcode ("mov", "%s,%s", buffer,
10606                 aopGet (right, offset++, FALSE, FALSE));
10607     }
10608
10609   freeAsmop (right, NULL, ic, TRUE);
10610   freeAsmop (result, NULL, ic, TRUE);
10611 }
10612
10613 /*-----------------------------------------------------------------*/
10614 /* genNearPointerSet - emitcode for near pointer put               */
10615 /*-----------------------------------------------------------------*/
10616 static void
10617 genNearPointerSet (operand * right,
10618                    operand * result,
10619                    iCode * ic,
10620                    iCode * pi)
10621 {
10622   asmop *aop = NULL;
10623   regs *preg = NULL;
10624   char *rname, *l;
10625   sym_link *retype, *letype;
10626   sym_link *ptype = operandType (result);
10627
10628   D (emitcode (";", "genNearPointerSet"));
10629
10630   retype = getSpec (operandType (right));
10631   letype = getSpec (ptype);
10632
10633   aopOp (result, ic, FALSE);
10634
10635   /* if the result is rematerializable &
10636      in data space & not a bit variable */
10637   if (AOP_TYPE (result) == AOP_IMMD &&
10638       DCL_TYPE (ptype) == POINTER &&
10639       !IS_BITVAR (retype) &&
10640       !IS_BITVAR (letype))
10641     {
10642       genDataPointerSet (right, result, ic);
10643       return;
10644     }
10645
10646   /* if the value is already in a pointer register
10647      then don't need anything more */
10648   if (!AOP_INPREG (AOP (result)))
10649     {
10650       if (IS_AOP_PREG (result))
10651         {
10652           // Aha, it is a pointer, just in disguise.
10653           rname = aopGet (result, 0, FALSE, FALSE);
10654           if (*rname != '@')
10655             {
10656               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10657                       __FILE__, __LINE__);
10658             }
10659           else
10660             {
10661               // Expected case.
10662               emitcode ("mov", "a%s,%s", rname + 1, rname);
10663               rname++;  // skip the '@'.
10664             }
10665         }
10666       else
10667         {
10668           /* otherwise get a free pointer register */
10669           aop = newAsmop (0);
10670           preg = getFreePtr (ic, &aop, FALSE);
10671           emitcode ("mov", "%s,%s",
10672                     preg->name,
10673                     aopGet (result, 0, FALSE, TRUE));
10674           rname = preg->name;
10675         }
10676     }
10677   else
10678     {
10679       rname = aopGet (result, 0, FALSE, FALSE);
10680     }
10681
10682   aopOp (right, ic, FALSE);
10683
10684   /* if bitfield then unpack the bits */
10685   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10686     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10687   else
10688     {
10689       /* we can just get the values */
10690       int size = AOP_SIZE (right);
10691       int offset = 0;
10692
10693       while (size--)
10694         {
10695           l = aopGet (right, offset, FALSE, TRUE);
10696           if ((*l == '@') || (strcmp (l, "acc") == 0))
10697             {
10698               MOVA (l);
10699               emitcode ("mov", "@%s,a", rname);
10700             }
10701           else
10702             emitcode ("mov", "@%s,%s", rname, l);
10703           if (size || pi)
10704             emitcode ("inc", "%s", rname);
10705           offset++;
10706         }
10707     }
10708
10709   /* now some housekeeping stuff */
10710   if (aop) /* we had to allocate for this iCode */
10711     {
10712       if (pi)
10713         aopPut (result, rname, 0);
10714       freeAsmop (NULL, aop, ic, TRUE);
10715     }
10716   else
10717     {
10718       /* we did not allocate which means left
10719          already in a pointer register, then
10720          if size > 0 && this could be used again
10721          we have to point it back to where it
10722          belongs */
10723       if ((AOP_SIZE (right) > 1 &&
10724            !OP_SYMBOL (result)->remat &&
10725            (OP_SYMBOL (result)->liveTo > ic->seq ||
10726             ic->depth)) &&
10727           !pi)
10728         {
10729           int size = AOP_SIZE (right) - 1;
10730           while (size--)
10731             emitcode ("dec", "%s", rname);
10732         }
10733     }
10734
10735   /* done */
10736   if (pi)
10737     pi->generated = 1;
10738   freeAsmop (right, NULL, ic, TRUE);
10739   freeAsmop (result, NULL, ic, TRUE);
10740 }
10741
10742 /*-----------------------------------------------------------------*/
10743 /* genPagedPointerSet - emitcode for Paged pointer put             */
10744 /*-----------------------------------------------------------------*/
10745 static void
10746 genPagedPointerSet (operand * right,
10747                     operand * result,
10748                     iCode * ic,
10749                     iCode * pi)
10750 {
10751   asmop *aop = NULL;
10752   regs *preg = NULL;
10753   char *rname, *l;
10754   sym_link *retype, *letype;
10755
10756   D (emitcode (";", "genPagedPointerSet"));
10757
10758   retype = getSpec (operandType (right));
10759   letype = getSpec (operandType (result));
10760
10761   aopOp (result, ic, FALSE);
10762
10763   /* if the value is already in a pointer register
10764      then don't need anything more */
10765   if (!AOP_INPREG (AOP (result)))
10766     {
10767       if (IS_AOP_PREG (result))
10768         {
10769           // Aha, it is a pointer, just in disguise.
10770           rname = aopGet (result, 0, FALSE, FALSE);
10771           if (*rname != '@')
10772             {
10773               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10774                       __FILE__, __LINE__);
10775             }
10776           else
10777             {
10778               // Expected case.
10779               emitcode ("mov", "a%s,%s", rname + 1, rname);
10780               rname++;  // skip the '@'.
10781             }
10782         }
10783       else
10784         {
10785           /* otherwise get a free pointer register */
10786           aop = newAsmop (0);
10787           preg = getFreePtr (ic, &aop, FALSE);
10788           emitcode ("mov", "%s,%s",
10789                     preg->name,
10790                     aopGet (result, 0, FALSE, TRUE));
10791           rname = preg->name;
10792         }
10793     }
10794   else
10795     {
10796       rname = aopGet (result, 0, FALSE, FALSE);
10797     }
10798
10799   aopOp (right, ic, FALSE);
10800
10801   /* if bitfield then unpack the bits */
10802   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10803     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10804   else
10805     {
10806       /* we can just get the values */
10807       int size = AOP_SIZE (right);
10808       int offset = 0;
10809
10810       while (size--)
10811         {
10812           l = aopGet (right, offset, FALSE, TRUE);
10813           MOVA (l);
10814           emitcode ("movx", "@%s,a", rname);
10815           if (size || pi)
10816             emitcode ("inc", "%s", rname);
10817           offset++;
10818         }
10819     }
10820
10821   /* now some housekeeping stuff */
10822   if (aop) /* we had to allocate for this iCode */
10823     {
10824       if (pi)
10825         aopPut (result, rname, 0);
10826       freeAsmop (NULL, aop, ic, TRUE);
10827     }
10828   else
10829     {
10830       /* we did not allocate which means left
10831          already in a pointer register, then
10832          if size > 0 && this could be used again
10833          we have to point it back to where it
10834          belongs */
10835       if (AOP_SIZE (right) > 1 &&
10836           !OP_SYMBOL (result)->remat &&
10837           (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) &&
10838           !pi)
10839         {
10840           int size = AOP_SIZE (right) - 1;
10841           while (size--)
10842             emitcode ("dec", "%s", rname);
10843         }
10844     }
10845
10846   /* done */
10847   if (pi)
10848     pi->generated = 1;
10849   freeAsmop (right, NULL, ic, TRUE);
10850   freeAsmop (result, NULL, ic, TRUE);
10851 }
10852
10853 /*-----------------------------------------------------------------*/
10854 /* genFarPointerSet - set value from far space                     */
10855 /*-----------------------------------------------------------------*/
10856 static void
10857 genFarPointerSet (operand * right,
10858                   operand * result, iCode * ic, iCode * pi)
10859 {
10860   int size, offset;
10861   sym_link *retype = getSpec (operandType (right));
10862   sym_link *letype = getSpec (operandType (result));
10863
10864   D(emitcode (";", "genFarPointerSet"));
10865
10866   aopOp (result, ic, FALSE);
10867   loadDptrFromOperand (result, FALSE);
10868
10869   /* so dptr now contains the address */
10870   aopOp (right, ic, FALSE);
10871
10872   /* if bit then unpack */
10873   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10874     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10875   else
10876     {
10877       size = AOP_SIZE (right);
10878       offset = 0;
10879
10880       while (size--)
10881         {
10882           char *l = aopGet (right, offset++, FALSE, FALSE);
10883           MOVA (l);
10884           emitcode ("movx", "@dptr,a");
10885           if (size || pi)
10886             emitcode ("inc", "dptr");
10887         }
10888     }
10889   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10890     aopPut (result, "dpl", 0);
10891     aopPut (result, "dph", 1);
10892     pi->generated=1;
10893   }
10894   freeAsmop (result, NULL, ic, TRUE);
10895   freeAsmop (right, NULL, ic, TRUE);
10896 }
10897
10898 /*-----------------------------------------------------------------*/
10899 /* genGenPointerSet - set value from generic pointer space         */
10900 /*-----------------------------------------------------------------*/
10901 static void
10902 genGenPointerSet (operand * right,
10903                   operand * result, iCode * ic, iCode * pi)
10904 {
10905   int size, offset;
10906   sym_link *retype = getSpec (operandType (right));
10907   sym_link *letype = getSpec (operandType (result));
10908
10909   D (emitcode (";", "genGenPointerSet"));
10910
10911   aopOp (result, ic, FALSE);
10912   loadDptrFromOperand (result, TRUE);
10913
10914   /* so dptr now contains the address */
10915   aopOp (right, ic, FALSE);
10916
10917   /* if bit then unpack */
10918   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10919     {
10920       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10921     }
10922   else
10923     {
10924       size = AOP_SIZE (right);
10925       offset = 0;
10926
10927       while (size--)
10928         {
10929           char *l = aopGet (right, offset++, FALSE, FALSE);
10930           MOVA (l);
10931           emitcode ("lcall", "__gptrput");
10932           if (size || pi)
10933             emitcode ("inc", "dptr");
10934         }
10935     }
10936
10937   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10938     aopPut (result, "dpl", 0);
10939     aopPut (result, "dph", 1);
10940     pi->generated=1;
10941   }
10942   freeAsmop (result, NULL, ic, TRUE);
10943   freeAsmop (right, NULL, ic, TRUE);
10944 }
10945
10946 /*-----------------------------------------------------------------*/
10947 /* genPointerSet - stores the value into a pointer location        */
10948 /*-----------------------------------------------------------------*/
10949 static void
10950 genPointerSet (iCode * ic, iCode *pi)
10951 {
10952   operand *right, *result;
10953   sym_link *type, *etype;
10954   int p_type;
10955
10956   D (emitcode (";", "genPointerSet"));
10957
10958   right = IC_RIGHT (ic);
10959   result = IC_RESULT (ic);
10960
10961   /* depending on the type of pointer we need to
10962      move it to the correct pointer register */
10963   type = operandType (result);
10964   etype = getSpec (type);
10965   /* if left is of type of pointer then it is simple */
10966   if (IS_PTR (type) && !IS_FUNC (type->next))
10967     {
10968       p_type = DCL_TYPE (type);
10969     }
10970   else
10971     {
10972       /* we have to go by the storage class */
10973       p_type = PTR_TYPE (SPEC_OCLS (etype));
10974     }
10975
10976   /* special case when cast remat */
10977   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10978       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10979           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10980           type = operandType (result);
10981           p_type = DCL_TYPE (type);
10982   }
10983
10984   /* now that we have the pointer type we assign
10985      the pointer values */
10986   switch (p_type)
10987     {
10988
10989     case POINTER:
10990     case IPOINTER:
10991       genNearPointerSet (right, result, ic, pi);
10992       break;
10993
10994     case PPOINTER:
10995       genPagedPointerSet (right, result, ic, pi);
10996       break;
10997
10998     case FPOINTER:
10999       genFarPointerSet (right, result, ic, pi);
11000       break;
11001
11002     case GPOINTER:
11003       genGenPointerSet (right, result, ic, pi);
11004       break;
11005
11006     default:
11007       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11008               "genPointerSet: illegal pointer type");
11009     }
11010 }
11011
11012 /*-----------------------------------------------------------------*/
11013 /* genIfx - generate code for Ifx statement                        */
11014 /*-----------------------------------------------------------------*/
11015 static void
11016 genIfx (iCode * ic, iCode * popIc)
11017 {
11018   operand *cond = IC_COND (ic);
11019   int isbit = 0;
11020   char *dup = NULL;
11021
11022   D (emitcode (";", "genIfx"));
11023
11024   aopOp (cond, ic, FALSE);
11025
11026   /* get the value into acc */
11027   if (AOP_TYPE (cond) != AOP_CRY)
11028     {
11029       toBoolean (cond);
11030     }
11031   else
11032     {
11033       isbit = 1;
11034       if (AOP(cond)->aopu.aop_dir)
11035         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11036     }
11037
11038   /* the result is now in the accumulator or a directly addressable bit */
11039   freeAsmop (cond, NULL, ic, TRUE);
11040
11041   /* if there was something to be popped then do it */
11042   if (popIc)
11043       genIpop (popIc);
11044
11045   /* if the condition is a bit variable */
11046   if (isbit && dup)
11047     genIfxJump(ic, dup, NULL, NULL, NULL);
11048   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11049     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
11050   else if (isbit && !IS_ITEMP (cond))
11051     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
11052   else
11053     genIfxJump (ic, "a", NULL, NULL, NULL);
11054
11055   ic->generated = 1;
11056 }
11057
11058 /*-----------------------------------------------------------------*/
11059 /* genAddrOf - generates code for address of                       */
11060 /*-----------------------------------------------------------------*/
11061 static void
11062 genAddrOf (iCode * ic)
11063 {
11064   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11065   int size, offset;
11066
11067   D (emitcode (";", "genAddrOf"));
11068
11069   aopOp (IC_RESULT (ic), ic, FALSE);
11070
11071   /* if the operand is on the stack then we
11072      need to get the stack offset of this
11073      variable */
11074   if (sym->onStack)
11075     {
11076       /* if it has an offset then we need to compute it */
11077       if (sym->stack)
11078         {
11079           int stack_offset = ((sym->stack < 0) ?
11080                               ((char) (sym->stack - _G.nRegsSaved)) :
11081                               ((char) sym->stack)) & 0xff;
11082           if ((abs(stack_offset) == 1) &&
11083               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11084               !isOperandVolatile (IC_RESULT (ic), FALSE))
11085             {
11086               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11087               if (stack_offset > 0)
11088                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11089               else
11090                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11091             }
11092           else
11093             {
11094               emitcode ("mov", "a,%s", SYM_BP (sym));
11095               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11096               aopPut (IC_RESULT (ic), "a", 0);
11097             }
11098         }
11099       else
11100         {
11101           /* we can just move _bp */
11102           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11103         }
11104       /* fill the result with zero */
11105       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11106
11107       offset = 1;
11108       while (size--)
11109         {
11110           aopPut (IC_RESULT (ic), zero, offset++);
11111         }
11112       goto release;
11113     }
11114
11115   /* object not on stack then we need the name */
11116   size = getDataSize (IC_RESULT (ic));
11117   offset = 0;
11118
11119   while (size--)
11120     {
11121       char s[SDCC_NAME_MAX];
11122       if (offset)
11123         sprintf (s, "#(%s >> %d)",
11124                  sym->rname,
11125                  offset * 8);
11126       else
11127         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11128       aopPut (IC_RESULT (ic), s, offset++);
11129     }
11130   if (opIsGptr (IC_RESULT (ic)))
11131     {
11132       char buffer[10];
11133       SNPRINTF (buffer, sizeof(buffer),
11134                 "#0x%02x", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
11135       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
11136     }
11137
11138 release:
11139   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11140
11141 }
11142
11143 /*-----------------------------------------------------------------*/
11144 /* genFarFarAssign - assignment when both are in far space         */
11145 /*-----------------------------------------------------------------*/
11146 static void
11147 genFarFarAssign (operand * result, operand * right, iCode * ic)
11148 {
11149   int size = AOP_SIZE (right);
11150   int offset = 0;
11151   char *l;
11152
11153   D (emitcode (";", "genFarFarAssign"));
11154
11155   /* first push the right side on to the stack */
11156   while (size--)
11157     {
11158       l = aopGet (right, offset++, FALSE, FALSE);
11159       MOVA (l);
11160       emitcode ("push", "acc");
11161     }
11162
11163   freeAsmop (right, NULL, ic, FALSE);
11164   /* now assign DPTR to result */
11165   aopOp (result, ic, FALSE);
11166   size = AOP_SIZE (result);
11167   while (size--)
11168     {
11169       emitcode ("pop", "acc");
11170       aopPut (result, "a", --offset);
11171     }
11172   freeAsmop (result, NULL, ic, FALSE);
11173 }
11174
11175 /*-----------------------------------------------------------------*/
11176 /* genAssign - generate code for assignment                        */
11177 /*-----------------------------------------------------------------*/
11178 static void
11179 genAssign (iCode * ic)
11180 {
11181   operand *result, *right;
11182   int size, offset;
11183   unsigned long lit = 0L;
11184
11185   D (emitcode (";", "genAssign"));
11186
11187   result = IC_RESULT (ic);
11188   right = IC_RIGHT (ic);
11189
11190   /* if they are the same */
11191   if (operandsEqu (result, right) &&
11192       !isOperandVolatile (result, FALSE) &&
11193       !isOperandVolatile (right, FALSE))
11194     return;
11195
11196   aopOp (right, ic, FALSE);
11197
11198   /* special case both in far space */
11199   if (AOP_TYPE (right) == AOP_DPTR &&
11200       IS_TRUE_SYMOP (result) &&
11201       isOperandInFarSpace (result))
11202     {
11203       genFarFarAssign (result, right, ic);
11204       return;
11205     }
11206
11207   aopOp (result, ic, TRUE);
11208
11209   /* if they are the same registers */
11210   if (sameRegs (AOP (right), AOP (result)) &&
11211       !isOperandVolatile (result, FALSE) &&
11212       !isOperandVolatile (right, FALSE))
11213     goto release;
11214
11215   /* if the result is a bit */
11216   if (AOP_TYPE (result) == AOP_CRY)
11217     {
11218       assignBit (result, right);
11219       goto release;
11220     }
11221
11222   /* bit variables done */
11223   /* general case */
11224   size = getDataSize (result);
11225   offset = 0;
11226   if (AOP_TYPE (right) == AOP_LIT)
11227     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11228
11229   if ((size > 1) &&
11230       (AOP_TYPE (result) != AOP_REG) &&
11231       (AOP_TYPE (right) == AOP_LIT) &&
11232       !IS_FLOAT (operandType (right)) &&
11233       (lit < 256L))
11234     {
11235       while ((size) && (lit))
11236         {
11237           aopPut (result,
11238                   aopGet (right, offset, FALSE, FALSE),
11239                   offset);
11240           lit >>= 8;
11241           offset++;
11242           size--;
11243         }
11244       /* And now fill the rest with zeros. */
11245       if (size)
11246         {
11247           emitcode ("clr", "a");
11248         }
11249       while (size--)
11250         {
11251           aopPut (result, "a", offset);
11252           offset++;
11253         }
11254     }
11255   else
11256     {
11257       while (size--)
11258         {
11259           aopPut (result,
11260                   aopGet (right, offset, FALSE, FALSE),
11261                   offset);
11262           offset++;
11263         }
11264     }
11265   adjustArithmeticResult (ic);
11266
11267 release:
11268   freeAsmop (result, NULL, ic, TRUE);
11269   freeAsmop (right, NULL, ic, TRUE);
11270 }
11271
11272 /*-----------------------------------------------------------------*/
11273 /* genJumpTab - generates code for jump table                      */
11274 /*-----------------------------------------------------------------*/
11275 static void
11276 genJumpTab (iCode * ic)
11277 {
11278   symbol *jtab,*jtablo,*jtabhi;
11279   char *l;
11280   unsigned int count;
11281
11282   D (emitcode (";", "genJumpTab"));
11283
11284   count = elementsInSet( IC_JTLABELS (ic) );
11285
11286   if( count <= 16 )
11287     {
11288       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11289          if the switch argument is in a register.
11290          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11291       /* Peephole may not convert ljmp to sjmp or ret
11292          labelIsReturnOnly & labelInRange must check
11293          currPl->ic->op != JUMPTABLE */
11294       aopOp (IC_JTCOND (ic), ic, FALSE);
11295       /* get the condition into accumulator */
11296       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11297       MOVA (l);
11298       /* multiply by three */
11299       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11300         {
11301           emitcode ("mov", "b,#0x03");
11302           emitcode ("mul", "ab");
11303         }
11304       else
11305         {
11306           emitcode ("add", "a,acc");
11307           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11308         }
11309       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11310
11311       jtab = newiTempLabel (NULL);
11312       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11313       emitcode ("jmp", "@a+dptr");
11314       emitLabel (jtab);
11315       /* now generate the jump labels */
11316       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11317            jtab = setNextItem (IC_JTLABELS (ic)))
11318         emitcode ("ljmp", "%05d$", jtab->key + 100);
11319     }
11320   else
11321     {
11322       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11323          if the switch argument is in a register.
11324          For n>6 this algorithm may be more compact */
11325       jtablo = newiTempLabel (NULL);
11326       jtabhi = newiTempLabel (NULL);
11327
11328       /* get the condition into accumulator.
11329          Using b as temporary storage, if register push/pop is needed */
11330       aopOp (IC_JTCOND (ic), ic, FALSE);
11331       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11332       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11333           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11334         {
11335           // (MB) what if B is in use???
11336           wassertl(!BINUSE, "B was in use");
11337           emitcode ("mov", "b,%s", l);
11338           l = "b";
11339         }
11340       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11341       MOVA (l);
11342       if( count <= 112 )
11343         {
11344           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11345           emitcode ("movc", "a,@a+pc");
11346           emitcode ("push", "acc");
11347
11348           MOVA (l);
11349           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11350           emitcode ("movc", "a,@a+pc");
11351           emitcode ("push", "acc");
11352         }
11353       else
11354         {
11355           /* this scales up to n<=255, but needs two more bytes
11356              and changes dptr */
11357           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11358           emitcode ("movc", "a,@a+dptr");
11359           emitcode ("push", "acc");
11360
11361           MOVA (l);
11362           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11363           emitcode ("movc", "a,@a+dptr");
11364           emitcode ("push", "acc");
11365         }
11366
11367       emitcode ("ret", "");
11368
11369       /* now generate jump table, LSB */
11370       emitLabel (jtablo);
11371       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11372            jtab = setNextItem (IC_JTLABELS (ic)))
11373         emitcode (".db", "%05d$", jtab->key + 100);
11374
11375       /* now generate jump table, MSB */
11376       emitLabel (jtabhi);
11377       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11378            jtab = setNextItem (IC_JTLABELS (ic)))
11379          emitcode (".db", "%05d$>>8", jtab->key + 100);
11380     }
11381 }
11382
11383 /*-----------------------------------------------------------------*/
11384 /* genCast - gen code for casting                                  */
11385 /*-----------------------------------------------------------------*/
11386 static void
11387 genCast (iCode * ic)
11388 {
11389   operand *result = IC_RESULT (ic);
11390   sym_link *ctype = operandType (IC_LEFT (ic));
11391   sym_link *rtype = operandType (IC_RIGHT (ic));
11392   operand *right = IC_RIGHT (ic);
11393   int size, offset;
11394
11395   D (emitcode (";", "genCast"));
11396
11397   /* if they are equivalent then do nothing */
11398   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11399     return;
11400
11401   aopOp (right, ic, FALSE);
11402   aopOp (result, ic, FALSE);
11403
11404   /* if the result is a bit (and not a bitfield) */
11405   if (IS_BIT (OP_SYMBOL (result)->type))
11406     {
11407       assignBit (result, right);
11408       goto release;
11409     }
11410
11411   /* if they are the same size : or less */
11412   if (AOP_SIZE (result) <= AOP_SIZE (right))
11413     {
11414
11415       /* if they are in the same place */
11416       if (sameRegs (AOP (right), AOP (result)))
11417         goto release;
11418
11419       /* if they in different places then copy */
11420       size = AOP_SIZE (result);
11421       offset = 0;
11422       while (size--)
11423         {
11424           aopPut (result,
11425                   aopGet (right, offset, FALSE, FALSE),
11426                   offset);
11427           offset++;
11428         }
11429       goto release;
11430     }
11431
11432   /* if the result is of type pointer */
11433   if (IS_PTR (ctype))
11434     {
11435
11436       int p_type;
11437       sym_link *type = operandType (right);
11438       sym_link *etype = getSpec (type);
11439
11440       /* pointer to generic pointer */
11441       if (IS_GENPTR (ctype))
11442         {
11443           if (IS_PTR (type))
11444             {
11445               p_type = DCL_TYPE (type);
11446             }
11447           else
11448             {
11449               if (SPEC_SCLS(etype)==S_REGISTER) {
11450                 // let's assume it is a generic pointer
11451                 p_type=GPOINTER;
11452               } else {
11453                 /* we have to go by the storage class */
11454                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11455               }
11456             }
11457
11458           /* the first two bytes are known */
11459           size = GPTRSIZE - 1;
11460           offset = 0;
11461           while (size--)
11462             {
11463               aopPut (result,
11464                       aopGet (right, offset, FALSE, FALSE),
11465                       offset);
11466               offset++;
11467             }
11468           /* the last byte depending on type */
11469             {
11470                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11471                 char gpValStr[10];
11472
11473                 if (gpVal == -1)
11474                 {
11475                     // pointerTypeToGPByte will have bitched.
11476                     exit(1);
11477                 }
11478
11479                 sprintf(gpValStr, "#0x%02x", gpVal);
11480                 aopPut (result, gpValStr, GPTRSIZE - 1);
11481             }
11482           goto release;
11483         }
11484
11485       /* just copy the pointers */
11486       size = AOP_SIZE (result);
11487       offset = 0;
11488       while (size--)
11489         {
11490           aopPut (result,
11491                   aopGet (right, offset, FALSE, FALSE),
11492                   offset);
11493           offset++;
11494         }
11495       goto release;
11496     }
11497
11498   /* so we now know that the size of destination is greater
11499      than the size of the source */
11500   /* we move to result for the size of source */
11501   size = AOP_SIZE (right);
11502   offset = 0;
11503   while (size--)
11504     {
11505       aopPut (result,
11506               aopGet (right, offset, FALSE, FALSE),
11507               offset);
11508       offset++;
11509     }
11510
11511   /* now depending on the sign of the source && destination */
11512   size = AOP_SIZE (result) - AOP_SIZE (right);
11513   /* if unsigned or not an integral type */
11514   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11515     {
11516       while (size--)
11517         aopPut (result, zero, offset++);
11518     }
11519   else
11520     {
11521       /* we need to extend the sign :{ */
11522       char *l = aopGet (right, AOP_SIZE (right) - 1,
11523                         FALSE, FALSE);
11524       MOVA (l);
11525       emitcode ("rlc", "a");
11526       emitcode ("subb", "a,acc");
11527       while (size--)
11528         aopPut (result, "a", offset++);
11529     }
11530
11531   /* we are done hurray !!!! */
11532
11533 release:
11534   freeAsmop (result, NULL, ic, TRUE);
11535   freeAsmop (right, NULL, ic, TRUE);
11536 }
11537
11538 /*-----------------------------------------------------------------*/
11539 /* genDjnz - generate decrement & jump if not zero instrucion      */
11540 /*-----------------------------------------------------------------*/
11541 static int
11542 genDjnz (iCode * ic, iCode * ifx)
11543 {
11544   symbol *lbl, *lbl1;
11545   if (!ifx)
11546     return 0;
11547
11548   /* if the if condition has a false label
11549      then we cannot save */
11550   if (IC_FALSE (ifx))
11551     return 0;
11552
11553   /* if the minus is not of the form a = a - 1 */
11554   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11555       !IS_OP_LITERAL (IC_RIGHT (ic)))
11556     return 0;
11557
11558   if (operandLitValue (IC_RIGHT (ic)) != 1)
11559     return 0;
11560
11561   /* if the size of this greater than one then no
11562      saving */
11563   if (getSize (operandType (IC_RESULT (ic))) > 1)
11564     return 0;
11565
11566   /* otherwise we can save BIG */
11567
11568   D (emitcode (";", "genDjnz"));
11569
11570   lbl = newiTempLabel (NULL);
11571   lbl1 = newiTempLabel (NULL);
11572
11573   aopOp (IC_RESULT (ic), ic, FALSE);
11574
11575   if (AOP_NEEDSACC(IC_RESULT(ic)))
11576   {
11577       /* If the result is accessed indirectly via
11578        * the accumulator, we must explicitly write
11579        * it back after the decrement.
11580        */
11581       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11582
11583       if (strcmp(rByte, "a"))
11584       {
11585            /* Something is hopelessly wrong */
11586            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11587                    __FILE__, __LINE__);
11588            /* We can just give up; the generated code will be inefficient,
11589             * but what the hey.
11590             */
11591            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11592            return 0;
11593       }
11594       emitcode ("dec", "%s", rByte);
11595       aopPut (IC_RESULT (ic), rByte, 0);
11596       emitcode ("jnz", "%05d$", lbl->key + 100);
11597   }
11598   else if (IS_AOP_PREG (IC_RESULT (ic)))
11599     {
11600       emitcode ("dec", "%s",
11601                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11602       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11603       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11604       ifx->generated = 1;
11605       emitcode ("jnz", "%05d$", lbl->key + 100);
11606     }
11607   else
11608     {
11609       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11610                 lbl->key + 100);
11611     }
11612   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11613   emitLabel (lbl);
11614   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11615   emitLabel (lbl1);
11616
11617   if (!ifx->generated)
11618       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11619   ifx->generated = 1;
11620   return 1;
11621 }
11622
11623 /*-----------------------------------------------------------------*/
11624 /* genReceive - generate code for a receive iCode                  */
11625 /*-----------------------------------------------------------------*/
11626 static void
11627 genReceive (iCode * ic)
11628 {
11629   int size = getSize (operandType (IC_RESULT (ic)));
11630   int offset = 0;
11631
11632   D (emitcode (";", "genReceive"));
11633
11634   if (ic->argreg == 1)
11635     { /* first parameter */
11636       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11637            isOperandInPagedSpace (IC_RESULT (ic))) &&
11638           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11639            IS_TRUE_SYMOP (IC_RESULT (ic))))
11640         {
11641           regs *tempRegs[4];
11642           int receivingA = 0;
11643           int roffset = 0;
11644
11645           for (offset = 0; offset<size; offset++)
11646             if (!strcmp (fReturn[offset], "a"))
11647               receivingA = 1;
11648
11649           if (!receivingA)
11650             {
11651               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11652                 {
11653                   for (offset = size-1; offset>0; offset--)
11654                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11655                   emitcode("mov","a,%s", fReturn[0]);
11656                   _G.accInUse++;
11657                   aopOp (IC_RESULT (ic), ic, FALSE);
11658                   _G.accInUse--;
11659                   aopPut (IC_RESULT (ic), "a", offset);
11660                   for (offset = 1; offset<size; offset++)
11661                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11662                   goto release;
11663                 }
11664             }
11665           else
11666             {
11667               if (getTempRegs(tempRegs, size, ic))
11668                 {
11669                   for (offset = 0; offset<size; offset++)
11670                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11671                   aopOp (IC_RESULT (ic), ic, FALSE);
11672                   for (offset = 0; offset<size; offset++)
11673                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11674                   goto release;
11675                 }
11676             }
11677
11678           offset = fReturnSizeMCS51 - size;
11679           while (size--)
11680             {
11681               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11682                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11683               offset++;
11684             }
11685           aopOp (IC_RESULT (ic), ic, FALSE);
11686           size = AOP_SIZE (IC_RESULT (ic));
11687           offset = 0;
11688           while (size--)
11689             {
11690               emitcode ("pop", "acc");
11691               aopPut (IC_RESULT (ic), "a", offset++);
11692             }
11693         }
11694       else
11695         {
11696           _G.accInUse++;
11697           aopOp (IC_RESULT (ic), ic, FALSE);
11698           _G.accInUse--;
11699           assignResultValue (IC_RESULT (ic), NULL);
11700         }
11701     }
11702   else if (ic->argreg > 12)
11703     { /* bit parameters */
11704       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11705
11706       BitBankUsed = 1;
11707       if (!reg || reg->rIdx != ic->argreg-5)
11708         {
11709           aopOp (IC_RESULT (ic), ic, FALSE);
11710           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11711           outBitC(IC_RESULT (ic));
11712         }
11713     }
11714   else
11715     { /* other parameters */
11716       int rb1off ;
11717       aopOp (IC_RESULT (ic), ic, FALSE);
11718       rb1off = ic->argreg;
11719       while (size--)
11720         {
11721           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11722         }
11723     }
11724
11725 release:
11726   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11727 }
11728
11729 /*-----------------------------------------------------------------*/
11730 /* genDummyRead - generate code for dummy read of volatiles        */
11731 /*-----------------------------------------------------------------*/
11732 static void
11733 genDummyRead (iCode * ic)
11734 {
11735   operand *op;
11736   int size, offset;
11737
11738   D (emitcode(";", "genDummyRead"));
11739
11740   op = IC_RIGHT (ic);
11741   if (op && IS_SYMOP (op))
11742     {
11743       aopOp (op, ic, FALSE);
11744
11745       /* if the result is a bit */
11746       if (AOP_TYPE (op) == AOP_CRY)
11747         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11748       else
11749         {
11750           /* bit variables done */
11751           /* general case */
11752           size = AOP_SIZE (op);
11753           offset = 0;
11754           while (size--)
11755           {
11756             MOVA (aopGet (op, offset, FALSE, FALSE));
11757             offset++;
11758           }
11759         }
11760
11761       freeAsmop (op, NULL, ic, TRUE);
11762     }
11763
11764   op = IC_LEFT (ic);
11765   if (op && IS_SYMOP (op))
11766     {
11767       aopOp (op, ic, FALSE);
11768
11769       /* if the result is a bit */
11770       if (AOP_TYPE (op) == AOP_CRY)
11771         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11772       else
11773         {
11774           /* bit variables done */
11775           /* general case */
11776           size = AOP_SIZE (op);
11777           offset = 0;
11778           while (size--)
11779           {
11780             MOVA (aopGet (op, offset, FALSE, FALSE));
11781             offset++;
11782           }
11783         }
11784
11785       freeAsmop (op, NULL, ic, TRUE);
11786     }
11787 }
11788
11789 /*-----------------------------------------------------------------*/
11790 /* genCritical - generate code for start of a critical sequence    */
11791 /*-----------------------------------------------------------------*/
11792 static void
11793 genCritical (iCode *ic)
11794 {
11795   symbol *tlbl = newiTempLabel (NULL);
11796
11797   D (emitcode(";", "genCritical"));
11798
11799   if (IC_RESULT (ic))
11800     {
11801       aopOp (IC_RESULT (ic), ic, TRUE);
11802       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11803       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11804       aopPut (IC_RESULT (ic), zero, 0);
11805       emitLabel (tlbl);
11806       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11807     }
11808   else
11809     {
11810       emitcode ("setb", "c");
11811       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11812       emitcode ("clr", "c");
11813       emitLabel (tlbl);
11814       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11815     }
11816 }
11817
11818 /*-----------------------------------------------------------------*/
11819 /* genEndCritical - generate code for end of a critical sequence   */
11820 /*-----------------------------------------------------------------*/
11821 static void
11822 genEndCritical (iCode *ic)
11823 {
11824   D(emitcode(";", "genEndCritical"));
11825
11826   if (IC_RIGHT (ic))
11827     {
11828       aopOp (IC_RIGHT (ic), ic, FALSE);
11829       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11830         {
11831           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11832           emitcode ("mov", "ea,c");
11833         }
11834       else
11835         {
11836           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11837             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11838           emitcode ("rrc", "a");
11839           emitcode ("mov", "ea,c");
11840         }
11841       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11842     }
11843   else
11844     {
11845       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11846       emitcode ("mov", "ea,c");
11847     }
11848 }
11849
11850 /*-----------------------------------------------------------------*/
11851 /* gen51Code - generate code for 8051 based controllers            */
11852 /*-----------------------------------------------------------------*/
11853 void
11854 gen51Code (iCode * lic)
11855 {
11856   iCode *ic;
11857   int cln = 0;
11858   /* int cseq = 0; */
11859
11860   _G.currentFunc = NULL;
11861   lineHead = lineCurr = NULL;
11862
11863   /* print the allocation information */
11864   if (allocInfo && currFunc)
11865     printAllocInfo (currFunc, codeOutBuf);
11866   /* if debug information required */
11867   if (options.debug && currFunc)
11868     {
11869       debugFile->writeFunction (currFunc, lic);
11870     }
11871   /* stack pointer name */
11872   if (options.useXstack)
11873     spname = "_spx";
11874   else
11875     spname = "sp";
11876
11877
11878   for (ic = lic; ic; ic = ic->next)
11879     {
11880       _G.current_iCode = ic;
11881
11882       if (ic->lineno && cln != ic->lineno)
11883         {
11884           if (options.debug)
11885             {
11886               debugFile->writeCLine (ic);
11887             }
11888           if (!options.noCcodeInAsm) {
11889             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11890                       printCLine(ic->filename, ic->lineno));
11891           }
11892           cln = ic->lineno;
11893         }
11894       #if 0
11895       if (ic->seqPoint && ic->seqPoint != cseq)
11896         {
11897           emitcode (";", "sequence point %d", ic->seqPoint);
11898           cseq = ic->seqPoint;
11899         }
11900       #endif
11901       if (options.iCodeInAsm) {
11902         char regsInUse[80];
11903         int i;
11904         const char *iLine;
11905
11906         #if 0
11907         for (i=0; i<8; i++) {
11908           sprintf (&regsInUse[i],
11909                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11910         regsInUse[i]=0;
11911         #else
11912         strcpy (regsInUse, "--------");
11913         for (i=0; i < 8; i++) {
11914           if (bitVectBitValue (ic->rMask, i))
11915             {
11916               int offset = regs8051[i].offset;
11917               regsInUse[offset] = offset + '0'; /* show rMask */
11918             }
11919         #endif
11920         }
11921         iLine = printILine(ic);
11922         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11923         dbuf_free(iLine);
11924       }
11925       /* if the result is marked as
11926          spilt and rematerializable or code for
11927          this has already been generated then
11928          do nothing */
11929       if (resultRemat (ic) || ic->generated)
11930         continue;
11931
11932       /* depending on the operation */
11933       switch (ic->op)
11934         {
11935         case '!':
11936           genNot (ic);
11937           break;
11938
11939         case '~':
11940           genCpl (ic);
11941           break;
11942
11943         case UNARYMINUS:
11944           genUminus (ic);
11945           break;
11946
11947         case IPUSH:
11948           genIpush (ic);
11949           break;
11950
11951         case IPOP:
11952             /* IPOP happens only when trying to restore a
11953                spilt live range, if there is an ifx statement
11954              following this pop then the if statement might
11955                be using some of the registers being popped which
11956                would destory the contents of the register so
11957                we need to check for this condition and handle it */
11958           if (ic->next &&
11959               ic->next->op == IFX &&
11960               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11961             genIfx (ic->next, ic);
11962             else
11963               genIpop (ic);
11964           break;
11965
11966         case CALL:
11967           genCall (ic);
11968           break;
11969
11970         case PCALL:
11971           genPcall (ic);
11972           break;
11973
11974         case FUNCTION:
11975           genFunction (ic);
11976           break;
11977
11978         case ENDFUNCTION:
11979           genEndFunction (ic);
11980           break;
11981
11982         case RETURN:
11983           genRet (ic);
11984           break;
11985
11986         case LABEL:
11987           genLabel (ic);
11988           break;
11989
11990         case GOTO:
11991           genGoto (ic);
11992           break;
11993
11994         case '+':
11995           genPlus (ic);
11996           break;
11997
11998         case '-':
11999           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
12000             genMinus (ic);
12001           break;
12002
12003         case '*':
12004           genMult (ic);
12005           break;
12006
12007         case '/':
12008           genDiv (ic);
12009           break;
12010
12011         case '%':
12012           genMod (ic);
12013           break;
12014
12015         case '>':
12016           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
12017           break;
12018
12019         case '<':
12020           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
12021           break;
12022
12023         case LE_OP:
12024         case GE_OP:
12025         case NE_OP:
12026
12027           /* note these two are xlated by algebraic equivalence
12028              in decorateType() in SDCCast.c */
12029           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12030                   "got '>=' or '<=' shouldn't have come here");
12031           break;
12032
12033         case EQ_OP:
12034           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
12035           break;
12036
12037         case AND_OP:
12038           genAndOp (ic);
12039           break;
12040
12041         case OR_OP:
12042           genOrOp (ic);
12043           break;
12044
12045         case '^':
12046           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
12047           break;
12048
12049         case '|':
12050           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
12051           break;
12052
12053         case BITWISEAND:
12054           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
12055           break;
12056
12057         case INLINEASM:
12058           genInline (ic);
12059           break;
12060
12061         case RRC:
12062           genRRC (ic);
12063           break;
12064
12065         case RLC:
12066           genRLC (ic);
12067           break;
12068
12069         case GETHBIT:
12070           genGetHbit (ic);
12071           break;
12072
12073         case GETABIT:
12074           genGetAbit (ic);
12075           break;
12076
12077         case GETBYTE:
12078           genGetByte (ic);
12079           break;
12080
12081         case GETWORD:
12082           genGetWord (ic);
12083           break;
12084
12085         case LEFT_OP:
12086           genLeftShift (ic);
12087           break;
12088
12089         case RIGHT_OP:
12090           genRightShift (ic);
12091           break;
12092
12093         case GET_VALUE_AT_ADDRESS:
12094           genPointerGet (ic,
12095                          hasInc (IC_LEFT (ic), ic,
12096                                  getSize (operandType (IC_RESULT (ic)))),
12097                          ifxForOp (IC_RESULT (ic), ic) );
12098           break;
12099
12100         case '=':
12101           if (POINTER_SET (ic))
12102             genPointerSet (ic,
12103                            hasInc (IC_RESULT (ic), ic,
12104                                    getSize (operandType (IC_RIGHT (ic)))));
12105           else
12106             genAssign (ic);
12107           break;
12108
12109         case IFX:
12110           genIfx (ic, NULL);
12111           break;
12112
12113         case ADDRESS_OF:
12114           genAddrOf (ic);
12115           break;
12116
12117         case JUMPTABLE:
12118           genJumpTab (ic);
12119           break;
12120
12121         case CAST:
12122           genCast (ic);
12123           break;
12124
12125         case RECEIVE:
12126           genReceive (ic);
12127           break;
12128
12129         case SEND:
12130           addSet (&_G.sendSet, ic);
12131           break;
12132
12133         case DUMMY_READ_VOLATILE:
12134           genDummyRead (ic);
12135           break;
12136
12137         case CRITICAL:
12138           genCritical (ic);
12139           break;
12140
12141         case ENDCRITICAL:
12142           genEndCritical (ic);
12143           break;
12144
12145         case SWAP:
12146           genSwap (ic);
12147           break;
12148
12149         default:
12150           ic = ic;
12151         }
12152     }
12153
12154   _G.current_iCode = NULL;
12155
12156   /* now we are ready to call the
12157      peep hole optimizer */
12158   if (!options.nopeep)
12159     peepHole (&lineHead);
12160
12161   /* now do the actual printing */
12162   printLine (lineHead, codeOutBuf);
12163   return;
12164 }