* src/mcs51/gen.c (pushSide, genPcall): fixed bug 1908493
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 #define D(x) do if (options.verboseAsm) {x;} while(0)
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include "SDCCglobl.h"
38 #include "newalloc.h"
39
40 #include "common.h"
41 #include "SDCCpeeph.h"
42 #include "ralloc.h"
43 #include "rtrack.h"
44 #include "gen.h"
45 #include "dbuf_string.h"
46
47 char *aopLiteral (value * val, int offset);
48 char *aopLiteralLong (value * val, int offset, int size);
49 extern int allocInfo;
50
51 /* this is the down and dirty file with all kinds of
52    kludgy & hacky stuff. This is what it is all about
53    CODE GENERATION for a specific MCU . some of the
54    routines may be reusable, will have to see */
55
56 static char *zero = "#0x00";
57 static char *one = "#0x01";
58 static char *spname;
59
60 char *fReturn8051[] =
61 {"dpl", "dph", "b", "a"};
62 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
63 char **fReturn = fReturn8051;
64 static char *accUse[] =
65 {"a", "b"};
66
67 static unsigned short rbank = -1;
68
69 #define REG_WITH_INDEX   mcs51_regWithIdx
70
71 #define AOP(op) op->aop
72 #define AOP_TYPE(op) AOP(op)->type
73 #define AOP_SIZE(op) AOP(op)->size
74 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
75                         AOP_TYPE(x) == AOP_R0))
76
77 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
78                          AOP_TYPE(x) == AOP_DPTR || \
79                          AOP(x)->paged))
80
81 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
82                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
83                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
84
85 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
86
87 #define R0INB   _G.bu.bs.r0InB
88 #define R1INB   _G.bu.bs.r1InB
89 #define OPINB   _G.bu.bs.OpInB
90 #define BINUSE  _G.bu.BInUse
91
92 static struct
93   {
94     short r0Pushed;
95     short r1Pushed;
96     union
97       {
98         struct
99           {
100             short r0InB : 2;//2 so we can see it overflow
101             short r1InB : 2;//2 so we can see it overflow
102             short OpInB : 2;//2 so we can see it overflow
103           } bs;
104         short BInUse;
105       } bu;
106     short accInUse;
107     short inLine;
108     short debugLine;
109     short nRegsSaved;
110     set *sendSet;
111     iCode *current_iCode;
112     symbol *currentFunc;
113   }
114 _G;
115
116 static char *rb1regs[] = {
117     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
118     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
119 };
120
121 extern struct dbuf_s *codeOutBuf;
122
123 #define RESULTONSTACK(x) \
124                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
125                          IC_RESULT(x)->aop->type == AOP_STK )
126
127 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
128 #define MOVB(x)  movb(x)
129
130 #define CLRC     emitcode("clr","c")
131 #define SETC     emitcode("setb","c")
132
133 static lineNode *lineHead = NULL;
134 static lineNode *lineCurr = NULL;
135
136 static unsigned char SLMask[] =
137 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
138  0xE0, 0xC0, 0x80, 0x00};
139 static unsigned char SRMask[] =
140 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
141  0x07, 0x03, 0x01, 0x00};
142
143 #define LSB     0
144 #define MSB16   1
145 #define MSB24   2
146 #define MSB32   3
147
148 /*-----------------------------------------------------------------*/
149 /* emitcode - writes the code into a file : for now it is simple    */
150 /*-----------------------------------------------------------------*/
151 void
152 emitcode (const char *inst, const char *fmt,...)
153 {
154   va_list ap;
155   struct dbuf_s dbuf;
156   const char *lbp, *lb;
157
158   dbuf_init (&dbuf, INITIAL_INLINEASM);
159
160   va_start (ap, fmt);
161
162   if (inst && *inst)
163     {
164       dbuf_append_str (&dbuf, inst);
165
166       if (fmt && *fmt)
167         {
168           dbuf_append_char (&dbuf, '\t');
169           dbuf_tvprintf (&dbuf, fmt, ap);
170         }
171     }
172   else
173     {
174       dbuf_tvprintf (&dbuf, fmt, ap);
175     }
176
177   lbp = lb = dbuf_c_str(&dbuf);
178
179   while (isspace ((unsigned char)*lbp))
180     {
181       lbp++;
182     }
183
184   if (lbp)
185     {
186       rtrackUpdate (lbp);
187
188       lineCurr = (lineCurr ?
189                   connectLine (lineCurr, newLineNode (lb)) :
190                   (lineHead = newLineNode (lb)));
191
192       lineCurr->isInline = _G.inLine;
193       lineCurr->isDebug = _G.debugLine;
194       lineCurr->ic = _G.current_iCode;
195       lineCurr->isComment = (*lbp==';');
196     }
197
198   va_end (ap);
199
200   dbuf_destroy(&dbuf);
201 }
202
203 static void
204 emitLabel (symbol *tlbl)
205 {
206   emitcode ("", "%05d$:", tlbl->key + 100);
207   lineCurr->isLabel = 1;
208 }
209
210 /*-----------------------------------------------------------------*/
211 /* mcs51_emitDebuggerSymbol - associate the current code location  */
212 /*   with a debugger symbol                                        */
213 /*-----------------------------------------------------------------*/
214 void
215 mcs51_emitDebuggerSymbol (char * debugSym)
216 {
217   _G.debugLine = 1;
218   emitcode ("", "%s ==.", debugSym);
219   _G.debugLine = 0;
220 }
221
222 /*-----------------------------------------------------------------*/
223 /* mova - moves specified value into accumulator                   */
224 /*-----------------------------------------------------------------*/
225 static void
226 mova (const char *x)
227 {
228   /* do some early peephole optimization */
229   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
230     return;
231
232   /* if it is a literal mov try to get it cheaper */
233   if (*x == '#' &&
234       rtrackMoveALit(x))
235     return;
236
237   emitcode("mov", "a,%s", x);
238 }
239
240 /*-----------------------------------------------------------------*/
241 /* movb - moves specified value into register b                    */
242 /*-----------------------------------------------------------------*/
243 static void
244 movb (const char *x)
245 {
246   /* do some early peephole optimization */
247   if (!strncmp(x, "b", 2))
248     return;
249
250   /* if it is a literal mov try to get it cheaper */
251   if (*x == '#')
252     {
253       emitcode("mov","b,%s", rtrackGetLit(x));
254       return;
255     }
256
257   emitcode("mov","b,%s", x);
258 }
259
260 /*-----------------------------------------------------------------*/
261 /* pushB - saves register B if necessary                           */
262 /*-----------------------------------------------------------------*/
263 static bool
264 pushB (void)
265 {
266   bool pushedB = FALSE;
267
268   if (BINUSE)
269     {
270       emitcode ("push", "b");
271 //    printf("B was in use !\n");
272       pushedB = TRUE;
273     }
274   else
275     {
276       OPINB++;
277     }
278   return pushedB;
279 }
280
281 /*-----------------------------------------------------------------*/
282 /* popB - restores value of register B if necessary                */
283 /*-----------------------------------------------------------------*/
284 static void
285 popB (bool pushedB)
286 {
287   if (pushedB)
288     {
289       emitcode ("pop", "b");
290     }
291   else
292     {
293       OPINB--;
294     }
295 }
296
297 /*-----------------------------------------------------------------*/
298 /* pushReg - saves register                                        */
299 /*-----------------------------------------------------------------*/
300 static bool
301 pushReg (int index, bool bits_pushed)
302 {
303   regs * reg = REG_WITH_INDEX (index);
304   if (reg->type == REG_BIT)
305     {
306       if (!bits_pushed)
307         emitcode ("push", "%s", reg->base);
308       return TRUE;
309     }
310   else
311     emitcode ("push", "%s", reg->dname);
312   return bits_pushed;
313 }
314
315 /*-----------------------------------------------------------------*/
316 /* popReg - restores register                                      */
317 /*-----------------------------------------------------------------*/
318 static bool
319 popReg (int index, bool bits_popped)
320 {
321   regs * reg = REG_WITH_INDEX (index);
322   if (reg->type == REG_BIT)
323     {
324       if (!bits_popped)
325         emitcode ("pop", "%s", reg->base);
326       return TRUE;
327     }
328   else
329     emitcode ("pop", "%s", reg->dname);
330   return bits_popped;
331 }
332
333 /*-----------------------------------------------------------------*/
334 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
335 /*-----------------------------------------------------------------*/
336 static regs *
337 getFreePtr (iCode * ic, asmop ** aopp, bool result)
338 {
339   bool r0iu, r1iu;
340   bool r0ou, r1ou;
341
342   /* the logic: if r0 & r1 used in the instruction
343      then we are in trouble otherwise */
344
345   /* first check if r0 & r1 are used by this
346      instruction, in which case we are in trouble */
347   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
348   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
349   if (r0iu && r1iu) {
350       goto endOfWorld;
351     }
352
353   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
354   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
355
356   /* if no usage of r0 then return it */
357   if (!r0iu && !r0ou)
358     {
359       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
360       (*aopp)->type = AOP_R0;
361
362       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
363     }
364
365   /* if no usage of r1 then return it */
366   if (!r1iu && !r1ou)
367     {
368       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
369       (*aopp)->type = AOP_R1;
370
371       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
372     }
373
374   /* now we know they both have usage */
375   /* if r0 not used in this instruction */
376   if (!r0iu)
377     {
378       /* push it if not already pushed */
379       if (ic->op == IPUSH)
380         {
381           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
382           R0INB++;
383         }
384       else if (!_G.r0Pushed)
385         {
386           emitcode ("push", "%s",
387                     REG_WITH_INDEX (R0_IDX)->dname);
388           _G.r0Pushed++;
389         }
390
391       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
392       (*aopp)->type = AOP_R0;
393
394       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
395     }
396
397   /* if r1 not used then */
398
399   if (!r1iu)
400     {
401       /* push it if not already pushed */
402       if (ic->op == IPUSH)
403         {
404           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
405           R1INB++;
406         }
407       else if (!_G.r1Pushed)
408         {
409           emitcode ("push", "%s",
410                     REG_WITH_INDEX (R1_IDX)->dname);
411           _G.r1Pushed++;
412         }
413
414       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
415       (*aopp)->type = AOP_R1;
416       return REG_WITH_INDEX (R1_IDX);
417     }
418
419 endOfWorld:
420   /* I said end of world, but not quite end of world yet */
421   /* if this is a result then we can push it on the stack */
422   if (result)
423     {
424       (*aopp)->type = AOP_STK;
425       return NULL;
426     }
427   /* in the case that result AND left AND right needs a pointer reg
428      we can safely use the result's */
429   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
430     {
431       (*aopp)->type = AOP_R0;
432       return REG_WITH_INDEX (R0_IDX);
433     }
434   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
435     {
436       (*aopp)->type = AOP_R1;
437       return REG_WITH_INDEX (R1_IDX);
438     }
439
440   /* now this is REALLY the end of the world */
441   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
442           "getFreePtr should never reach here");
443   exit (1);
444 }
445
446
447 /*-----------------------------------------------------------------*/
448 /* getTempRegs - initialize an array of pointers to GPR registers */
449 /*               that are not in use. Returns 1 if the requested   */
450 /*               number of registers were available, 0 otherwise.  */
451 /*-----------------------------------------------------------------*/
452 int
453 getTempRegs(regs **tempRegs, int size, iCode *ic)
454 {
455   bitVect * freeRegs;
456   int i;
457   int offset;
458
459   if (!ic)
460     ic = _G.current_iCode;
461   if (!ic)
462     return 0;
463   if (!_G.currentFunc)
464     return 0;
465
466   freeRegs = newBitVect(8);
467   bitVectSetBit (freeRegs, R2_IDX);
468   bitVectSetBit (freeRegs, R3_IDX);
469   bitVectSetBit (freeRegs, R4_IDX);
470   bitVectSetBit (freeRegs, R5_IDX);
471   bitVectSetBit (freeRegs, R6_IDX);
472   bitVectSetBit (freeRegs, R7_IDX);
473
474   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
475     {
476       bitVect * newfreeRegs;
477       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
478       freeBitVect(freeRegs);
479       freeRegs = newfreeRegs;
480     }
481   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
482
483   offset = 0;
484   for (i=0; i<freeRegs->size; i++)
485     {
486       if (bitVectBitValue(freeRegs,i))
487         tempRegs[offset++] = REG_WITH_INDEX(i);
488       if (offset>=size)
489         {
490           freeBitVect(freeRegs);
491           return 1;
492         }
493     }
494
495   freeBitVect(freeRegs);
496   return 0;
497 }
498
499
500 /*-----------------------------------------------------------------*/
501 /* newAsmop - creates a new asmOp                                  */
502 /*-----------------------------------------------------------------*/
503 static asmop *
504 newAsmop (short type)
505 {
506   asmop *aop;
507
508   aop = Safe_calloc (1, sizeof (asmop));
509   aop->type = type;
510   aop->allocated = 1;
511   return aop;
512 }
513
514 /*-----------------------------------------------------------------*/
515 /* pointerCode - returns the code for a pointer type               */
516 /*-----------------------------------------------------------------*/
517 static int
518 pointerCode (sym_link * etype)
519 {
520
521   return PTR_TYPE (SPEC_OCLS (etype));
522
523 }
524
525 /*-----------------------------------------------------------------*/
526 /* leftRightUseAcc - returns size of accumulator use by operands   */
527 /*-----------------------------------------------------------------*/
528 static int
529 leftRightUseAcc(iCode *ic)
530 {
531   operand *op;
532   int size;
533   int accuseSize = 0;
534   int accuse = 0;
535
536   if (!ic)
537     {
538       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
539               "null iCode pointer");
540       return 0;
541     }
542
543   if (ic->op == IFX)
544     {
545       op = IC_COND (ic);
546       if (IS_OP_ACCUSE (op))
547         {
548           accuse = 1;
549           size = getSize (OP_SYMBOL (op)->type);
550           if (size>accuseSize)
551             accuseSize = size;
552         }
553     }
554   else if (ic->op == JUMPTABLE)
555     {
556       op = IC_JTCOND (ic);
557       if (IS_OP_ACCUSE (op))
558         {
559           accuse = 1;
560           size = getSize (OP_SYMBOL (op)->type);
561           if (size>accuseSize)
562             accuseSize = size;
563         }
564     }
565   else
566     {
567       op = IC_LEFT (ic);
568       if (IS_OP_ACCUSE (op))
569         {
570           accuse = 1;
571           size = getSize (OP_SYMBOL (op)->type);
572           if (size>accuseSize)
573             accuseSize = size;
574         }
575       op = IC_RIGHT (ic);
576       if (IS_OP_ACCUSE (op))
577         {
578           accuse = 1;
579           size = getSize (OP_SYMBOL (op)->type);
580           if (size>accuseSize)
581             accuseSize = size;
582         }
583     }
584
585   if (accuseSize)
586     return accuseSize;
587   else
588     return accuse;
589 }
590
591 /*-----------------------------------------------------------------*/
592 /* aopForSym - for a true symbol                                   */
593 /*-----------------------------------------------------------------*/
594 static asmop *
595 aopForSym (iCode * ic, symbol * sym, bool result)
596 {
597   asmop *aop;
598   memmap *space;
599   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
600
601   wassertl (ic != NULL, "Got a null iCode");
602   wassertl (sym != NULL, "Got a null symbol");
603
604   space = SPEC_OCLS (sym->etype);
605
606   /* if already has one */
607   if (sym->aop)
608     {
609       sym->aop->allocated++;
610       return sym->aop;
611     }
612
613   /* assign depending on the storage class */
614   /* if it is on the stack or indirectly addressable */
615   /* space we need to assign either r0 or r1 to it   */
616   if (sym->onStack || sym->iaccess)
617     {
618       sym->aop = aop = newAsmop (0);
619       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
620       aop->size = getSize (sym->type);
621
622       /* now assign the address of the variable to
623          the pointer register */
624       if (aop->type != AOP_STK)
625         {
626           if (sym->onStack)
627             {
628               signed char offset = ((sym->stack < 0) ?
629                          ((signed char) (sym->stack - _G.nRegsSaved)) :
630                          ((signed char) sym->stack)) & 0xff;
631
632               if ((abs(offset) <= 3) ||
633                   (accuse && (abs(offset) <= 7)))
634                 {
635                   emitcode ("mov", "%s,%s",
636                             aop->aopu.aop_ptr->name, SYM_BP (sym));
637                   while (offset < 0)
638                     {
639                       emitcode ("dec", aop->aopu.aop_ptr->name);
640                       offset++;
641                     }
642                   while (offset > 0)
643                     {
644                       emitcode ("inc", aop->aopu.aop_ptr->name);
645                       offset--;
646                     }
647                 }
648               else
649                 {
650                   if (accuse)
651                     emitcode ("push", "acc");
652                   emitcode ("mov", "a,%s", SYM_BP (sym));
653                   emitcode ("add", "a,#0x%02x", offset & 0xff);
654                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
655                   if (accuse)
656                     emitcode ("pop", "acc");
657                 }
658             }
659           else
660             {
661               emitcode ("mov", "%s,#%s",
662                         aop->aopu.aop_ptr->name,
663                         sym->rname);
664             }
665           aop->paged = space->paged;
666         }
667       else
668         aop->aopu.aop_stk = sym->stack;
669       return aop;
670     }
671
672   /* if in bit space */
673   if (IN_BITSPACE (space))
674     {
675       sym->aop = aop = newAsmop (AOP_CRY);
676       aop->aopu.aop_dir = sym->rname;
677       aop->size = getSize (sym->type);
678       return aop;
679     }
680   /* if it is in direct space */
681   if (IN_DIRSPACE (space))
682     {
683       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
684       //printTypeChainRaw(sym->type, NULL);
685       //printf("space = %s\n", space ? space->sname : "NULL");
686       sym->aop = aop = newAsmop (AOP_DIR);
687       aop->aopu.aop_dir = sym->rname;
688       aop->size = getSize (sym->type);
689       return aop;
690     }
691
692   /* special case for a function */
693   if (IS_FUNC (sym->type))
694     {
695       sym->aop = aop = newAsmop (AOP_IMMD);
696       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
697       aop->size = getSize (sym->type);
698       return aop;
699     }
700
701   /* only remaining is far space */
702   /* in which case DPTR gets the address */
703   sym->aop = aop = newAsmop (AOP_DPTR);
704   emitcode ("mov", "dptr,#%s", sym->rname);
705   aop->size = getSize (sym->type);
706
707   /* if it is in code space */
708   if (IN_CODESPACE (space))
709     aop->code = 1;
710
711   return aop;
712 }
713
714 /*-----------------------------------------------------------------*/
715 /* aopForRemat - rematerializes an object                          */
716 /*-----------------------------------------------------------------*/
717 static asmop *
718 aopForRemat (symbol * sym)
719 {
720   iCode *ic = sym->rematiCode;
721   asmop *aop = newAsmop (AOP_IMMD);
722   int ptr_type = 0;
723   int val = 0;
724
725   for (;;)
726     {
727       if (ic->op == '+')
728         val += (int) operandLitValue (IC_RIGHT (ic));
729       else if (ic->op == '-')
730         val -= (int) operandLitValue (IC_RIGHT (ic));
731       else if (IS_CAST_ICODE(ic))
732         {
733           sym_link *from_type = operandType(IC_RIGHT(ic));
734           aop->aopu.aop_immd.from_cast_remat = 1;
735           ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
736           ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
737           continue;
738         }
739       else break;
740
741       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
742     }
743
744   if (val)
745     {
746       SNPRINTF (buffer, sizeof(buffer),
747                 "(%s %c 0x%04x)",
748                 OP_SYMBOL (IC_LEFT (ic))->rname,
749                 val >= 0 ? '+' : '-',
750                 abs (val) & 0xffff);
751     }
752   else
753     {
754       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
755     }
756
757   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
758   /* set immd2 field if required */
759   if (aop->aopu.aop_immd.from_cast_remat)
760     {
761       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
762       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
763     }
764
765   return aop;
766 }
767
768 /*-----------------------------------------------------------------*/
769 /* regsInCommon - two operands have some registers in common       */
770 /*-----------------------------------------------------------------*/
771 static bool
772 regsInCommon (operand * op1, operand * op2)
773 {
774   symbol *sym1, *sym2;
775   int i;
776
777   /* if they have registers in common */
778   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
779     return FALSE;
780
781   sym1 = OP_SYMBOL (op1);
782   sym2 = OP_SYMBOL (op2);
783
784   if (sym1->nRegs == 0 || sym2->nRegs == 0)
785     return FALSE;
786
787   for (i = 0; i < sym1->nRegs; i++)
788     {
789       int j;
790       if (!sym1->regs[i])
791         continue;
792
793       for (j = 0; j < sym2->nRegs; j++)
794         {
795           if (!sym2->regs[j])
796             continue;
797
798           if (sym2->regs[j] == sym1->regs[i])
799             return TRUE;
800         }
801     }
802
803   return FALSE;
804 }
805
806 /*-----------------------------------------------------------------*/
807 /* operandsEqu - equivalent                                        */
808 /*-----------------------------------------------------------------*/
809 static bool
810 operandsEqu (operand * op1, operand * op2)
811 {
812   symbol *sym1, *sym2;
813
814   /* if they're not symbols */
815   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
816     return FALSE;
817
818   sym1 = OP_SYMBOL (op1);
819   sym2 = OP_SYMBOL (op2);
820
821   /* if both are itemps & one is spilt
822      and the other is not then false */
823   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
824       sym1->isspilt != sym2->isspilt)
825     return FALSE;
826
827   /* if they are the same */
828   if (sym1 == sym2)
829     return TRUE;
830
831   /* if they have the same rname */
832   if (sym1->rname[0] && sym2->rname[0] &&
833       strcmp (sym1->rname, sym2->rname) == 0 &&
834       !(IS_PARM (op2) && IS_ITEMP (op1)))
835     return TRUE;
836
837   /* if left is a tmp & right is not */
838   if (IS_ITEMP (op1) &&
839       !IS_ITEMP (op2) &&
840       sym1->isspilt &&
841       (sym1->usl.spillLoc == sym2))
842     return TRUE;
843
844   if (IS_ITEMP (op2) &&
845       !IS_ITEMP (op1) &&
846       sym2->isspilt &&
847       sym1->level > 0 &&
848       (sym2->usl.spillLoc == sym1))
849     return TRUE;
850
851   return FALSE;
852 }
853
854 /*-----------------------------------------------------------------*/
855 /* sameByte - two asmops have the same address at given offsets    */
856 /*-----------------------------------------------------------------*/
857 static bool
858 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
859 {
860   if (aop1 == aop2 && off1 == off2)
861     return TRUE;
862
863   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
864     return FALSE;
865
866   if (aop1->type != aop2->type)
867     return FALSE;
868
869   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
870     return FALSE;
871
872   return TRUE;
873 }
874
875 /*-----------------------------------------------------------------*/
876 /* sameRegs - two asmops have the same registers                   */
877 /*-----------------------------------------------------------------*/
878 static bool
879 sameRegs (asmop * aop1, asmop * aop2)
880 {
881   int i;
882
883   if (aop1 == aop2)
884     return TRUE;
885
886   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
887     return FALSE;
888
889   if (aop1->type != aop2->type)
890     return FALSE;
891
892   if (aop1->size != aop2->size)
893     return FALSE;
894
895   for (i = 0; i < aop1->size; i++)
896     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
897       return FALSE;
898
899   return TRUE;
900 }
901
902 /*-----------------------------------------------------------------*/
903 /* aopOp - allocates an asmop for an operand  :                    */
904 /*-----------------------------------------------------------------*/
905 static void
906 aopOp (operand * op, iCode * ic, bool result)
907 {
908   asmop *aop;
909   symbol *sym;
910   int i;
911
912   if (!op)
913     return;
914
915   /* if this a literal */
916   if (IS_OP_LITERAL (op))
917     {
918       op->aop = aop = newAsmop (AOP_LIT);
919       aop->aopu.aop_lit = op->operand.valOperand;
920       aop->size = getSize (operandType (op));
921       return;
922     }
923
924   /* if already has a asmop then continue */
925   if (op->aop)
926     {
927       op->aop->allocated++;
928       return;
929     }
930
931   /* if the underlying symbol has a aop */
932   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
933     {
934       op->aop = OP_SYMBOL (op)->aop;
935       op->aop->allocated++;
936       return;
937     }
938
939   /* if this is a true symbol */
940   if (IS_TRUE_SYMOP (op))
941     {
942       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
943       return;
944     }
945
946   /* this is a temporary : this has
947      only five choices :
948      a) register
949      b) spillocation
950      c) rematerialize
951      d) conditional
952      e) can be a return use only */
953
954   sym = OP_SYMBOL (op);
955
956   /* if the type is a conditional */
957   if (sym->regType == REG_CND)
958     {
959       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
960       aop->size = sym->ruonly ? 1 : 0;
961       return;
962     }
963
964   /* if it is spilt then two situations
965      a) is rematerialize
966      b) has a spill location */
967   if (sym->isspilt || sym->nRegs == 0)
968     {
969
970       /* rematerialize it NOW */
971       if (sym->remat)
972         {
973           sym->aop = op->aop = aop = aopForRemat (sym);
974           aop->size = operandSize (op);
975           return;
976         }
977
978       if (sym->accuse)
979         {
980           int i;
981           sym->aop = op->aop = aop = newAsmop (AOP_ACC);
982           aop->size = getSize (sym->type);
983           for (i = 0; i < 2; i++)
984             aop->aopu.aop_str[i] = accUse[i];
985           return;
986         }
987
988       if (sym->ruonly)
989         {
990           unsigned i;
991
992           sym->aop = op->aop = aop = newAsmop (AOP_STR);
993           aop->size = getSize (sym->type);
994           for (i = 0; i < fReturnSizeMCS51; i++)
995             aop->aopu.aop_str[i] = fReturn[i];
996           return;
997         }
998
999       if (sym->usl.spillLoc)
1000         {
1001           asmop *oldAsmOp = NULL;
1002
1003           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1004             {
1005               /* force a new aop if sizes differ */
1006               oldAsmOp = sym->usl.spillLoc->aop;
1007               sym->usl.spillLoc->aop = NULL;
1008             }
1009           sym->aop = op->aop = aop =
1010                      aopForSym (ic, sym->usl.spillLoc, result);
1011           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1012             {
1013               /* Don't reuse the new aop, go with the last one */
1014               sym->usl.spillLoc->aop = oldAsmOp;
1015             }
1016           aop->size = getSize (sym->type);
1017           return;
1018         }
1019
1020       /* else must be a dummy iTemp */
1021       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1022       aop->size = getSize (sym->type);
1023       return;
1024     }
1025
1026   /* if the type is a bit register */
1027   if (sym->regType == REG_BIT)
1028     {
1029       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1030       aop->size = sym->nRegs;//1???
1031       aop->aopu.aop_reg[0] = sym->regs[0];
1032       aop->aopu.aop_dir = sym->regs[0]->name;
1033       return;
1034     }
1035
1036   /* must be in a register */
1037   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1038   aop->size = sym->nRegs;
1039   for (i = 0; i < sym->nRegs; i++)
1040     aop->aopu.aop_reg[i] = sym->regs[i];
1041 }
1042
1043 /*-----------------------------------------------------------------*/
1044 /* freeAsmop - free up the asmop given to an operand               */
1045 /*-----------------------------------------------------------------*/
1046 static void
1047 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1048 {
1049   asmop *aop;
1050
1051   if (!op)
1052     aop = aaop;
1053   else
1054     aop = op->aop;
1055
1056   if (!aop)
1057     return;
1058
1059   aop->allocated--;
1060
1061   if (aop->allocated)
1062     goto dealloc;
1063
1064   /* depending on the asmop type only three cases need work
1065      AOP_R0, AOP_R1 & AOP_STK */
1066   switch (aop->type)
1067     {
1068     case AOP_R0:
1069       if (R0INB)
1070         {
1071           emitcode ("mov", "r0,b");
1072           R0INB--;
1073         }
1074       else if (_G.r0Pushed)
1075         {
1076           if (pop)
1077             {
1078               emitcode ("pop", "ar0");
1079               _G.r0Pushed--;
1080             }
1081         }
1082       bitVectUnSetBit (ic->rUsed, R0_IDX);
1083       break;
1084
1085     case AOP_R1:
1086       if (R1INB)
1087         {
1088           emitcode ("mov", "r1,b");
1089           R1INB--;
1090         }
1091       else if (_G.r1Pushed)
1092         {
1093           if (pop)
1094             {
1095               emitcode ("pop", "ar1");
1096               _G.r1Pushed--;
1097             }
1098         }
1099       bitVectUnSetBit (ic->rUsed, R1_IDX);
1100       break;
1101
1102     case AOP_STK:
1103       {
1104         int sz = aop->size;
1105         int stk = aop->aopu.aop_stk + aop->size - 1;
1106         bitVectUnSetBit (ic->rUsed, R0_IDX);
1107         bitVectUnSetBit (ic->rUsed, R1_IDX);
1108
1109         getFreePtr (ic, &aop, FALSE);
1110
1111         if (stk)
1112           {
1113             emitcode ("mov", "a,_bp");
1114             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1115             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1116           }
1117         else
1118           {
1119             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1120           }
1121
1122         while (sz--)
1123           {
1124             emitcode ("pop", "acc");
1125             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1126             if (!sz)
1127               break;
1128             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1129           }
1130         op->aop = aop;
1131         freeAsmop (op, NULL, ic, TRUE);
1132         if (_G.r1Pushed)
1133           {
1134             emitcode ("pop", "ar1");
1135             _G.r1Pushed--;
1136           }
1137         if (_G.r0Pushed)
1138           {
1139             emitcode ("pop", "ar0");
1140             _G.r0Pushed--;
1141           }
1142       }
1143       break;
1144     }
1145
1146 dealloc:
1147   /* all other cases just dealloc */
1148   if (op)
1149     {
1150       op->aop = NULL;
1151       if (IS_SYMOP (op))
1152         {
1153           OP_SYMBOL (op)->aop = NULL;
1154           /* if the symbol has a spill */
1155           if (SPIL_LOC (op))
1156             SPIL_LOC (op)->aop = NULL;
1157         }
1158     }
1159 }
1160
1161 /*------------------------------------------------------------------*/
1162 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1163 /*                      pop r0 or r1 off stack if pushed            */
1164 /*------------------------------------------------------------------*/
1165 static void
1166 freeForBranchAsmop (operand * op)
1167 {
1168   asmop *aop;
1169
1170   if (!op)
1171     return;
1172
1173   aop = op->aop;
1174
1175   if (!aop)
1176     return;
1177
1178   if (!aop->allocated)
1179     return;
1180
1181   switch (aop->type)
1182     {
1183     case AOP_R0:
1184       if (R0INB)
1185         {
1186           emitcode ("mov", "r0,b");
1187         }
1188       else if (_G.r0Pushed)
1189         {
1190           emitcode ("pop", "ar0");
1191         }
1192       break;
1193
1194     case AOP_R1:
1195       if (R1INB)
1196         {
1197           emitcode ("mov", "r1,b");
1198         }
1199       else if (_G.r1Pushed)
1200         {
1201           emitcode ("pop", "ar1");
1202         }
1203       break;
1204
1205     case AOP_STK:
1206       {
1207         int sz = aop->size;
1208         int stk = aop->aopu.aop_stk + aop->size - 1;
1209
1210         emitcode ("mov", "b,r0");
1211         if (stk)
1212           {
1213             emitcode ("mov", "a,_bp");
1214             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1215             emitcode ("mov", "r0,a");
1216           }
1217         else
1218           {
1219             emitcode ("mov", "r0,_bp");
1220           }
1221
1222         while (sz--)
1223           {
1224             emitcode ("pop", "acc");
1225             emitcode ("mov", "@r0,a");
1226             if (!sz)
1227               break;
1228             emitcode ("dec", "r0");
1229           }
1230         emitcode ("mov", "r0,b");
1231       }
1232     }
1233
1234 }
1235
1236 /*-----------------------------------------------------------------*/
1237 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1238 /*                 clobber the accumulator                         */
1239 /*-----------------------------------------------------------------*/
1240 static bool
1241 aopGetUsesAcc (operand * oper, int offset)
1242 {
1243   asmop * aop = AOP (oper);
1244
1245   if (offset > (aop->size - 1))
1246     return FALSE;
1247
1248   switch (aop->type)
1249     {
1250
1251     case AOP_R0:
1252     case AOP_R1:
1253       if (aop->paged)
1254         return TRUE;
1255       return FALSE;
1256     case AOP_DPTR:
1257       return TRUE;
1258     case AOP_IMMD:
1259       return FALSE;
1260     case AOP_DIR:
1261       return FALSE;
1262     case AOP_REG:
1263       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1264       return FALSE;
1265     case AOP_CRY:
1266       return TRUE;
1267     case AOP_ACC:
1268       if (offset)
1269         return FALSE;
1270       return TRUE;
1271     case AOP_LIT:
1272       return FALSE;
1273     case AOP_STR:
1274       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1275         return TRUE;
1276       return FALSE;
1277     case AOP_DUMMY:
1278       return FALSE;
1279     default:
1280       /* Error case --- will have been caught already */
1281       wassert(0);
1282       return FALSE;
1283     }
1284 }
1285
1286 /*-------------------------------------------------------------------*/
1287 /* aopGet - for fetching value of the aop                            */
1288 /*-------------------------------------------------------------------*/
1289 static char *
1290 aopGet (operand * oper, int offset, bool bit16, bool dname)
1291 {
1292   asmop * aop = AOP (oper);
1293
1294   /* offset is greater than
1295      size then zero */
1296   if (offset > (aop->size - 1) &&
1297       aop->type != AOP_LIT)
1298     return zero;
1299
1300   /* depending on type */
1301   switch (aop->type)
1302     {
1303     case AOP_DUMMY:
1304       return zero;
1305
1306     case AOP_R0:
1307     case AOP_R1:
1308       /* if we need to increment it */
1309       while (offset > aop->coff)
1310         {
1311           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1312           aop->coff++;
1313         }
1314
1315       while (offset < aop->coff)
1316         {
1317           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1318           aop->coff--;
1319         }
1320
1321       aop->coff = offset;
1322       if (aop->paged)
1323         {
1324           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1325           return (dname ? "acc" : "a");
1326         }
1327       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1328       return Safe_strdup(buffer);
1329
1330     case AOP_DPTR:
1331       if (aop->code && aop->coff==0 && offset>=1) {
1332         emitcode ("mov", "a,#0x%02x", offset);
1333         emitcode ("movc", "a,@a+dptr");
1334         return (dname ? "acc" : "a");
1335       }
1336
1337       while (offset > aop->coff)
1338         {
1339           emitcode ("inc", "dptr");
1340           aop->coff++;
1341         }
1342
1343       while (offset < aop->coff)
1344         {
1345           emitcode ("lcall", "__decdptr");
1346           aop->coff--;
1347         }
1348
1349       aop->coff = offset;
1350       if (aop->code)
1351         {
1352           emitcode ("clr", "a");
1353           emitcode ("movc", "a,@a+dptr");
1354         }
1355       else
1356         {
1357           emitcode ("movx", "a,@dptr");
1358         }
1359       return (dname ? "acc" : "a");
1360
1361     case AOP_IMMD:
1362       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1363         {
1364           SNPRINTF(buffer, sizeof(buffer),
1365                    "%s",aop->aopu.aop_immd.aop_immd2);
1366         }
1367       else if (bit16)
1368         {
1369           SNPRINTF(buffer, sizeof(buffer),
1370                    "#%s", aop->aopu.aop_immd.aop_immd1);
1371         }
1372       else if (offset)
1373         {
1374           SNPRINTF (buffer, sizeof(buffer),
1375                     "#(%s >> %d)",
1376                     aop->aopu.aop_immd.aop_immd1,
1377                     offset * 8);
1378         }
1379       else
1380         {
1381           SNPRINTF (buffer, sizeof(buffer),
1382                     "#%s",
1383                     aop->aopu.aop_immd.aop_immd1);
1384         }
1385       return Safe_strdup(buffer);
1386
1387     case AOP_DIR:
1388       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1389         {
1390           SNPRINTF (buffer, sizeof(buffer),
1391                     "(%s >> %d)",
1392                     aop->aopu.aop_dir, offset * 8);
1393         }
1394       else if (offset)
1395         {
1396           SNPRINTF (buffer, sizeof(buffer),
1397                     "(%s + %d)",
1398                     aop->aopu.aop_dir,
1399                     offset);
1400         }
1401       else
1402         {
1403           SNPRINTF (buffer, sizeof(buffer),
1404                     "%s",
1405                     aop->aopu.aop_dir);
1406         }
1407
1408       return Safe_strdup(buffer);
1409
1410     case AOP_REG:
1411       if (dname)
1412         return aop->aopu.aop_reg[offset]->dname;
1413       else
1414         return aop->aopu.aop_reg[offset]->name;
1415
1416     case AOP_CRY:
1417       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1418       emitcode ("clr", "a");
1419       emitcode ("rlc", "a");
1420       return (dname ? "acc" : "a");
1421
1422     case AOP_ACC:
1423       if (!offset && dname)
1424         return "acc";
1425       return aop->aopu.aop_str[offset];
1426
1427     case AOP_LIT:
1428       return aopLiteral (aop->aopu.aop_lit, offset);
1429
1430     case AOP_STR:
1431       aop->coff = offset;
1432       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1433           dname)
1434         return "acc";
1435
1436       return aop->aopu.aop_str[offset];
1437
1438     }
1439
1440   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1441           "aopget got unsupported aop->type");
1442   exit (1);
1443 }
1444
1445 /*-----------------------------------------------------------------*/
1446 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1447 /*                 clobber the accumulator                         */
1448 /*-----------------------------------------------------------------*/
1449 static bool
1450 aopPutUsesAcc (operand * oper, const char *s, int offset)
1451 {
1452   asmop * aop = AOP (oper);
1453
1454   if (offset > (aop->size - 1))
1455     return FALSE;
1456
1457   switch (aop->type)
1458     {
1459     case AOP_DUMMY:
1460       return TRUE;
1461     case AOP_DIR:
1462       return FALSE;
1463     case AOP_REG:
1464       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1465       return FALSE;
1466     case AOP_DPTR:
1467       return TRUE;
1468     case AOP_R0:
1469     case AOP_R1:
1470       return ((aop->paged) || (*s == '@'));
1471     case AOP_STK:
1472       return (*s == '@');
1473     case AOP_CRY:
1474       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1475     case AOP_STR:
1476       return FALSE;
1477     case AOP_IMMD:
1478       return FALSE;
1479     case AOP_ACC:
1480       return FALSE;
1481     default:
1482       /* Error case --- will have been caught already */
1483       wassert(0);
1484       return FALSE;
1485     }
1486 }
1487
1488 /*-----------------------------------------------------------------*/
1489 /* aopPut - puts a string for a aop and indicates if acc is in use */
1490 /*-----------------------------------------------------------------*/
1491 static bool
1492 aopPut (operand * result, const char *s, int offset)
1493 {
1494   bool bvolatile = isOperandVolatile (result, FALSE);
1495   bool accuse = FALSE;
1496   asmop * aop = AOP (result);
1497   const char *d = NULL;
1498
1499   if (aop->size && offset > (aop->size - 1))
1500     {
1501       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1502               "aopPut got offset > aop->size");
1503       exit (1);
1504     }
1505
1506   /* will assign value to value */
1507   /* depending on where it is ofcourse */
1508   switch (aop->type)
1509     {
1510     case AOP_DUMMY:
1511       MOVA (s);         /* read s in case it was volatile */
1512       accuse = TRUE;
1513       break;
1514
1515     case AOP_DIR:
1516       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1517         {
1518           SNPRINTF (buffer, sizeof(buffer),
1519                     "(%s >> %d)",
1520                     aop->aopu.aop_dir, offset * 8);
1521         }
1522       else if (offset)
1523         {
1524           SNPRINTF (buffer, sizeof(buffer),
1525                     "(%s + %d)",
1526                     aop->aopu.aop_dir, offset);
1527         }
1528       else
1529         {
1530           SNPRINTF (buffer, sizeof(buffer),
1531                     "%s",
1532                     aop->aopu.aop_dir);
1533         }
1534
1535       if (strcmp (buffer, s) || bvolatile)
1536         {
1537           emitcode ("mov", "%s,%s", buffer, s);
1538         }
1539       if (!strcmp (buffer, "acc"))
1540         {
1541           accuse = TRUE;
1542         }
1543       break;
1544
1545     case AOP_REG:
1546       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1547           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1548         {
1549           if (*s == '@' ||
1550               strcmp (s, "r0") == 0 ||
1551               strcmp (s, "r1") == 0 ||
1552               strcmp (s, "r2") == 0 ||
1553               strcmp (s, "r3") == 0 ||
1554               strcmp (s, "r4") == 0 ||
1555               strcmp (s, "r5") == 0 ||
1556               strcmp (s, "r6") == 0 ||
1557               strcmp (s, "r7") == 0)
1558             {
1559               emitcode ("mov", "%s,%s",
1560                         aop->aopu.aop_reg[offset]->dname, s);
1561             }
1562           else
1563             {
1564               emitcode ("mov", "%s,%s",
1565                         aop->aopu.aop_reg[offset]->name, s);
1566             }
1567         }
1568       break;
1569
1570     case AOP_DPTR:
1571       if (aop->code)
1572         {
1573           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1574                   "aopPut writing to code space");
1575           exit (1);
1576         }
1577
1578       while (offset > aop->coff)
1579         {
1580           aop->coff++;
1581           emitcode ("inc", "dptr");
1582         }
1583
1584       while (offset < aop->coff)
1585         {
1586           aop->coff--;
1587           emitcode ("lcall", "__decdptr");
1588         }
1589
1590       aop->coff = offset;
1591
1592       /* if not in accumulator */
1593       MOVA (s);
1594
1595       emitcode ("movx", "@dptr,a");
1596       break;
1597
1598     case AOP_R0:
1599     case AOP_R1:
1600       while (offset > aop->coff)
1601         {
1602           aop->coff++;
1603           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1604         }
1605       while (offset < aop->coff)
1606         {
1607           aop->coff--;
1608           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1609         }
1610       aop->coff = offset;
1611
1612       if (aop->paged)
1613         {
1614           MOVA (s);
1615           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1616         }
1617       else if (*s == '@')
1618         {
1619           MOVA (s);
1620           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1621         }
1622       else if (strcmp (s, "r0") == 0 ||
1623                strcmp (s, "r1") == 0 ||
1624                strcmp (s, "r2") == 0 ||
1625                strcmp (s, "r3") == 0 ||
1626                strcmp (s, "r4") == 0 ||
1627                strcmp (s, "r5") == 0 ||
1628                strcmp (s, "r6") == 0 ||
1629                strcmp (s, "r7") == 0)
1630         {
1631           char buffer[10];
1632           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1633           emitcode ("mov", "@%s,%s",
1634                     aop->aopu.aop_ptr->name, buffer);
1635         }
1636       else
1637         {
1638           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1639         }
1640       break;
1641
1642     case AOP_STK:
1643       if (strcmp (s, "a") == 0)
1644         {
1645           emitcode ("push", "acc");
1646         }
1647       else if (*s=='@')
1648         {
1649           MOVA(s);
1650           emitcode ("push", "acc");
1651         }
1652       else if (strcmp (s, "r0") == 0 ||
1653                strcmp (s, "r1") == 0 ||
1654                strcmp (s, "r2") == 0 ||
1655                strcmp (s, "r3") == 0 ||
1656                strcmp (s, "r4") == 0 ||
1657                strcmp (s, "r5") == 0 ||
1658                strcmp (s, "r6") == 0 ||
1659                strcmp (s, "r7") == 0)
1660         {
1661           char buffer[10];
1662           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1663           emitcode ("push", buffer);
1664         }
1665       else
1666         {
1667           emitcode ("push", s);
1668         }
1669
1670       break;
1671
1672     case AOP_CRY:
1673       // destination is carry for return-use-only
1674       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1675       // source is no literal and not in carry
1676       if ((s != zero) && (s != one) && strcmp (s, "c"))
1677         {
1678           MOVA (s);
1679           /* set C, if a >= 1 */
1680           emitcode ("add", "a,#0xff");
1681           s = "c";
1682         }
1683       // now source is zero, one or carry
1684
1685       /* if result no bit variable */
1686       if (!d)
1687         {
1688           if (!strcmp (s, "c"))
1689             {
1690               /* inefficient: move carry into A and use jz/jnz */
1691               emitcode ("clr", "a");
1692               emitcode ("rlc", "a");
1693               accuse = TRUE;
1694             }
1695           else
1696             {
1697               MOVA (s);
1698               accuse = TRUE;
1699             }
1700         }
1701       else if (s == zero)
1702           emitcode ("clr", "%s", d);
1703       else if (s == one)
1704           emitcode ("setb", "%s", d);
1705       else if (strcmp (s, d))
1706           emitcode ("mov", "%s,c", d);
1707       break;
1708
1709     case AOP_STR:
1710       aop->coff = offset;
1711       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1712         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1713       break;
1714
1715     case AOP_ACC:
1716       accuse = TRUE;
1717       aop->coff = offset;
1718       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1719         break;
1720
1721       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1722         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1723       break;
1724
1725     default:
1726       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1727               "aopPut got unsupported aop->type");
1728       exit (1);
1729     }
1730
1731     return accuse;
1732 }
1733
1734
1735 #if 0
1736 /*-----------------------------------------------------------------*/
1737 /* pointToEnd :- points to the last byte of the operand            */
1738 /*-----------------------------------------------------------------*/
1739 static void
1740 pointToEnd (asmop * aop)
1741 {
1742   int count;
1743   if (!aop)
1744     return;
1745
1746   aop->coff = count = (aop->size - 1);
1747   switch (aop->type)
1748     {
1749     case AOP_R0:
1750     case AOP_R1:
1751       while (count--)
1752         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1753       break;
1754     case AOP_DPTR:
1755       while (count--)
1756         emitcode ("inc", "dptr");
1757       break;
1758     }
1759
1760 }
1761 #endif
1762
1763 /*-----------------------------------------------------------------*/
1764 /* reAdjustPreg - points a register back to where it should        */
1765 /*-----------------------------------------------------------------*/
1766 static void
1767 reAdjustPreg (asmop * aop)
1768 {
1769   if ((aop->coff==0) || (aop->size <= 1))
1770     return;
1771
1772   switch (aop->type)
1773     {
1774     case AOP_R0:
1775     case AOP_R1:
1776       while (aop->coff--)
1777         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1778       break;
1779     case AOP_DPTR:
1780       while (aop->coff--)
1781         {
1782           emitcode ("lcall", "__decdptr");
1783         }
1784       break;
1785     }
1786   aop->coff = 0;
1787 }
1788
1789 /*-----------------------------------------------------------------*/
1790 /* opIsGptr: returns non-zero if the passed operand is       */
1791 /* a generic pointer type.             */
1792 /*-----------------------------------------------------------------*/
1793 static int
1794 opIsGptr (operand * op)
1795 {
1796   sym_link *type = operandType (op);
1797
1798   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1799     {
1800       return 1;
1801     }
1802   return 0;
1803 }
1804
1805 /*-----------------------------------------------------------------*/
1806 /* getDataSize - get the operand data size                         */
1807 /*-----------------------------------------------------------------*/
1808 static int
1809 getDataSize (operand * op)
1810 {
1811   int size;
1812   size = AOP_SIZE (op);
1813   if (size == GPTRSIZE)
1814     {
1815       sym_link *type = operandType (op);
1816       if (IS_GENPTR (type))
1817         {
1818           /* generic pointer; arithmetic operations
1819            * should ignore the high byte (pointer type).
1820            */
1821           size--;
1822         }
1823     }
1824   return size;
1825 }
1826
1827 /*-----------------------------------------------------------------*/
1828 /* outAcc - output Acc                                             */
1829 /*-----------------------------------------------------------------*/
1830 static void
1831 outAcc (operand * result)
1832 {
1833   int size, offset;
1834   size = getDataSize (result);
1835   if (size)
1836     {
1837       aopPut (result, "a", 0);
1838       size--;
1839       offset = 1;
1840       /* unsigned or positive */
1841       while (size--)
1842         {
1843           aopPut (result, zero, offset++);
1844         }
1845     }
1846 }
1847
1848 /*-----------------------------------------------------------------*/
1849 /* outBitC - output a bit C                                        */
1850 /*-----------------------------------------------------------------*/
1851 static void
1852 outBitC (operand * result)
1853 {
1854   /* if the result is bit */
1855   if (AOP_TYPE (result) == AOP_CRY)
1856     {
1857       if (!IS_OP_RUONLY (result))
1858         aopPut (result, "c", 0);
1859     }
1860   else if (AOP_TYPE (result) != AOP_DUMMY)
1861     {
1862       emitcode ("clr", "a");
1863       emitcode ("rlc", "a");
1864       outAcc (result);
1865     }
1866 }
1867
1868 /*-----------------------------------------------------------------*/
1869 /* toBoolean - emit code for orl a,operator(sizeop)                */
1870 /*-----------------------------------------------------------------*/
1871 static void
1872 toBoolean (operand * oper)
1873 {
1874   int size = AOP_SIZE (oper) - 1;
1875   int offset = 1;
1876   bool AccUsed = FALSE;
1877   bool pushedB;
1878
1879   while (!AccUsed && size--)
1880     {
1881       AccUsed |= aopGetUsesAcc(oper, offset++);
1882     }
1883
1884   size = AOP_SIZE (oper) - 1;
1885   offset = 1;
1886   MOVA (aopGet (oper, 0, FALSE, FALSE));
1887   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1888     {
1889       pushedB = pushB ();
1890       emitcode("mov", "b,a");
1891       while (--size)
1892         {
1893           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1894           emitcode ("orl", "b,a");
1895         }
1896       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1897       emitcode ("orl", "a,b");
1898       popB (pushedB);
1899     }
1900   else
1901     {
1902       while (size--)
1903         {
1904           emitcode ("orl", "a,%s",
1905                     aopGet (oper, offset++, FALSE, FALSE));
1906         }
1907     }
1908 }
1909
1910 /*-----------------------------------------------------------------*/
1911 /* toCarry - make boolean and move into carry                      */
1912 /*-----------------------------------------------------------------*/
1913 static void
1914 toCarry (operand * oper)
1915 {
1916   /* if the operand is a literal then
1917      we know what the value is */
1918   if (AOP_TYPE (oper) == AOP_LIT)
1919     {
1920       if ((int) operandLitValue (oper))
1921         SETC;
1922       else
1923         CLRC;
1924     }
1925   else if (AOP_TYPE (oper) == AOP_CRY)
1926     {
1927       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1928     }
1929   else
1930     {
1931       /* or the operand into a */
1932       toBoolean (oper);
1933       /* set C, if a >= 1 */
1934       emitcode ("add", "a,#0xff");
1935     }
1936 }
1937
1938 /*-----------------------------------------------------------------*/
1939 /* assignBit - assign operand to bit operand                       */
1940 /*-----------------------------------------------------------------*/
1941 static void
1942 assignBit (operand * result, operand * right)
1943 {
1944   /* if the right side is a literal then
1945      we know what the value is */
1946   if (AOP_TYPE (right) == AOP_LIT)
1947     {
1948       if ((int) operandLitValue (right))
1949         aopPut (result, one, 0);
1950       else
1951         aopPut (result, zero, 0);
1952     }
1953   else
1954     {
1955       toCarry (right);
1956       aopPut (result, "c", 0);
1957     }
1958 }
1959
1960
1961 /*-------------------------------------------------------------------*/
1962 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1963 /*-------------------------------------------------------------------*/
1964 static char *
1965 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1966 {
1967   char * l;
1968
1969   if (aopGetUsesAcc (oper, offset))
1970     {
1971       emitcode("mov", "b,a");
1972       MOVA (aopGet (oper, offset, bit16, dname));
1973       emitcode("xch", "a,b");
1974       aopPut (oper, "a", offset);
1975       emitcode("xch", "a,b");
1976       l = "b";
1977     }
1978   else
1979     {
1980       l = aopGet (oper, offset, bit16, dname);
1981       emitcode("xch", "a,%s", l);
1982     }
1983   return l;
1984 }
1985
1986
1987 /*-----------------------------------------------------------------*/
1988 /* genNot - generate code for ! operation                          */
1989 /*-----------------------------------------------------------------*/
1990 static void
1991 genNot (iCode * ic)
1992 {
1993   symbol *tlbl;
1994
1995   D (emitcode (";", "genNot"));
1996
1997   /* assign asmOps to operand & result */
1998   aopOp (IC_LEFT (ic), ic, FALSE);
1999   aopOp (IC_RESULT (ic), ic, TRUE);
2000
2001   /* if in bit space then a special case */
2002   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2003     {
2004       /* if left==result then cpl bit */
2005       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2006         {
2007           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2008         }
2009       else
2010         {
2011           toCarry (IC_LEFT (ic));
2012           emitcode ("cpl", "c");
2013           outBitC (IC_RESULT (ic));
2014         }
2015       goto release;
2016     }
2017
2018   toBoolean (IC_LEFT (ic));
2019
2020   /* set C, if a == 0 */
2021   tlbl = newiTempLabel (NULL);
2022   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2023   emitLabel (tlbl);
2024   outBitC (IC_RESULT (ic));
2025
2026 release:
2027   /* release the aops */
2028   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2029   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2030 }
2031
2032
2033 /*-----------------------------------------------------------------*/
2034 /* genCpl - generate code for complement                           */
2035 /*-----------------------------------------------------------------*/
2036 static void
2037 genCpl (iCode * ic)
2038 {
2039   int offset = 0;
2040   int size;
2041   symbol *tlbl;
2042   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2043
2044   D(emitcode (";", "genCpl"));
2045
2046   /* assign asmOps to operand & result */
2047   aopOp (IC_LEFT (ic), ic, FALSE);
2048   aopOp (IC_RESULT (ic), ic, TRUE);
2049
2050   /* special case if in bit space */
2051   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2052     {
2053       char *l;
2054
2055       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2056           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2057         {
2058           /* promotion rules are responsible for this strange result:
2059              bit -> int -> ~int -> bit
2060              uchar -> int -> ~int -> bit
2061           */
2062           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2063           goto release;
2064         }
2065
2066       tlbl=newiTempLabel(NULL);
2067       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2068       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2069           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2070           IS_AOP_PREG (IC_LEFT (ic)))
2071         {
2072           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2073         }
2074       else
2075         {
2076           MOVA (l);
2077           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2078         }
2079       emitLabel (tlbl);
2080       outBitC (IC_RESULT(ic));
2081       goto release;
2082     }
2083
2084   size = AOP_SIZE (IC_RESULT (ic));
2085   while (size--)
2086     {
2087       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2088       MOVA (l);
2089       emitcode ("cpl", "a");
2090       aopPut (IC_RESULT (ic), "a", offset++);
2091     }
2092
2093
2094 release:
2095   /* release the aops */
2096   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2097   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2098 }
2099
2100 /*-----------------------------------------------------------------*/
2101 /* genUminusFloat - unary minus for floating points                */
2102 /*-----------------------------------------------------------------*/
2103 static void
2104 genUminusFloat (operand * op, operand * result)
2105 {
2106   int size, offset = 0;
2107   char *l;
2108
2109   D (emitcode (";", "genUminusFloat"));
2110
2111   /* for this we just copy and then flip the bit */
2112
2113   size = AOP_SIZE (op) - 1;
2114
2115   while (size--)
2116     {
2117       aopPut (result,
2118               aopGet (op, offset, FALSE, FALSE),
2119               offset);
2120       offset++;
2121     }
2122
2123   l = aopGet (op, offset, FALSE, FALSE);
2124   MOVA (l);
2125
2126   emitcode ("cpl", "acc.7");
2127   aopPut (result, "a", offset);
2128 }
2129
2130 /*-----------------------------------------------------------------*/
2131 /* genUminus - unary minus code generation                         */
2132 /*-----------------------------------------------------------------*/
2133 static void
2134 genUminus (iCode * ic)
2135 {
2136   int offset, size;
2137   sym_link *optype;
2138
2139   D (emitcode (";", "genUminus"));
2140
2141   /* assign asmops */
2142   aopOp (IC_LEFT (ic), ic, FALSE);
2143   aopOp (IC_RESULT (ic), ic, TRUE);
2144
2145   /* if both in bit space then special
2146      case */
2147   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2148       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2149     {
2150
2151       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2152       emitcode ("cpl", "c");
2153       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2154       goto release;
2155     }
2156
2157   optype = operandType (IC_LEFT (ic));
2158
2159   /* if float then do float stuff */
2160   if (IS_FLOAT (optype))
2161     {
2162       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2163       goto release;
2164     }
2165
2166   /* otherwise subtract from zero */
2167   size = AOP_SIZE (IC_LEFT (ic));
2168   offset = 0;
2169   while (size--)
2170     {
2171       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2172       if (!strcmp (l, "a"))
2173         {
2174           if (offset == 0)
2175             SETC;
2176           emitcode ("cpl", "a");
2177           emitcode ("addc", "a,#0");
2178         }
2179       else
2180         {
2181           if (offset == 0)
2182             CLRC;
2183           emitcode ("clr", "a");
2184           emitcode ("subb", "a,%s", l);
2185         }
2186       aopPut (IC_RESULT (ic), "a", offset++);
2187     }
2188
2189   /* if any remaining bytes in the result */
2190   /* we just need to propagate the sign   */
2191   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2192     {
2193       emitcode ("rlc", "a");
2194       emitcode ("subb", "a,acc");
2195       while (size--)
2196         aopPut (IC_RESULT (ic), "a", offset++);
2197     }
2198
2199 release:
2200   /* release the aops */
2201   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2202   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2203 }
2204
2205 /*-----------------------------------------------------------------*/
2206 /* saveRegisters - will look for a call and save the registers     */
2207 /*-----------------------------------------------------------------*/
2208 static void
2209 saveRegisters (iCode * lic)
2210 {
2211   int i;
2212   iCode *ic;
2213   bitVect *rsave;
2214
2215   /* look for call */
2216   for (ic = lic; ic; ic = ic->next)
2217     if (ic->op == CALL || ic->op == PCALL)
2218       break;
2219
2220   if (!ic)
2221     {
2222       fprintf (stderr, "found parameter push with no function call\n");
2223       return;
2224     }
2225
2226   /* if the registers have been saved already or don't need to be then
2227      do nothing */
2228   if (ic->regsSaved)
2229     return;
2230   if (IS_SYMOP(IC_LEFT(ic)) &&
2231       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2232        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2233     return;
2234
2235   /* save the registers in use at this time but skip the
2236      ones for the result */
2237   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2238                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2239
2240   ic->regsSaved = 1;
2241   if (options.useXstack)
2242     {
2243       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2244       int nBits = bitVectnBitsOn (rsavebits);
2245       int count = bitVectnBitsOn (rsave);
2246
2247       if (nBits != 0)
2248         {
2249           count = count - nBits + 1;
2250           /* remove all but the first bits as they are pushed all at once */
2251           rsave = bitVectCplAnd (rsave, rsavebits);
2252           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2253         }
2254       freeBitVect (rsavebits);
2255
2256       if (count == 1)
2257         {
2258           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2259           if (reg->type == REG_BIT)
2260             {
2261               emitcode ("mov", "a,%s", reg->base);
2262             }
2263           else
2264             {
2265               emitcode ("mov", "a,%s", reg->name);
2266             }
2267           emitcode ("mov", "r0,%s", spname);
2268           emitcode ("inc", "%s", spname);// allocate before use
2269           emitcode ("movx", "@r0,a");
2270           if (bitVectBitValue (rsave, R0_IDX))
2271             emitcode ("mov", "r0,a");
2272         }
2273       else if (count != 0)
2274         {
2275           if (bitVectBitValue (rsave, R0_IDX))
2276             {
2277               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2278             }
2279           emitcode ("mov", "r0,%s", spname);
2280           MOVA ("r0");
2281           emitcode ("add", "a,#%d", count);
2282           emitcode ("mov", "%s,a", spname);
2283           for (i = 0; i < mcs51_nRegs; i++)
2284             {
2285               if (bitVectBitValue (rsave, i))
2286                 {
2287                   regs * reg = REG_WITH_INDEX (i);
2288                   if (i == R0_IDX)
2289                     {
2290                       emitcode ("pop", "acc");
2291                       emitcode ("push", "acc");
2292                     }
2293                   else if (reg->type == REG_BIT)
2294                     {
2295                       emitcode ("mov", "a,%s", reg->base);
2296                     }
2297                   else
2298                     {
2299                       emitcode ("mov", "a,%s", reg->name);
2300                     }
2301                   emitcode ("movx", "@r0,a");
2302                   if (--count)
2303                     {
2304                       emitcode ("inc", "r0");
2305                     }
2306                 }
2307             }
2308           if (bitVectBitValue (rsave, R0_IDX))
2309             {
2310               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2311             }
2312         }
2313     }
2314   else
2315     {
2316       bool bits_pushed = FALSE;
2317       for (i = 0; i < mcs51_nRegs; i++)
2318         {
2319           if (bitVectBitValue (rsave, i))
2320             {
2321               bits_pushed = pushReg (i, bits_pushed);
2322             }
2323         }
2324     }
2325   freeBitVect (rsave);
2326 }
2327
2328 /*-----------------------------------------------------------------*/
2329 /* unsaveRegisters - pop the pushed registers                      */
2330 /*-----------------------------------------------------------------*/
2331 static void
2332 unsaveRegisters (iCode * ic)
2333 {
2334   int i;
2335   bitVect *rsave;
2336
2337   /* restore the registers in use at this time but skip the
2338      ones for the result */
2339   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2340                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2341
2342   if (options.useXstack)
2343     {
2344       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2345       int nBits = bitVectnBitsOn (rsavebits);
2346       int count = bitVectnBitsOn (rsave);
2347
2348       if (nBits != 0)
2349         {
2350           count = count - nBits + 1;
2351           /* remove all but the first bits as they are popped all at once */
2352           rsave = bitVectCplAnd (rsave, rsavebits);
2353           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2354         }
2355       freeBitVect (rsavebits);
2356
2357       if (count == 1)
2358         {
2359           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2360           emitcode ("mov", "r0,%s", spname);
2361           emitcode ("dec", "r0");
2362           emitcode ("movx", "a,@r0");
2363           if (reg->type == REG_BIT)
2364             {
2365               emitcode ("mov", "%s,a", reg->base);
2366             }
2367           else
2368             {
2369               emitcode ("mov", "%s,a", reg->name);
2370             }
2371           emitcode ("dec", "%s", spname);
2372         }
2373       else if (count != 0)
2374         {
2375           emitcode ("mov", "r0,%s", spname);
2376           for (i = mcs51_nRegs; i >= 0; i--)
2377             {
2378               if (bitVectBitValue (rsave, i))
2379                 {
2380                   regs * reg = REG_WITH_INDEX (i);
2381                   emitcode ("dec", "r0");
2382                   emitcode ("movx", "a,@r0");
2383                   if (i == R0_IDX)
2384                     {
2385                       emitcode ("push", "acc");
2386                     }
2387                   else if (reg->type == REG_BIT)
2388                     {
2389                       emitcode ("mov", "%s,a", reg->base);
2390                     }
2391                   else
2392                     {
2393                       emitcode ("mov", "%s,a", reg->name);
2394                     }
2395                 }
2396             }
2397           emitcode ("mov", "%s,r0", spname);
2398           if (bitVectBitValue (rsave, R0_IDX))
2399             {
2400               emitcode ("pop", "ar0");
2401             }
2402         }
2403     }
2404   else
2405     {
2406       bool bits_popped = FALSE;
2407       for (i = mcs51_nRegs; i >= 0; i--)
2408         {
2409           if (bitVectBitValue (rsave, i))
2410             {
2411               bits_popped = popReg (i, bits_popped);
2412             }
2413         }
2414     }
2415   freeBitVect (rsave);
2416 }
2417
2418
2419 /*-----------------------------------------------------------------*/
2420 /* pushSide -                                                      */
2421 /*-----------------------------------------------------------------*/
2422 static void
2423 pushSide (operand * oper, int size, iCode * ic)
2424 {
2425   int offset = 0;
2426   int nPushed = _G.r0Pushed + _G.r1Pushed;
2427
2428   aopOp (oper, ic, FALSE);
2429
2430   if (nPushed != _G.r0Pushed + _G.r1Pushed)
2431     {
2432       while (offset < size)
2433         {
2434           char *l = aopGet (oper, offset, FALSE, TRUE);
2435           emitcode ("mov", "%s,%s", fReturn[offset++], l);
2436         }
2437       freeAsmop (oper, NULL, ic, TRUE);
2438       offset = 0;
2439       while (offset < size)
2440         {
2441           emitcode ("push", "%s", fReturn[offset++]);
2442         }
2443       return;
2444     }
2445     
2446   while (size--)
2447     {
2448       char *l = aopGet (oper, offset++, FALSE, TRUE);
2449       if (AOP_TYPE (oper) != AOP_REG &&
2450           AOP_TYPE (oper) != AOP_DIR &&
2451           strcmp (l, "a"))
2452         {
2453           MOVA (l);
2454           emitcode ("push", "acc");
2455         }
2456       else
2457         {
2458           emitcode ("push", "%s", l);
2459         }
2460     }
2461
2462   freeAsmop (oper, NULL, ic, TRUE);
2463 }
2464
2465 /*-----------------------------------------------------------------*/
2466 /* assignResultValue - also indicates if acc is in use afterwards  */
2467 /*-----------------------------------------------------------------*/
2468 static bool
2469 assignResultValue (operand * oper, operand * func)
2470 {
2471   int offset = 0;
2472   int size = AOP_SIZE (oper);
2473   bool accuse = FALSE;
2474   bool pushedA = FALSE;
2475
2476   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2477     {
2478       outBitC (oper);
2479       return FALSE;
2480     }
2481
2482   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2483     {
2484       emitcode ("push", "acc");
2485       pushedA = TRUE;
2486     }
2487   while (size--)
2488     {
2489       if ((offset == 3) && pushedA)
2490         emitcode ("pop", "acc");
2491       accuse |= aopPut (oper, fReturn[offset], offset);
2492       offset++;
2493     }
2494   return accuse;
2495 }
2496
2497
2498 /*-----------------------------------------------------------------*/
2499 /* genXpush - pushes onto the external stack                       */
2500 /*-----------------------------------------------------------------*/
2501 static void
2502 genXpush (iCode * ic)
2503 {
2504   asmop *aop = newAsmop (0);
2505   regs *r;
2506   int size, offset = 0;
2507
2508   D (emitcode (";", "genXpush"));
2509
2510   aopOp (IC_LEFT (ic), ic, FALSE);
2511   r = getFreePtr (ic, &aop, FALSE);
2512
2513   size = AOP_SIZE (IC_LEFT (ic));
2514
2515   if (size == 1)
2516     {
2517       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2518       emitcode ("mov", "%s,%s", r->name, spname);
2519       emitcode ("inc", "%s", spname); // allocate space first
2520       emitcode ("movx", "@%s,a", r->name);
2521     }
2522   else
2523     {
2524       // allocate space first
2525       emitcode ("mov", "%s,%s", r->name, spname);
2526       MOVA (r->name);
2527       emitcode ("add", "a,#%d", size);
2528       emitcode ("mov", "%s,a", spname);
2529
2530       while (size--)
2531         {
2532           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2533           emitcode ("movx", "@%s,a", r->name);
2534           emitcode ("inc", "%s", r->name);
2535         }
2536     }
2537
2538   freeAsmop (NULL, aop, ic, TRUE);
2539   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2540 }
2541
2542 /*-----------------------------------------------------------------*/
2543 /* genIpush - generate code for pushing this gets a little complex */
2544 /*-----------------------------------------------------------------*/
2545 static void
2546 genIpush (iCode * ic)
2547 {
2548   int size, offset = 0;
2549   char *l;
2550   char *prev = "";
2551
2552   D (emitcode (";", "genIpush"));
2553
2554   /* if this is not a parm push : ie. it is spill push
2555      and spill push is always done on the local stack */
2556   if (!ic->parmPush)
2557     {
2558
2559       /* and the item is spilt then do nothing */
2560       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2561         return;
2562
2563       aopOp (IC_LEFT (ic), ic, FALSE);
2564       size = AOP_SIZE (IC_LEFT (ic));
2565       /* push it on the stack */
2566       while (size--)
2567         {
2568           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2569           if (*l == '#')
2570             {
2571               MOVA (l);
2572               l = "acc";
2573             }
2574           emitcode ("push", "%s", l);
2575         }
2576       return;
2577     }
2578
2579   /* this is a parameter push: in this case we call
2580      the routine to find the call and save those
2581      registers that need to be saved */
2582   saveRegisters (ic);
2583
2584   /* if use external stack then call the external
2585      stack pushing routine */
2586   if (options.useXstack)
2587     {
2588       genXpush (ic);
2589       return;
2590     }
2591
2592   /* then do the push */
2593   aopOp (IC_LEFT (ic), ic, FALSE);
2594
2595   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2596   size = AOP_SIZE (IC_LEFT (ic));
2597
2598   while (size--)
2599     {
2600       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2601       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2602           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2603         {
2604           if (strcmp (l, prev) || *l == '@')
2605             MOVA (l);
2606           emitcode ("push", "acc");
2607         }
2608       else
2609         {
2610           emitcode ("push", "%s", l);
2611         }
2612       prev = l;
2613     }
2614
2615   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2616 }
2617
2618 /*-----------------------------------------------------------------*/
2619 /* genIpop - recover the registers: can happen only for spilling   */
2620 /*-----------------------------------------------------------------*/
2621 static void
2622 genIpop (iCode * ic)
2623 {
2624   int size, offset;
2625
2626   D (emitcode (";", "genIpop"));
2627
2628   /* if the temp was not pushed then */
2629   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2630     return;
2631
2632   aopOp (IC_LEFT (ic), ic, FALSE);
2633   size = AOP_SIZE (IC_LEFT (ic));
2634   offset = (size - 1);
2635   while (size--)
2636     {
2637       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2638                                      FALSE, TRUE));
2639     }
2640
2641   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2642 }
2643
2644 /*-----------------------------------------------------------------*/
2645 /* saveRBank - saves an entire register bank on the stack          */
2646 /*-----------------------------------------------------------------*/
2647 static void
2648 saveRBank (int bank, iCode * ic, bool pushPsw)
2649 {
2650   int i;
2651   int count = 8 + (pushPsw ? 1 : 0);
2652   asmop *aop = NULL;
2653   regs *r = NULL;
2654
2655   if (options.useXstack)
2656     {
2657       if (!ic)
2658         {
2659           /* Assume r0 is available for use. */
2660           r = REG_WITH_INDEX (R0_IDX);
2661         }
2662       else
2663         {
2664           aop = newAsmop (0);
2665           r = getFreePtr (ic, &aop, FALSE);
2666         }
2667       // allocate space first
2668       emitcode ("mov", "%s,%s", r->name, spname);
2669       MOVA (r->name);
2670       emitcode ("add", "a,#%d", count);
2671       emitcode ("mov", "%s,a", spname);
2672     }
2673
2674   for (i = 0; i < 8; i++)
2675     {
2676       if (options.useXstack)
2677         {
2678           emitcode ("mov", "a,(%s+%d)",
2679                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2680           emitcode ("movx", "@%s,a", r->name);
2681           if (--count)
2682             emitcode ("inc", "%s", r->name);
2683         }
2684       else
2685         emitcode ("push", "(%s+%d)",
2686                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2687     }
2688
2689   if (pushPsw)
2690     {
2691       if (options.useXstack)
2692         {
2693           emitcode ("mov", "a,psw");
2694           emitcode ("movx", "@%s,a", r->name);
2695         }
2696       else
2697         {
2698           emitcode ("push", "psw");
2699         }
2700
2701       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2702     }
2703
2704   if (aop)
2705     {
2706       freeAsmop (NULL, aop, ic, TRUE);
2707     }
2708
2709   if (ic)
2710     {
2711       ic->bankSaved = 1;
2712     }
2713 }
2714
2715 /*-----------------------------------------------------------------*/
2716 /* unsaveRBank - restores the register bank from stack             */
2717 /*-----------------------------------------------------------------*/
2718 static void
2719 unsaveRBank (int bank, iCode * ic, bool popPsw)
2720 {
2721   int i;
2722   asmop *aop = NULL;
2723   regs *r = NULL;
2724
2725   if (options.useXstack)
2726     {
2727       if (!ic)
2728         {
2729           /* Assume r0 is available for use. */
2730           r = REG_WITH_INDEX (R0_IDX);;
2731         }
2732       else
2733         {
2734           aop = newAsmop (0);
2735           r = getFreePtr (ic, &aop, FALSE);
2736         }
2737       emitcode ("mov", "%s,%s", r->name, spname);
2738     }
2739
2740   if (popPsw)
2741     {
2742       if (options.useXstack)
2743         {
2744           emitcode ("dec", "%s", r->name);
2745           emitcode ("movx", "a,@%s", r->name);
2746           emitcode ("mov", "psw,a");
2747         }
2748       else
2749         {
2750           emitcode ("pop", "psw");
2751         }
2752     }
2753
2754   for (i = 7; i >= 0; i--)
2755     {
2756       if (options.useXstack)
2757         {
2758           emitcode ("dec", "%s", r->name);
2759           emitcode ("movx", "a,@%s", r->name);
2760           emitcode ("mov", "(%s+%d),a",
2761                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2762         }
2763       else
2764         {
2765           emitcode ("pop", "(%s+%d)",
2766                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2767         }
2768     }
2769
2770   if (options.useXstack)
2771     {
2772       emitcode ("mov", "%s,%s", spname, r->name);
2773     }
2774
2775   if (aop)
2776     {
2777       freeAsmop (NULL, aop, ic, TRUE);
2778     }
2779 }
2780
2781 /*-----------------------------------------------------------------*/
2782 /* genSend - gen code for SEND                                     */
2783 /*-----------------------------------------------------------------*/
2784 static void genSend(set *sendSet)
2785 {
2786   iCode *sic;
2787   int bit_count = 0;
2788
2789   /* first we do all bit parameters */
2790   for (sic = setFirstItem (sendSet); sic;
2791        sic = setNextItem (sendSet))
2792     {
2793       if (sic->argreg > 12)
2794         {
2795           int bit = sic->argreg-13;
2796
2797           aopOp (IC_LEFT (sic), sic, FALSE);
2798
2799           /* if left is a literal then
2800              we know what the value is */
2801           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2802             {
2803               if (((int) operandLitValue (IC_LEFT (sic))))
2804                   emitcode ("setb", "b[%d]", bit);
2805               else
2806                   emitcode ("clr", "b[%d]", bit);
2807             }
2808           else
2809             {
2810               /* we need to or */
2811               toCarry (IC_LEFT (sic));
2812               emitcode ("mov", "b[%d],c", bit);
2813             }
2814           bit_count++;
2815           BitBankUsed = 1;
2816
2817           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2818         }
2819     }
2820
2821   if (bit_count)
2822     {
2823       saveRegisters (setFirstItem (sendSet));
2824       emitcode ("mov", "bits,b");
2825     }
2826
2827   /* then we do all other parameters */
2828   for (sic = setFirstItem (sendSet); sic;
2829        sic = setNextItem (sendSet))
2830     {
2831       if (sic->argreg <= 12)
2832         {
2833           int size, offset = 0;
2834           aopOp (IC_LEFT (sic), sic, FALSE);
2835           size = AOP_SIZE (IC_LEFT (sic));
2836
2837           if (sic->argreg == 1)
2838             {
2839               while (size--)
2840                 {
2841                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2842                   if (strcmp (l, fReturn[offset]))
2843                     {
2844                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2845                     }
2846                   offset++;
2847                 }
2848             }
2849           else
2850             {
2851               while (size--)
2852                 {
2853                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2854                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2855                   offset++;
2856                 }
2857             }
2858           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2859         }
2860     }
2861 }
2862
2863 /*-----------------------------------------------------------------*/
2864 /* selectRegBank - emit code to select the register bank           */
2865 /*-----------------------------------------------------------------*/
2866 static void
2867 selectRegBank (short bank, bool keepFlags)
2868 {
2869   /* if f.e. result is in carry */
2870   if (keepFlags)
2871     {
2872       emitcode ("anl", "psw,#0xE7");
2873       if (bank)
2874         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2875     }
2876   else
2877     {
2878       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2879     }
2880 }
2881
2882 /*-----------------------------------------------------------------*/
2883 /* genCall - generates a call statement                            */
2884 /*-----------------------------------------------------------------*/
2885 static void
2886 genCall (iCode * ic)
2887 {
2888   sym_link *dtype;
2889   sym_link *etype;
2890 //  bool restoreBank = FALSE;
2891   bool swapBanks = FALSE;
2892   bool accuse = FALSE;
2893   bool accPushed = FALSE;
2894   bool resultInF0 = FALSE;
2895   bool assignResultGenerated = FALSE;
2896
2897   D (emitcode (";", "genCall"));
2898
2899   dtype = operandType (IC_LEFT (ic));
2900   etype = getSpec(dtype);
2901   /* if send set is not empty then assign */
2902   if (_G.sendSet)
2903     {
2904         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2905             genSend(reverseSet(_G.sendSet));
2906         } else {
2907             genSend(_G.sendSet);
2908         }
2909       _G.sendSet = NULL;
2910     }
2911
2912   /* if we are calling a not _naked function that is not using
2913      the same register bank then we need to save the
2914      destination registers on the stack */
2915   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2916       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2917        !IFFUNC_ISISR (dtype))
2918     {
2919       swapBanks = TRUE;
2920     }
2921
2922   /* if caller saves & we have not saved then */
2923   if (!ic->regsSaved)
2924       saveRegisters (ic);
2925
2926   if (swapBanks)
2927     {
2928         emitcode ("mov", "psw,#0x%02x",
2929            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2930     }
2931
2932   /* make the call */
2933   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2934     {
2935       if (IFFUNC_CALLEESAVES(dtype))
2936         {
2937           werror (E_BANKED_WITH_CALLEESAVES);
2938         }
2939       else
2940         {
2941           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2942                      OP_SYMBOL (IC_LEFT (ic))->rname :
2943                      OP_SYMBOL (IC_LEFT (ic))->name);
2944
2945           emitcode ("mov", "r0,#%s", l);
2946           emitcode ("mov", "r1,#(%s >> 8)", l);
2947           emitcode ("mov", "r2,#(%s >> 16)", l);
2948           emitcode ("lcall", "__sdcc_banked_call");
2949         }
2950     }
2951   else
2952     {
2953       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2954                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2955                                 OP_SYMBOL (IC_LEFT (ic))->name));
2956     }
2957
2958   if (swapBanks)
2959     {
2960       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2961     }
2962
2963   /* if we need assign a result value */
2964   if ((IS_ITEMP (IC_RESULT (ic)) &&
2965        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2966        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2967         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2968         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2969       IS_TRUE_SYMOP (IC_RESULT (ic)))
2970     {
2971
2972       _G.accInUse++;
2973       aopOp (IC_RESULT (ic), ic, FALSE);
2974       _G.accInUse--;
2975
2976       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2977       assignResultGenerated = TRUE;
2978
2979       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2980     }
2981
2982   /* adjust the stack for parameters if required */
2983   if (ic->parmBytes)
2984     {
2985       int i;
2986       if (ic->parmBytes > 3)
2987         {
2988           if (accuse)
2989             {
2990               emitcode ("push", "acc");
2991               accPushed = TRUE;
2992             }
2993           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2994               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2995               !assignResultGenerated)
2996             {
2997               emitcode ("mov", "F0,c");
2998               resultInF0 = TRUE;
2999             }
3000
3001           emitcode ("mov", "a,%s", spname);
3002           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3003           emitcode ("mov", "%s,a", spname);
3004
3005           /* unsaveRegisters from xstack needs acc, but */
3006           /* unsaveRegisters from stack needs this popped */
3007           if (accPushed && !options.useXstack)
3008             {
3009               emitcode ("pop", "acc");
3010               accPushed = FALSE;
3011             }
3012         }
3013       else
3014         for (i = 0; i < ic->parmBytes; i++)
3015           emitcode ("dec", "%s", spname);
3016     }
3017
3018   /* if we had saved some registers then unsave them */
3019   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3020     {
3021       if (accuse && !accPushed && options.useXstack)
3022         {
3023           /* xstack needs acc, but doesn't touch normal stack */
3024           emitcode ("push", "acc");
3025           accPushed = TRUE;
3026         }
3027       unsaveRegisters (ic);
3028     }
3029
3030 //  /* if register bank was saved then pop them */
3031 //  if (restoreBank)
3032 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3033
3034   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3035     {
3036       if (resultInF0)
3037           emitcode ("mov", "c,F0");
3038
3039       aopOp (IC_RESULT (ic), ic, FALSE);
3040       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3041       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3042     }
3043
3044   if (accPushed)
3045     emitcode ("pop", "acc");
3046 }
3047
3048 /*-----------------------------------------------------------------*/
3049 /* genPcall - generates a call by pointer statement                */
3050 /*-----------------------------------------------------------------*/
3051 static void
3052 genPcall (iCode * ic)
3053 {
3054   sym_link *dtype;
3055   sym_link *etype;
3056   symbol *rlbl = newiTempLabel (NULL);
3057 //  bool restoreBank=FALSE;
3058   bool swapBanks = FALSE;
3059   bool resultInF0 = FALSE;
3060
3061   D (emitcode (";", "genPcall"));
3062
3063   dtype = operandType (IC_LEFT (ic))->next;
3064   etype = getSpec(dtype);
3065   /* if caller saves & we have not saved then */
3066   if (!ic->regsSaved)
3067     saveRegisters (ic);
3068
3069   /* if we are calling a not _naked function that is not using
3070      the same register bank then we need to save the
3071      destination registers on the stack */
3072   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3073       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3074       !IFFUNC_ISISR (dtype))
3075     {
3076 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3077 //    restoreBank=TRUE;
3078       swapBanks = TRUE;
3079       // need caution message to user here
3080     }
3081
3082   if (IS_LITERAL (etype))
3083     {
3084       /* if send set is not empty then assign */
3085       if (_G.sendSet)
3086         {
3087           genSend(reverseSet(_G.sendSet));
3088           _G.sendSet = NULL;
3089         }
3090
3091       if (swapBanks)
3092         {
3093           emitcode ("mov", "psw,#0x%02x",
3094            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3095         }
3096
3097       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3098         {
3099           if (IFFUNC_CALLEESAVES (dtype))
3100             {
3101               werror (E_BANKED_WITH_CALLEESAVES);
3102             }
3103           else
3104             {
3105               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3106
3107               emitcode ("mov", "r0,#%s", l);
3108               emitcode ("mov", "r1,#(%s >> 8)", l);
3109               emitcode ("mov", "r2,#(%s >> 16)", l);
3110               emitcode ("lcall", "__sdcc_banked_call");
3111             }
3112         }
3113       else
3114         {
3115           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3116         }
3117     }
3118   else
3119     {
3120       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3121         {
3122           if (IFFUNC_CALLEESAVES (dtype))
3123             {
3124               werror (E_BANKED_WITH_CALLEESAVES);
3125             }
3126           else
3127             {
3128               aopOp (IC_LEFT (ic), ic, FALSE);
3129
3130               if (!swapBanks)
3131                 {
3132                   /* what if aopGet needs r0 or r1 ??? */
3133                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3134                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3135                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3136                 }
3137               else
3138                 {
3139                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3140                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3141                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3142                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3143                 }
3144
3145               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3146
3147               /* if send set is not empty then assign */
3148               if (_G.sendSet)
3149                 {
3150                   genSend(reverseSet(_G.sendSet));
3151                   _G.sendSet = NULL;
3152                 }
3153
3154               if (swapBanks)
3155                 {
3156                   emitcode ("mov", "psw,#0x%02x",
3157                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3158                 }
3159
3160               /* make the call */
3161               emitcode ("lcall", "__sdcc_banked_call");
3162             }
3163         }
3164       else if (_G.sendSet)
3165         {
3166           /* push the return address on to the stack */
3167           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3168           emitcode ("push", "acc");
3169           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3170           emitcode ("push", "acc");
3171
3172           /* now push the calling address */
3173           pushSide (IC_LEFT (ic), FPTRSIZE, ic);
3174
3175           /* if send set is not empty then assign */
3176           if (_G.sendSet)
3177             {
3178               genSend(reverseSet(_G.sendSet));
3179               _G.sendSet = NULL;
3180             }
3181
3182           if (swapBanks)
3183             {
3184               emitcode ("mov", "psw,#0x%02x",
3185                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3186             }
3187
3188           /* make the call */
3189           emitcode ("ret", "");
3190           emitLabel (rlbl);
3191         }
3192       else /* the send set is empty */
3193         {
3194           char *l;
3195           /* now get the calling address into dptr */
3196           aopOp (IC_LEFT (ic), ic, FALSE);
3197
3198           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3199           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3200             {
3201               emitcode ("mov", "r0,%s", l);
3202               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3203               emitcode ("mov", "dph,%s", l);
3204               emitcode ("mov", "dpl,r0");
3205             }
3206           else
3207             {
3208               emitcode ("mov", "dpl,%s", l);
3209               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3210               emitcode ("mov", "dph,%s", l);
3211             }
3212
3213           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3214
3215           if (swapBanks)
3216             {
3217               emitcode ("mov", "psw,#0x%02x",
3218                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3219             }
3220
3221           /* make the call */
3222           emitcode ("lcall", "__sdcc_call_dptr");
3223         }
3224     }
3225   if (swapBanks)
3226     {
3227       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3228     }
3229
3230   /* if we need assign a result value */
3231   if ((IS_ITEMP (IC_RESULT (ic)) &&
3232        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3233        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3234         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3235       IS_TRUE_SYMOP (IC_RESULT (ic)))
3236     {
3237
3238       _G.accInUse++;
3239       aopOp (IC_RESULT (ic), ic, FALSE);
3240       _G.accInUse--;
3241
3242       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3243
3244       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3245     }
3246
3247   /* adjust the stack for parameters if required */
3248   if (ic->parmBytes)
3249     {
3250       int i;
3251       if (ic->parmBytes > 3)
3252         {
3253           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3254               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3255             {
3256               emitcode ("mov", "F0,c");
3257               resultInF0 = TRUE;
3258             }
3259
3260           emitcode ("mov", "a,%s", spname);
3261           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3262           emitcode ("mov", "%s,a", spname);
3263         }
3264       else
3265         for (i = 0; i < ic->parmBytes; i++)
3266           emitcode ("dec", "%s", spname);
3267     }
3268
3269 //  /* if register bank was saved then unsave them */
3270 //  if (restoreBank)
3271 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3272
3273   /* if we had saved some registers then unsave them */
3274   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3275     unsaveRegisters (ic);
3276
3277   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3278     {
3279       if (resultInF0)
3280           emitcode ("mov", "c,F0");
3281
3282       aopOp (IC_RESULT (ic), ic, FALSE);
3283       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3284       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3285     }
3286 }
3287
3288 /*-----------------------------------------------------------------*/
3289 /* resultRemat - result  is rematerializable                       */
3290 /*-----------------------------------------------------------------*/
3291 static int
3292 resultRemat (iCode * ic)
3293 {
3294   if (SKIP_IC (ic) || ic->op == IFX)
3295     return 0;
3296
3297   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3298     {
3299       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3300       if (sym->remat && !POINTER_SET (ic))
3301         return 1;
3302     }
3303
3304   return 0;
3305 }
3306
3307 /*-----------------------------------------------------------------*/
3308 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3309 /*-----------------------------------------------------------------*/
3310 static int
3311 regsCmp(void *p1, void *p2)
3312 {
3313   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3314 }
3315
3316 static bool
3317 inExcludeList (char *s)
3318 {
3319   const char *p = setFirstItem(options.excludeRegsSet);
3320
3321   if (p == NULL || STRCASECMP(p, "none") == 0)
3322     return FALSE;
3323
3324
3325   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3326 }
3327
3328 /*-----------------------------------------------------------------*/
3329 /* genFunction - generated code for function entry                 */
3330 /*-----------------------------------------------------------------*/
3331 static void
3332 genFunction (iCode * ic)
3333 {
3334   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3335   sym_link *ftype;
3336   bool     switchedPSW = FALSE;
3337   int      calleesaves_saved_register = -1;
3338   int      stackAdjust = sym->stack;
3339   int      accIsFree = sym->recvSize < 4;
3340   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3341   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3342
3343   _G.nRegsSaved = 0;
3344   /* create the function header */
3345   emitcode (";", "-----------------------------------------");
3346   emitcode (";", " function %s", sym->name);
3347   emitcode (";", "-----------------------------------------");
3348
3349   emitcode ("", "%s:", sym->rname);
3350   lineCurr->isLabel = 1;
3351   ftype = operandType (IC_LEFT (ic));
3352   _G.currentFunc = sym;
3353
3354   if (IFFUNC_ISNAKED(ftype))
3355   {
3356       emitcode(";", "naked function: no prologue.");
3357       return;
3358   }
3359
3360   /* here we need to generate the equates for the
3361      register bank if required */
3362   if (FUNC_REGBANK (ftype) != rbank)
3363     {
3364       int i;
3365
3366       rbank = FUNC_REGBANK (ftype);
3367       for (i = 0; i < mcs51_nRegs; i++)
3368         {
3369           if (regs8051[i].type != REG_BIT)
3370             {
3371               if (strcmp (regs8051[i].base, "0") == 0)
3372                 emitcode ("", "%s = 0x%02x",
3373                           regs8051[i].dname,
3374                           8 * rbank + regs8051[i].offset);
3375               else
3376                 emitcode ("", "%s = %s + 0x%02x",
3377                           regs8051[i].dname,
3378                           regs8051[i].base,
3379                           8 * rbank + regs8051[i].offset);
3380             }
3381         }
3382     }
3383
3384   /* if this is an interrupt service routine then
3385      save acc, b, dpl, dph  */
3386   if (IFFUNC_ISISR (sym->type))
3387     {
3388       bitVect *rsavebits;
3389
3390       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3391       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3392         {
3393           emitcode ("push", "bits");
3394           BitBankUsed = 1;
3395         }
3396       freeBitVect (rsavebits);
3397
3398       if (!inExcludeList ("acc"))
3399         emitcode ("push", "acc");
3400       if (!inExcludeList ("b"))
3401         emitcode ("push", "b");
3402       if (!inExcludeList ("dpl"))
3403         emitcode ("push", "dpl");
3404       if (!inExcludeList ("dph"))
3405         emitcode ("push", "dph");
3406       /* if this isr has no bank i.e. is going to
3407          run with bank 0 , then we need to save more
3408          registers :-) */
3409       if (!FUNC_REGBANK (sym->type))
3410         {
3411           int i;
3412
3413           /* if this function does not call any other
3414              function then we can be economical and
3415              save only those registers that are used */
3416           if (!IFFUNC_HASFCALL(sym->type))
3417             {
3418               /* if any registers used */
3419               if (sym->regsUsed)
3420                 {
3421                   /* save the registers used */
3422                   for (i = 0; i < sym->regsUsed->size; i++)
3423                     {
3424                       if (bitVectBitValue (sym->regsUsed, i))
3425                         pushReg (i, TRUE);
3426                     }
3427                 }
3428             }
3429           else
3430             {
3431               /* this function has a function call. We cannot
3432                  determine register usage so we will have to push the
3433                  entire bank */
3434                 saveRBank (0, ic, FALSE);
3435                 if (options.parms_in_bank1) {
3436                     for (i=0; i < 8 ; i++ ) {
3437                         emitcode ("push","%s",rb1regs[i]);
3438                     }
3439                 }
3440             }
3441         }
3442       else
3443         {
3444             /* This ISR uses a non-zero bank.
3445              *
3446              * We assume that the bank is available for our
3447              * exclusive use.
3448              *
3449              * However, if this ISR calls a function which uses some
3450              * other bank, we must save that bank entirely.
3451              */
3452             unsigned long banksToSave = 0;
3453
3454             if (IFFUNC_HASFCALL(sym->type))
3455             {
3456
3457 #define MAX_REGISTER_BANKS 4
3458
3459                 iCode *i;
3460                 int ix;
3461
3462                 for (i = ic; i; i = i->next)
3463                 {
3464                     if (i->op == ENDFUNCTION)
3465                     {
3466                         /* we got to the end OK. */
3467                         break;
3468                     }
3469
3470                     if (i->op == CALL)
3471                     {
3472                         sym_link *dtype;
3473
3474                         dtype = operandType (IC_LEFT(i));
3475                         if (dtype
3476                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3477                         {
3478                              /* Mark this bank for saving. */
3479                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3480                              {
3481                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3482                              }
3483                              else
3484                              {
3485                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3486                              }
3487
3488                              /* And note that we don't need to do it in
3489                               * genCall.
3490                               */
3491                              i->bankSaved = 1;
3492                         }
3493                     }
3494                     if (i->op == PCALL)
3495                     {
3496                         /* This is a mess; we have no idea what
3497                          * register bank the called function might
3498                          * use.
3499                          *
3500                          * The only thing I can think of to do is
3501                          * throw a warning and hope.
3502                          */
3503                         werror(W_FUNCPTR_IN_USING_ISR);
3504                     }
3505                 }
3506
3507                 if (banksToSave && options.useXstack)
3508                 {
3509                     /* Since we aren't passing it an ic,
3510                      * saveRBank will assume r0 is available to abuse.
3511                      *
3512                      * So switch to our (trashable) bank now, so
3513                      * the caller's R0 isn't trashed.
3514                      */
3515                     emitcode ("push", "psw");
3516                     emitcode ("mov", "psw,#0x%02x",
3517                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3518                     switchedPSW = TRUE;
3519                 }
3520
3521                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3522                 {
3523                      if (banksToSave & (1 << ix))
3524                      {
3525                          saveRBank(ix, NULL, FALSE);
3526                      }
3527                 }
3528             }
3529             // TODO: this needs a closer look
3530             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3531         }
3532
3533       /* Set the register bank to the desired value if nothing else */
3534       /* has done so yet. */
3535       if (!switchedPSW)
3536         {
3537           emitcode ("push", "psw");
3538           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3539         }
3540     }
3541   else
3542     {
3543       /* This is a non-ISR function. The caller has already switched register */
3544       /* banks, if necessary, so just handle the callee-saves option. */
3545
3546       /* if callee-save to be used for this function
3547          then save the registers being used in this function */
3548       if (IFFUNC_CALLEESAVES(sym->type))
3549         {
3550           int i;
3551
3552           /* if any registers used */
3553           if (sym->regsUsed)
3554             {
3555               bool bits_pushed = FALSE;
3556               /* save the registers used */
3557               for (i = 0; i < sym->regsUsed->size; i++)
3558                 {
3559                   if (bitVectBitValue (sym->regsUsed, i))
3560                     {
3561                       /* remember one saved register for later usage */
3562                       if (calleesaves_saved_register < 0)
3563                         calleesaves_saved_register = i;
3564                       bits_pushed = pushReg (i, bits_pushed);
3565                       _G.nRegsSaved++;
3566                     }
3567                 }
3568             }
3569         }
3570     }
3571
3572   if (fReentrant)
3573     {
3574       if (options.useXstack)
3575         {
3576           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3577             {
3578               emitcode ("mov", "r0,%s", spname);
3579               emitcode ("inc", "%s", spname);
3580               emitcode ("xch", "a,_bpx");
3581               emitcode ("movx", "@r0,a");
3582               emitcode ("inc", "r0");
3583               emitcode ("mov", "a,r0");
3584               emitcode ("xch", "a,_bpx");
3585             }
3586           if (sym->stack)
3587             {
3588               emitcode ("push", "_bp");     /* save the callers stack  */
3589               emitcode ("mov", "_bp,sp");
3590             }
3591         }
3592       else
3593         {
3594           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3595             {
3596               /* set up the stack */
3597               emitcode ("push", "_bp");     /* save the callers stack  */
3598               emitcode ("mov", "_bp,sp");
3599             }
3600         }
3601     }
3602
3603   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3604   /* before setting up the stack frame completely. */
3605   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3606     {
3607       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3608
3609       if (rsym->isitmp)
3610         {
3611           if (rsym && rsym->regType == REG_CND)
3612             rsym = NULL;
3613           if (rsym && (rsym->accuse || rsym->ruonly))
3614             rsym = NULL;
3615           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3616             rsym = rsym->usl.spillLoc;
3617         }
3618
3619       /* If the RECEIVE operand immediately spills to the first entry on the */
3620       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3621       /* rather than the usual @r0/r1 machinations. */
3622       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3623         {
3624           int ofs;
3625
3626           _G.current_iCode = ric;
3627           D(emitcode (";", "genReceive"));
3628           for (ofs=0; ofs < sym->recvSize; ofs++)
3629             {
3630               if (!strcmp (fReturn[ofs], "a"))
3631                 emitcode ("push", "acc");
3632               else
3633                 emitcode ("push", fReturn[ofs]);
3634             }
3635           stackAdjust -= sym->recvSize;
3636           if (stackAdjust<0)
3637             {
3638               assert (stackAdjust>=0);
3639               stackAdjust = 0;
3640             }
3641           _G.current_iCode = ic;
3642           ric->generated = 1;
3643           accIsFree = 1;
3644         }
3645       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3646       /* to free up the accumulator. */
3647       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3648         {
3649           int ofs;
3650
3651           _G.current_iCode = ric;
3652           D(emitcode (";", "genReceive"));
3653           for (ofs=0; ofs < sym->recvSize; ofs++)
3654             {
3655               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3656             }
3657           _G.current_iCode = ic;
3658           ric->generated = 1;
3659           accIsFree = 1;
3660         }
3661     }
3662
3663   /* adjust the stack for the function */
3664   if (stackAdjust)
3665     {
3666       int i = stackAdjust;
3667       if (i > 256)
3668         werror (W_STACK_OVERFLOW, sym->name);
3669
3670       if (i > 3 && accIsFree)
3671         {
3672           emitcode ("mov", "a,sp");
3673           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3674           emitcode ("mov", "sp,a");
3675         }
3676       else if (i > 5)
3677         {
3678           /* The accumulator is not free, so we will need another register */
3679           /* to clobber. No need to worry about a possible conflict with */
3680           /* the above early RECEIVE optimizations since they would have */
3681           /* freed the accumulator if they were generated. */
3682
3683           if (IFFUNC_CALLEESAVES(sym->type))
3684             {
3685               /* if it's a callee-saves function we need a saved register */
3686               if (calleesaves_saved_register >= 0)
3687                 {
3688                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3689                   emitcode ("mov", "a,sp");
3690                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3691                   emitcode ("mov", "sp,a");
3692                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3693                 }
3694               else
3695                 /* do it the hard way */
3696                 while (i--)
3697                   emitcode ("inc", "sp");
3698             }
3699           else
3700             {
3701               /* not callee-saves, we can clobber r0 */
3702               emitcode ("mov", "r0,a");
3703               emitcode ("mov", "a,sp");
3704               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3705               emitcode ("mov", "sp,a");
3706               emitcode ("mov", "a,r0");
3707             }
3708         }
3709       else
3710         while (i--)
3711           emitcode ("inc", "sp");
3712     }
3713
3714   if (sym->xstack)
3715     {
3716       char i = ((char) sym->xstack & 0xff);
3717
3718       if (i > 3 && accIsFree)
3719         {
3720           emitcode ("mov", "a,_spx");
3721           emitcode ("add", "a,#0x%02x", i & 0xff);
3722           emitcode ("mov", "_spx,a");
3723         }
3724       else if (i > 5)
3725         {
3726           emitcode ("push", "acc");
3727           emitcode ("mov", "a,_spx");
3728           emitcode ("add", "a,#0x%02x", i & 0xff);
3729           emitcode ("mov", "_spx,a");
3730           emitcode ("pop", "acc");
3731         }
3732       else
3733         {
3734           while (i--)
3735             emitcode ("inc", "_spx");
3736         }
3737     }
3738
3739   /* if critical function then turn interrupts off */
3740   if (IFFUNC_ISCRITICAL (ftype))
3741     {
3742       symbol *tlbl = newiTempLabel (NULL);
3743       emitcode ("setb", "c");
3744       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3745       emitcode ("clr", "c");
3746       emitLabel (tlbl);
3747       emitcode ("push", "psw"); /* save old ea via c in psw */
3748     }
3749 }
3750
3751 /*-----------------------------------------------------------------*/
3752 /* genEndFunction - generates epilogue for functions               */
3753 /*-----------------------------------------------------------------*/
3754 static void
3755 genEndFunction (iCode * ic)
3756 {
3757   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3758   lineNode *lnp = lineCurr;
3759   bitVect  *regsUsed;
3760   bitVect  *regsUsedPrologue;
3761   bitVect  *regsUnneeded;
3762   int      idx;
3763
3764   _G.currentFunc = NULL;
3765   if (IFFUNC_ISNAKED(sym->type))
3766   {
3767       emitcode(";", "naked function: no epilogue.");
3768       if (options.debug && currFunc)
3769         debugFile->writeEndFunction (currFunc, ic, 0);
3770       return;
3771   }
3772
3773   if (IFFUNC_ISCRITICAL (sym->type))
3774     {
3775       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3776         {
3777           emitcode ("rlc", "a");   /* save c in a */
3778           emitcode ("pop", "psw"); /* restore ea via c in psw */
3779           emitcode ("mov", "ea,c");
3780           emitcode ("rrc", "a");   /* restore c from a */
3781         }
3782       else
3783         {
3784           emitcode ("pop", "psw"); /* restore ea via c in psw */
3785           emitcode ("mov", "ea,c");
3786         }
3787     }
3788
3789   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3790     {
3791       if (options.useXstack)
3792         {
3793           if (sym->stack)
3794             {
3795               emitcode ("mov", "sp,_bp");
3796               emitcode ("pop", "_bp");
3797             }
3798           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3799             {
3800               emitcode ("xch", "a,_bpx");
3801               emitcode ("mov", "r0,a");
3802               emitcode ("dec", "r0");
3803               emitcode ("movx", "a,@r0");
3804               emitcode ("xch", "a,_bpx");
3805               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3806             }
3807         }
3808       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3809         {
3810           if (sym->stack)
3811             emitcode ("mov", "sp,_bp");
3812           emitcode ("pop", "_bp");
3813         }
3814     }
3815
3816   /* restore the register bank  */
3817   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3818   {
3819     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3820      || !options.useXstack)
3821     {
3822         /* Special case of ISR using non-zero bank with useXstack
3823          * is handled below.
3824          */
3825         emitcode ("pop", "psw");
3826     }
3827   }
3828
3829   if (IFFUNC_ISISR (sym->type))
3830     {
3831       bitVect *rsavebits;
3832
3833       /* now we need to restore the registers */
3834       /* if this isr has no bank i.e. is going to
3835          run with bank 0 , then we need to save more
3836          registers :-) */
3837       if (!FUNC_REGBANK (sym->type))
3838         {
3839           int i;
3840           /* if this function does not call any other
3841              function then we can be economical and
3842              save only those registers that are used */
3843           if (!IFFUNC_HASFCALL(sym->type))
3844             {
3845               /* if any registers used */
3846               if (sym->regsUsed)
3847                 {
3848                   /* save the registers used */
3849                   for (i = sym->regsUsed->size; i >= 0; i--)
3850                     {
3851                       if (bitVectBitValue (sym->regsUsed, i))
3852                         popReg (i, TRUE);
3853                     }
3854                 }
3855             }
3856           else
3857             {
3858               if (options.parms_in_bank1) {
3859                   for (i = 7 ; i >= 0 ; i-- ) {
3860                       emitcode ("pop","%s",rb1regs[i]);
3861                   }
3862               }
3863               /* this function has a function call. We cannot
3864                  determine register usage so we will have to pop the
3865                  entire bank */
3866               unsaveRBank (0, ic, FALSE);
3867             }
3868         }
3869         else
3870         {
3871             /* This ISR uses a non-zero bank.
3872              *
3873              * Restore any register banks saved by genFunction
3874              * in reverse order.
3875              */
3876             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3877             int ix;
3878
3879             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3880             {
3881                 if (savedBanks & (1 << ix))
3882                 {
3883                     unsaveRBank(ix, NULL, FALSE);
3884                 }
3885             }
3886
3887             if (options.useXstack)
3888             {
3889                 /* Restore bank AFTER calling unsaveRBank,
3890                  * since it can trash r0.
3891                  */
3892                 emitcode ("pop", "psw");
3893             }
3894         }
3895
3896       if (!inExcludeList ("dph"))
3897         emitcode ("pop", "dph");
3898       if (!inExcludeList ("dpl"))
3899         emitcode ("pop", "dpl");
3900       if (!inExcludeList ("b"))
3901         emitcode ("pop", "b");
3902       if (!inExcludeList ("acc"))
3903         emitcode ("pop", "acc");
3904
3905       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3906       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3907         emitcode ("pop", "bits");
3908       freeBitVect (rsavebits);
3909
3910       /* if debug then send end of function */
3911       if (options.debug && currFunc)
3912         {
3913           debugFile->writeEndFunction (currFunc, ic, 1);
3914         }
3915
3916       emitcode ("reti", "");
3917     }
3918   else
3919     {
3920       if (IFFUNC_CALLEESAVES(sym->type))
3921         {
3922           int i;
3923
3924           /* if any registers used */
3925           if (sym->regsUsed)
3926             {
3927               /* save the registers used */
3928               for (i = sym->regsUsed->size; i >= 0; i--)
3929                 {
3930                   if (bitVectBitValue (sym->regsUsed, i) ||
3931                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3932                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3933                 }
3934             }
3935           else if (mcs51_ptrRegReq)
3936             {
3937               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3938               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3939             }
3940
3941         }
3942
3943       /* if debug then send end of function */
3944       if (options.debug && currFunc)
3945         {
3946           debugFile->writeEndFunction (currFunc, ic, 1);
3947         }
3948
3949       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3950         {
3951           emitcode ("ljmp", "__sdcc_banked_ret");
3952         }
3953       else
3954         {
3955           emitcode ("ret", "");
3956         }
3957     }
3958
3959   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3960     return;
3961
3962   /* If this was an interrupt handler using bank 0 that called another */
3963   /* function, then all registers must be saved; nothing to optimized. */
3964   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3965       && !FUNC_REGBANK(sym->type))
3966     return;
3967
3968   /* There are no push/pops to optimize if not callee-saves or ISR */
3969   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3970     return;
3971
3972   /* If there were stack parameters, we cannot optimize without also    */
3973   /* fixing all of the stack offsets; this is too dificult to consider. */
3974   if (FUNC_HASSTACKPARM(sym->type))
3975     return;
3976
3977   /* Compute the registers actually used */
3978   regsUsed = newBitVect (mcs51_nRegs);
3979   regsUsedPrologue = newBitVect (mcs51_nRegs);
3980   while (lnp)
3981     {
3982       if (lnp->ic && lnp->ic->op == FUNCTION)
3983         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3984       else
3985         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3986
3987       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3988           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3989         break;
3990       if (!lnp->prev)
3991         break;
3992       lnp = lnp->prev;
3993     }
3994
3995   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3996       && !bitVectBitValue (regsUsed, CND_IDX))
3997     {
3998       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3999       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
4000           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
4001         bitVectUnSetBit (regsUsed, CND_IDX);
4002     }
4003   else
4004     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4005
4006   /* If this was an interrupt handler that called another function */
4007   /* function, then assume A, B, DPH, & DPL may be modified by it. */
4008   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4009     {
4010       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4011       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4012       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4013       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4014       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4015     }
4016
4017   /* Remove the unneeded push/pops */
4018   regsUnneeded = newBitVect (mcs51_nRegs);
4019   while (lnp)
4020     {
4021       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4022         {
4023           if (!strncmp(lnp->line, "push", 4))
4024             {
4025               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4026               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4027                 {
4028                   connectLine (lnp->prev, lnp->next);
4029                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4030                 }
4031             }
4032           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4033             {
4034               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4035               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4036                 {
4037                   connectLine (lnp->prev, lnp->next);
4038                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4039                 }
4040             }
4041         }
4042       lnp = lnp->next;
4043     }
4044
4045   for (idx = 0; idx < regsUnneeded->size; idx++)
4046     if (bitVectBitValue (regsUnneeded, idx))
4047       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4048
4049   freeBitVect (regsUnneeded);
4050   freeBitVect (regsUsed);
4051   freeBitVect (regsUsedPrologue);
4052 }
4053
4054 /*-----------------------------------------------------------------*/
4055 /* genRet - generate code for return statement                     */
4056 /*-----------------------------------------------------------------*/
4057 static void
4058 genRet (iCode * ic)
4059 {
4060   int size, offset = 0, pushed = 0;
4061
4062   D (emitcode (";", "genRet"));
4063
4064   /* if we have no return value then
4065      just generate the "ret" */
4066   if (!IC_LEFT (ic))
4067     goto jumpret;
4068
4069   /* we have something to return then
4070      move the return value into place */
4071   aopOp (IC_LEFT (ic), ic, FALSE);
4072   size = AOP_SIZE (IC_LEFT (ic));
4073
4074   if (IS_BIT(_G.currentFunc->etype))
4075     {
4076       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4077         toCarry (IC_LEFT (ic));
4078     }
4079   else
4080     {
4081       while (size--)
4082         {
4083           char *l;
4084           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4085             {
4086               /* #NOCHANGE */
4087               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4088               emitcode ("push", "%s", l);
4089               pushed++;
4090             }
4091           else
4092             {
4093               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4094               if (strcmp (fReturn[offset], l))
4095                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4096             }
4097         }
4098
4099       while (pushed)
4100         {
4101           pushed--;
4102           if (strcmp (fReturn[pushed], "a"))
4103             emitcode ("pop", fReturn[pushed]);
4104           else
4105             emitcode ("pop", "acc");
4106         }
4107     }
4108   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4109
4110 jumpret:
4111   /* generate a jump to the return label
4112      if the next is not the return statement */
4113   if (!(ic->next && ic->next->op == LABEL &&
4114         IC_LABEL (ic->next) == returnLabel))
4115
4116     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4117
4118 }
4119
4120 /*-----------------------------------------------------------------*/
4121 /* genLabel - generates a label                                    */
4122 /*-----------------------------------------------------------------*/
4123 static void
4124 genLabel (iCode * ic)
4125 {
4126   /* special case never generate */
4127   if (IC_LABEL (ic) == entryLabel)
4128     return;
4129
4130   emitLabel (IC_LABEL (ic));
4131 }
4132
4133 /*-----------------------------------------------------------------*/
4134 /* genGoto - generates a ljmp                                      */
4135 /*-----------------------------------------------------------------*/
4136 static void
4137 genGoto (iCode * ic)
4138 {
4139   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4140 }
4141
4142 /*-----------------------------------------------------------------*/
4143 /* findLabelBackwards: walks back through the iCode chain looking  */
4144 /* for the given label. Returns number of iCode instructions     */
4145 /* between that label and given ic.          */
4146 /* Returns zero if label not found.          */
4147 /*-----------------------------------------------------------------*/
4148 static int
4149 findLabelBackwards (iCode * ic, int key)
4150 {
4151   int count = 0;
4152
4153   while (ic->prev)
4154     {
4155       ic = ic->prev;
4156       count++;
4157
4158       /* If we have any pushes or pops, we cannot predict the distance.
4159          I don't like this at all, this should be dealt with in the
4160          back-end */
4161       if (ic->op == IPUSH || ic->op == IPOP) {
4162         return 0;
4163       }
4164
4165       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4166         {
4167           return count;
4168         }
4169     }
4170
4171   return 0;
4172 }
4173
4174 /*-----------------------------------------------------------------*/
4175 /* genPlusIncr :- does addition with increment if possible         */
4176 /*-----------------------------------------------------------------*/
4177 static bool
4178 genPlusIncr (iCode * ic)
4179 {
4180   unsigned int icount;
4181   unsigned int size = getDataSize (IC_RESULT (ic));
4182
4183   /* will try to generate an increment */
4184   /* if the right side is not a literal
4185      we cannot */
4186   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4187     return FALSE;
4188
4189   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4190
4191   D(emitcode (";","genPlusIncr"));
4192
4193   /* if increment >=16 bits in register or direct space */
4194   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4195         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4196         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4197       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4198       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4199       (size > 1) &&
4200       (icount == 1))
4201     {
4202       symbol *tlbl;
4203       int emitTlbl;
4204       int labelRange;
4205
4206       /* If the next instruction is a goto and the goto target
4207        * is < 10 instructions previous to this, we can generate
4208        * jumps straight to that target.
4209        */
4210       if (ic->next && ic->next->op == GOTO
4211           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4212           && labelRange <= 10)
4213         {
4214           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4215           tlbl = IC_LABEL (ic->next);
4216           emitTlbl = 0;
4217         }
4218       else
4219         {
4220           tlbl = newiTempLabel (NULL);
4221           emitTlbl = 1;
4222         }
4223       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4224       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4225           IS_AOP_PREG (IC_RESULT (ic)))
4226         emitcode ("cjne", "%s,#0x00,%05d$",
4227                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4228                   tlbl->key + 100);
4229       else
4230         {
4231           emitcode ("clr", "a");
4232           emitcode ("cjne", "a,%s,%05d$",
4233                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4234                     tlbl->key + 100);
4235         }
4236
4237       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4238       if (size > 2)
4239         {
4240           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4241               IS_AOP_PREG (IC_RESULT (ic)))
4242             emitcode ("cjne", "%s,#0x00,%05d$",
4243                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4244                       tlbl->key + 100);
4245           else
4246             emitcode ("cjne", "a,%s,%05d$",
4247                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4248                       tlbl->key + 100);
4249
4250           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4251         }
4252       if (size > 3)
4253         {
4254           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4255               IS_AOP_PREG (IC_RESULT (ic)))
4256             emitcode ("cjne", "%s,#0x00,%05d$",
4257                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4258                       tlbl->key + 100);
4259           else
4260             {
4261               emitcode ("cjne", "a,%s,%05d$",
4262                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4263                         tlbl->key + 100);
4264             }
4265           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4266         }
4267
4268       if (emitTlbl)
4269         {
4270           emitLabel (tlbl);
4271         }
4272       return TRUE;
4273     }
4274
4275   /* if result is dptr */
4276   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4277       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4278       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4279       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4280     {
4281       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4282         return FALSE;
4283
4284       if (icount > 9)
4285         return FALSE;
4286
4287       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4288         return FALSE;
4289
4290       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4291       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4292       while (icount--)
4293         emitcode ("inc", "dptr");
4294
4295       return TRUE;
4296     }
4297
4298   /* if the literal value of the right hand side
4299      is greater than 4 then it is not worth it */
4300   if (icount > 4)
4301     return FALSE;
4302
4303   /* if the sizes are greater than 1 then we cannot */
4304   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4305       AOP_SIZE (IC_LEFT (ic)) > 1)
4306     return FALSE;
4307
4308   /* we can if the aops of the left & result match or
4309      if they are in registers and the registers are the
4310      same */
4311   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4312     {
4313       if (icount > 3)
4314         {
4315           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4316           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4317           aopPut (IC_RESULT (ic), "a", 0);
4318         }
4319       else
4320         {
4321           while (icount--)
4322             {
4323               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4324             }
4325         }
4326
4327       return TRUE;
4328     }
4329
4330   if (icount == 1)
4331     {
4332       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4333       emitcode ("inc", "a");
4334       aopPut (IC_RESULT (ic), "a", 0);
4335       return TRUE;
4336     }
4337
4338   return FALSE;
4339 }
4340
4341 /*-----------------------------------------------------------------*/
4342 /* outBitAcc - output a bit in acc                                 */
4343 /*-----------------------------------------------------------------*/
4344 static void
4345 outBitAcc (operand * result)
4346 {
4347   symbol *tlbl = newiTempLabel (NULL);
4348   /* if the result is a bit */
4349   if (AOP_TYPE (result) == AOP_CRY)
4350     {
4351       aopPut (result, "a", 0);
4352     }
4353   else
4354     {
4355       emitcode ("jz", "%05d$", tlbl->key + 100);
4356       emitcode ("mov", "a,%s", one);
4357       emitLabel (tlbl);
4358       outAcc (result);
4359     }
4360 }
4361
4362 /*-----------------------------------------------------------------*/
4363 /* genPlusBits - generates code for addition of two bits           */
4364 /*-----------------------------------------------------------------*/
4365 static void
4366 genPlusBits (iCode * ic)
4367 {
4368   D (emitcode (";", "genPlusBits"));
4369
4370   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4371   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4372     {
4373       symbol *lbl = newiTempLabel (NULL);
4374       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4375       emitcode ("cpl", "c");
4376       emitLabel (lbl);
4377       outBitC (IC_RESULT (ic));
4378     }
4379   else
4380     {
4381       emitcode ("clr", "a");
4382       emitcode ("rlc", "a");
4383       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4384       emitcode ("addc", "a,%s", zero);
4385       outAcc (IC_RESULT (ic));
4386     }
4387 }
4388
4389 #if 0
4390 /* This is the original version of this code.
4391
4392  * This is being kept around for reference,
4393  * because I am not entirely sure I got it right...
4394  */
4395 static void
4396 adjustArithmeticResult (iCode * ic)
4397 {
4398   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4399       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4400       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4401     aopPut (IC_RESULT (ic),
4402             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4403             2);
4404
4405   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4406       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4407       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4408     aopPut (IC_RESULT (ic),
4409             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4410             2);
4411
4412   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4413       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4414       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4415       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4416       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4417     {
4418       char buffer[5];
4419       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4420       aopPut (IC_RESULT (ic), buffer, 2);
4421     }
4422 }
4423 #else
4424 /* This is the pure and virtuous version of this code.
4425  * I'm pretty certain it's right, but not enough to toss the old
4426  * code just yet...
4427  */
4428 static void
4429 adjustArithmeticResult (iCode * ic)
4430 {
4431   if (opIsGptr (IC_RESULT (ic)) &&
4432       opIsGptr (IC_LEFT (ic)) &&
4433       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4434     {
4435       aopPut (IC_RESULT (ic),
4436               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4437               GPTRSIZE - 1);
4438     }
4439
4440   if (opIsGptr (IC_RESULT (ic)) &&
4441       opIsGptr (IC_RIGHT (ic)) &&
4442       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4443     {
4444       aopPut (IC_RESULT (ic),
4445               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4446               GPTRSIZE - 1);
4447     }
4448
4449   if (opIsGptr (IC_RESULT (ic)) &&
4450       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4451       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4452       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4453       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4454     {
4455       char buffer[5];
4456       SNPRINTF (buffer, sizeof(buffer),
4457                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4458       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4459     }
4460 }
4461 #endif
4462
4463 /*-----------------------------------------------------------------*/
4464 /* genPlus - generates code for addition                           */
4465 /*-----------------------------------------------------------------*/
4466 static void
4467 genPlus (iCode * ic)
4468 {
4469   int size, offset = 0;
4470   int skip_bytes = 0;
4471   char *add = "add";
4472   bool swappedLR = FALSE;
4473   operand *leftOp, *rightOp;
4474   operand * op;
4475
4476   D (emitcode (";", "genPlus"));
4477
4478   /* special cases :- */
4479
4480   aopOp (IC_LEFT (ic), ic, FALSE);
4481   aopOp (IC_RIGHT (ic), ic, FALSE);
4482   aopOp (IC_RESULT (ic), ic, TRUE);
4483
4484   /* if literal, literal on the right or
4485      if left requires ACC or right is already
4486      in ACC */
4487   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4488       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4489       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4490     {
4491       operand *t = IC_RIGHT (ic);
4492       IC_RIGHT (ic) = IC_LEFT (ic);
4493       IC_LEFT (ic) = t;
4494       swappedLR = TRUE;
4495     }
4496
4497   /* if both left & right are in bit
4498      space */
4499   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4500       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4501     {
4502       genPlusBits (ic);
4503       goto release;
4504     }
4505
4506   /* if left in bit space & right literal */
4507   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4508       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4509     {
4510       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4511       /* if result in bit space */
4512       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4513         {
4514           if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4515             emitcode ("cpl", "c");
4516           outBitC (IC_RESULT (ic));
4517         }
4518       else
4519         {
4520           size = getDataSize (IC_RESULT (ic));
4521           while (size--)
4522             {
4523               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4524               emitcode ("addc", "a,%s", zero);
4525               aopPut (IC_RESULT (ic), "a", offset++);
4526             }
4527         }
4528       goto release;
4529     }
4530
4531   /* if I can do an increment instead
4532      of add then GOOD for ME */
4533   if (genPlusIncr (ic) == TRUE)
4534     goto release;
4535
4536   size = getDataSize (IC_RESULT (ic));
4537   leftOp = IC_LEFT(ic);
4538   rightOp = IC_RIGHT(ic);
4539   op = IC_LEFT(ic);
4540
4541   /* if this is an add for an array access
4542      at a 256 byte boundary */
4543   if ( 2 == size
4544        && AOP_TYPE (op) == AOP_IMMD
4545        && IS_SYMOP (op)
4546        && IS_SPEC (OP_SYM_ETYPE (op))
4547        && SPEC_ABSA (OP_SYM_ETYPE (op))
4548        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4549      )
4550     {
4551       D(emitcode (";", "genPlus aligned array"));
4552       aopPut (IC_RESULT (ic),
4553               aopGet (rightOp, 0, FALSE, FALSE),
4554               0);
4555
4556       if( 1 == getDataSize (IC_RIGHT (ic)) )
4557         {
4558           aopPut (IC_RESULT (ic),
4559                   aopGet (leftOp, 1, FALSE, FALSE),
4560                   1);
4561         }
4562       else
4563         {
4564           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4565           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4566           aopPut (IC_RESULT (ic), "a", 1);
4567         }
4568       goto release;
4569     }
4570
4571   /* if the lower bytes of a literal are zero skip the addition */
4572   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4573     {
4574        while ((0 == ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4575               (skip_bytes+1 < size))
4576          {
4577            skip_bytes++;
4578          }
4579        if (skip_bytes)
4580          D(emitcode (";", "genPlus shortcut"));
4581     }
4582
4583   while (size--)
4584     {
4585       if( offset >= skip_bytes )
4586         {
4587           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4588             {
4589               bool pushedB;
4590               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4591               pushedB = pushB ();
4592               emitcode("xch", "a,b");
4593               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4594               emitcode (add, "a,b");
4595               popB (pushedB);
4596             }
4597           else if (aopGetUsesAcc (leftOp, offset))
4598             {
4599               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4600               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4601             }
4602           else
4603             {
4604               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4605               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4606             }
4607           aopPut (IC_RESULT (ic), "a", offset);
4608           add = "addc";  /* further adds must propagate carry */
4609         }
4610       else
4611         {
4612           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4613               isOperandVolatile (IC_RESULT (ic), FALSE))
4614             {
4615               /* just move */
4616               aopPut (IC_RESULT (ic),
4617                       aopGet (leftOp, offset, FALSE, FALSE),
4618                       offset);
4619             }
4620         }
4621       offset++;
4622     }
4623
4624   adjustArithmeticResult (ic);
4625
4626 release:
4627   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4628   if (!swappedLR)
4629     {
4630       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4631       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4632     }
4633   else
4634     {
4635       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4636       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4637     }
4638 }
4639
4640 /*-----------------------------------------------------------------*/
4641 /* genMinusDec :- does subtraction with decrement if possible      */
4642 /*-----------------------------------------------------------------*/
4643 static bool
4644 genMinusDec (iCode * ic)
4645 {
4646   unsigned int icount;
4647   unsigned int size = getDataSize (IC_RESULT (ic));
4648
4649   /* will try to generate an increment */
4650   /* if the right side is not a literal
4651      we cannot */
4652   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4653     return FALSE;
4654
4655   /* if the literal value of the right hand side
4656      is greater than 4 then it is not worth it */
4657   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4658     return FALSE;
4659
4660   D (emitcode (";", "genMinusDec"));
4661
4662   /* if decrement >=16 bits in register or direct space */
4663   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4664         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4665         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4666       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4667       (size > 1) &&
4668       (icount == 1))
4669     {
4670       symbol *tlbl;
4671       int emitTlbl;
4672       int labelRange;
4673
4674       /* If the next instruction is a goto and the goto target
4675        * is <= 10 instructions previous to this, we can generate
4676        * jumps straight to that target.
4677        */
4678       if (ic->next && ic->next->op == GOTO
4679           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4680           && labelRange <= 10)
4681         {
4682           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4683           tlbl = IC_LABEL (ic->next);
4684           emitTlbl = 0;
4685         }
4686       else
4687         {
4688           tlbl = newiTempLabel (NULL);
4689           emitTlbl = 1;
4690         }
4691
4692       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4693       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4694           IS_AOP_PREG (IC_RESULT (ic)))
4695         emitcode ("cjne", "%s,#0xff,%05d$"
4696                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4697                   ,tlbl->key + 100);
4698       else
4699         {
4700           emitcode ("mov", "a,#0xff");
4701           emitcode ("cjne", "a,%s,%05d$"
4702                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4703                     ,tlbl->key + 100);
4704         }
4705       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4706       if (size > 2)
4707         {
4708           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4709               IS_AOP_PREG (IC_RESULT (ic)))
4710             emitcode ("cjne", "%s,#0xff,%05d$"
4711                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4712                       ,tlbl->key + 100);
4713           else
4714             {
4715               emitcode ("cjne", "a,%s,%05d$"
4716                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4717                         ,tlbl->key + 100);
4718             }
4719           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4720         }
4721       if (size > 3)
4722         {
4723           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4724               IS_AOP_PREG (IC_RESULT (ic)))
4725             emitcode ("cjne", "%s,#0xff,%05d$"
4726                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4727                       ,tlbl->key + 100);
4728           else
4729             {
4730               emitcode ("cjne", "a,%s,%05d$"
4731                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4732                         ,tlbl->key + 100);
4733             }
4734           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4735         }
4736       if (emitTlbl)
4737         {
4738           emitLabel (tlbl);
4739         }
4740       return TRUE;
4741     }
4742
4743   /* if the sizes are greater than 1 then we cannot */
4744   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4745       AOP_SIZE (IC_LEFT (ic)) > 1)
4746     return FALSE;
4747
4748   /* we can if the aops of the left & result match or
4749      if they are in registers and the registers are the
4750      same */
4751   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4752     {
4753       char *l;
4754
4755       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4756         {
4757           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4758           l = "a";
4759         }
4760       else
4761         {
4762           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4763         }
4764
4765       while (icount--)
4766         {
4767           emitcode ("dec", "%s", l);
4768         }
4769
4770       if (AOP_NEEDSACC (IC_RESULT (ic)))
4771         aopPut (IC_RESULT (ic), "a", 0);
4772
4773       return TRUE;
4774     }
4775
4776   if (icount == 1)
4777     {
4778       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4779       emitcode ("dec", "a");
4780       aopPut (IC_RESULT (ic), "a", 0);
4781       return TRUE;
4782     }
4783
4784   return FALSE;
4785 }
4786
4787 /*-----------------------------------------------------------------*/
4788 /* addSign - complete with sign                                    */
4789 /*-----------------------------------------------------------------*/
4790 static void
4791 addSign (operand * result, int offset, int sign)
4792 {
4793   int size = (getDataSize (result) - offset);
4794   if (size > 0)
4795     {
4796       if (sign)
4797         {
4798           emitcode ("rlc", "a");
4799           emitcode ("subb", "a,acc");
4800           while (size--)
4801             {
4802               aopPut (result, "a", offset++);
4803             }
4804         }
4805       else
4806         {
4807           while (size--)
4808             {
4809               aopPut (result, zero, offset++);
4810             }
4811         }
4812     }
4813 }
4814
4815 /*-----------------------------------------------------------------*/
4816 /* genMinusBits - generates code for subtraction  of two bits      */
4817 /*-----------------------------------------------------------------*/
4818 static void
4819 genMinusBits (iCode * ic)
4820 {
4821   symbol *lbl = newiTempLabel (NULL);
4822
4823   D (emitcode (";", "genMinusBits"));
4824
4825   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4826     {
4827       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4828       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4829       emitcode ("cpl", "c");
4830       emitLabel (lbl);
4831       outBitC (IC_RESULT (ic));
4832     }
4833   else
4834     {
4835       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4836       emitcode ("subb", "a,acc");
4837       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4838       emitcode ("inc", "a");
4839       emitLabel (lbl);
4840       aopPut (IC_RESULT (ic), "a", 0);
4841       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4842     }
4843 }
4844
4845 /*-----------------------------------------------------------------*/
4846 /* genMinus - generates code for subtraction                       */
4847 /*-----------------------------------------------------------------*/
4848 static void
4849 genMinus (iCode * ic)
4850 {
4851   int size, offset = 0;
4852
4853   D (emitcode (";", "genMinus"));
4854
4855   aopOp (IC_LEFT (ic), ic, FALSE);
4856   aopOp (IC_RIGHT (ic), ic, FALSE);
4857   aopOp (IC_RESULT (ic), ic, TRUE);
4858
4859   /* special cases :- */
4860   /* if both left & right are in bit space */
4861   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4862       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4863     {
4864       genMinusBits (ic);
4865       goto release;
4866     }
4867
4868   /* if I can do an decrement instead
4869      of subtract then GOOD for ME */
4870   if (genMinusDec (ic) == TRUE)
4871     goto release;
4872
4873   size = getDataSize (IC_RESULT (ic));
4874
4875   /* if literal, add a,#-lit, else normal subb */
4876   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4877     {
4878       unsigned long lit = 0L;
4879       bool useCarry = FALSE;
4880
4881       lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4882       lit = -(long) lit;
4883
4884       while (size--)
4885         {
4886           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4887             {
4888               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4889               if (!offset && !size && lit== (unsigned long) -1)
4890                 {
4891                   emitcode ("dec", "a");
4892                 }
4893               else if (!useCarry)
4894                 {
4895                   /* first add without previous c */
4896                   emitcode ("add", "a,#0x%02x",
4897                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4898                   useCarry = TRUE;
4899                 }
4900               else
4901                 {
4902                   emitcode ("addc", "a,#0x%02x",
4903                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4904                 }
4905               aopPut (IC_RESULT (ic), "a", offset++);
4906             }
4907           else
4908             {
4909               /* no need to add zeroes */
4910               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4911                 {
4912                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4913                           offset);
4914                 }
4915               offset++;
4916             }
4917         }
4918     }
4919   else
4920     {
4921       operand *leftOp, *rightOp;
4922
4923       leftOp = IC_LEFT(ic);
4924       rightOp = IC_RIGHT(ic);
4925
4926       while (size--)
4927         {
4928           if (aopGetUsesAcc(rightOp, offset)) {
4929             if (aopGetUsesAcc(leftOp, offset)) {
4930               bool pushedB;
4931
4932               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4933               pushedB = pushB ();
4934               emitcode ("mov", "b,a");
4935               if (offset == 0)
4936                 CLRC;
4937               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4938               emitcode ("subb", "a,b");
4939               popB (pushedB);
4940             } else {
4941               /* reverse subtraction with 2's complement */
4942               if (offset == 0)
4943                 emitcode( "setb", "c");
4944               else
4945                 emitcode( "cpl", "c");
4946               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4947               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4948               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4949               emitcode("cpl", "a");
4950               if (size) /* skip if last byte */
4951                 emitcode( "cpl", "c");
4952             }
4953           } else {
4954             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4955             if (offset == 0)
4956               CLRC;
4957             emitcode ("subb", "a,%s",
4958                       aopGet(rightOp, offset, FALSE, TRUE));
4959           }
4960
4961           aopPut (IC_RESULT (ic), "a", offset++);
4962         }
4963     }
4964
4965   adjustArithmeticResult (ic);
4966
4967 release:
4968   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4969   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4970   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4971 }
4972
4973
4974 /*-----------------------------------------------------------------*/
4975 /* genMultbits :- multiplication of bits                           */
4976 /*-----------------------------------------------------------------*/
4977 static void
4978 genMultbits (operand * left,
4979              operand * right,
4980              operand * result)
4981 {
4982   D (emitcode (";", "genMultbits"));
4983
4984   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4985   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4986   outBitC (result);
4987 }
4988
4989 /*-----------------------------------------------------------------*/
4990 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4991 /*-----------------------------------------------------------------*/
4992 static void
4993 genMultOneByte (operand * left,
4994                 operand * right,
4995                 operand * result)
4996 {
4997   symbol *lbl;
4998   int size = AOP_SIZE (result);
4999   bool runtimeSign, compiletimeSign;
5000   bool lUnsigned, rUnsigned, pushedB;
5001
5002   D (emitcode (";", "genMultOneByte"));
5003
5004   if (size < 1 || size > 2)
5005     {
5006       /* this should never happen */
5007       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5008                AOP_SIZE(result), __FILE__, lineno);
5009       exit (1);
5010     }
5011
5012   /* (if two literals: the value is computed before) */
5013   /* if one literal, literal on the right */
5014   if (AOP_TYPE (left) == AOP_LIT)
5015     {
5016       operand *t = right;
5017       right = left;
5018       left = t;
5019       /* emitcode (";", "swapped left and right"); */
5020     }
5021   /* if no literal, unsigned on the right: shorter code */
5022   if (   AOP_TYPE (right) != AOP_LIT
5023       && SPEC_USIGN (getSpec (operandType (left))))
5024     {
5025       operand *t = right;
5026       right = left;
5027       left = t;
5028     }
5029
5030   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5031   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5032
5033   pushedB = pushB ();
5034
5035   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5036                    no need to take care about the signedness! */
5037       || (lUnsigned && rUnsigned))
5038     {
5039       /* just an unsigned 8 * 8 = 8 multiply
5040          or 8u * 8u = 16u */
5041       /* emitcode (";","unsigned"); */
5042       /* TODO: check for accumulator clash between left & right aops? */
5043
5044       if (AOP_TYPE (right) == AOP_LIT)
5045         {
5046           /* moving to accumulator first helps peepholes */
5047           MOVA (aopGet (left, 0, FALSE, FALSE));
5048           MOVB (aopGet (right, 0, FALSE, FALSE));
5049         }
5050       else
5051         {
5052           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5053           MOVA (aopGet (left, 0, FALSE, FALSE));
5054         }
5055
5056       emitcode ("mul", "ab");
5057       aopPut (result, "a", 0);
5058       if (size == 2)
5059         aopPut (result, "b", 1);
5060
5061       popB (pushedB);
5062       return;
5063     }
5064
5065   /* we have to do a signed multiply */
5066   /* emitcode (";", "signed"); */
5067
5068   /* now sign adjust for both left & right */
5069
5070   /* let's see what's needed: */
5071   /* apply negative sign during runtime */
5072   runtimeSign = FALSE;
5073   /* negative sign from literals */
5074   compiletimeSign = FALSE;
5075
5076   if (!lUnsigned)
5077     {
5078       if (AOP_TYPE(left) == AOP_LIT)
5079         {
5080           /* signed literal */
5081           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5082           if (val < 0)
5083             compiletimeSign = TRUE;
5084         }
5085       else
5086         /* signed but not literal */
5087         runtimeSign = TRUE;
5088     }
5089
5090   if (!rUnsigned)
5091     {
5092       if (AOP_TYPE(right) == AOP_LIT)
5093         {
5094           /* signed literal */
5095           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5096           if (val < 0)
5097             compiletimeSign ^= TRUE;
5098         }
5099       else
5100         /* signed but not literal */
5101         runtimeSign = TRUE;
5102     }
5103
5104   /* initialize F0, which stores the runtime sign */
5105   if (runtimeSign)
5106     {
5107       if (compiletimeSign)
5108         emitcode ("setb", "F0"); /* set sign flag */
5109       else
5110         emitcode ("clr", "F0"); /* reset sign flag */
5111     }
5112
5113   /* save the signs of the operands */
5114   if (AOP_TYPE(right) == AOP_LIT)
5115     {
5116       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5117
5118       if (!rUnsigned && val < 0)
5119         emitcode ("mov", "b,#0x%02x", -val);
5120       else
5121         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5122     }
5123   else /* ! literal */
5124     {
5125       if (rUnsigned)  /* emitcode (";", "signed"); */
5126         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5127       else
5128         {
5129           MOVA (aopGet (right, 0, FALSE, FALSE));
5130           lbl = newiTempLabel (NULL);
5131           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5132           emitcode ("cpl", "F0"); /* complement sign flag */
5133           emitcode ("cpl", "a");  /* 2's complement */
5134           emitcode ("inc", "a");
5135           emitLabel (lbl);
5136           emitcode ("mov", "b,a");
5137         }
5138     }
5139
5140   if (AOP_TYPE(left) == AOP_LIT)
5141     {
5142       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5143
5144       if (!lUnsigned && val < 0)
5145         emitcode ("mov", "a,#0x%02x", -val);
5146       else
5147         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5148     }
5149   else /* ! literal */
5150     {
5151       MOVA (aopGet (left, 0, FALSE, FALSE));
5152
5153       if (!lUnsigned)
5154         {
5155           lbl = newiTempLabel (NULL);
5156           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5157           emitcode ("cpl", "F0"); /* complement sign flag */
5158           emitcode ("cpl", "a"); /* 2's complement */
5159           emitcode ("inc", "a");
5160           emitLabel (lbl);
5161         }
5162     }
5163
5164   /* now the multiplication */
5165   emitcode ("mul", "ab");
5166   if (runtimeSign || compiletimeSign)
5167     {
5168       lbl = newiTempLabel (NULL);
5169       if (runtimeSign)
5170         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5171       emitcode ("cpl", "a"); /* lsb 2's complement */
5172       if (size != 2)
5173         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5174       else
5175         {
5176           emitcode ("add", "a,#1"); /* this sets carry flag */
5177           emitcode ("xch", "a,b");
5178           emitcode ("cpl", "a"); /* msb 2's complement */
5179           emitcode ("addc", "a,#0");
5180           emitcode ("xch", "a,b");
5181         }
5182       emitLabel (lbl);
5183     }
5184   aopPut (result, "a", 0);
5185   if (size == 2)
5186     aopPut (result, "b", 1);
5187
5188   popB (pushedB);
5189 }
5190
5191 /*-----------------------------------------------------------------*/
5192 /* genMult - generates code for multiplication                     */
5193 /*-----------------------------------------------------------------*/
5194 static void
5195 genMult (iCode * ic)
5196 {
5197   operand *left = IC_LEFT (ic);
5198   operand *right = IC_RIGHT (ic);
5199   operand *result = IC_RESULT (ic);
5200
5201   D (emitcode (";", "genMult"));
5202
5203   /* assign the asmops */
5204   aopOp (left, ic, FALSE);
5205   aopOp (right, ic, FALSE);
5206   aopOp (result, ic, TRUE);
5207
5208   /* special cases first */
5209   /* both are bits */
5210   if (AOP_TYPE (left) == AOP_CRY &&
5211       AOP_TYPE (right) == AOP_CRY)
5212     {
5213       genMultbits (left, right, result);
5214       goto release;
5215     }
5216
5217   /* if both are of size == 1 */
5218 #if 0 // one of them can be a sloc shared with the result
5219     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5220 #else
5221   if (getSize(operandType(left)) == 1 &&
5222       getSize(operandType(right)) == 1)
5223 #endif
5224     {
5225       genMultOneByte (left, right, result);
5226       goto release;
5227     }
5228
5229   /* should have been converted to function call */
5230     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5231              getSize(OP_SYMBOL(right)->type));
5232   assert (0);
5233
5234 release:
5235   freeAsmop (result, NULL, ic, TRUE);
5236   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5237   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5238 }
5239
5240 /*-----------------------------------------------------------------*/
5241 /* genDivbits :- division of bits                                  */
5242 /*-----------------------------------------------------------------*/
5243 static void
5244 genDivbits (operand * left,
5245             operand * right,
5246             operand * result)
5247 {
5248   char *l;
5249   bool pushedB;
5250
5251   D(emitcode (";", "genDivbits"));
5252
5253   pushedB = pushB ();
5254
5255   /* the result must be bit */
5256   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5257   l = aopGet (left, 0, FALSE, FALSE);
5258
5259   MOVA (l);
5260
5261   emitcode ("div", "ab");
5262   emitcode ("rrc", "a");
5263
5264   popB (pushedB);
5265
5266   aopPut (result, "c", 0);
5267 }
5268
5269 /*-----------------------------------------------------------------*/
5270 /* genDivOneByte : 8 bit division                                  */
5271 /*-----------------------------------------------------------------*/
5272 static void
5273 genDivOneByte (operand * left,
5274                operand * right,
5275                operand * result)
5276 {
5277   bool lUnsigned, rUnsigned, pushedB;
5278   bool runtimeSign, compiletimeSign;
5279   bool accuse = FALSE;
5280   bool pushedA = FALSE;
5281   symbol *lbl;
5282   int size, offset;
5283
5284   D(emitcode (";", "genDivOneByte"));
5285
5286   /* Why is it necessary that genDivOneByte() can return an int result?
5287      Have a look at:
5288
5289         volatile unsigned char uc;
5290         volatile signed char sc1, sc2;
5291         volatile int i;
5292
5293         uc  = 255;
5294         sc1 = -1;
5295         i = uc / sc1;
5296
5297      Or:
5298
5299         sc1 = -128;
5300         sc2 = -1;
5301         i = sc1 / sc2;
5302
5303      In all cases a one byte result would overflow, the following cast to int
5304      would return the wrong result.
5305
5306      Two possible solution:
5307         a) cast operands to int, if ((unsigned) / (signed)) or
5308            ((signed) / (signed))
5309         b) return an 16 bit signed int; this is what we're doing here!
5310   */
5311
5312   size = AOP_SIZE (result) - 1;
5313   offset = 1;
5314   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5315   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5316
5317   pushedB = pushB ();
5318
5319   /* signed or unsigned */
5320   if (lUnsigned && rUnsigned)
5321     {
5322       /* unsigned is easy */
5323       MOVB (aopGet (right, 0, FALSE, FALSE));
5324       MOVA (aopGet (left, 0, FALSE, FALSE));
5325       emitcode ("div", "ab");
5326       aopPut (result, "a", 0);
5327       while (size--)
5328         aopPut (result, zero, offset++);
5329
5330       popB (pushedB);
5331       return;
5332     }
5333
5334   /* signed is a little bit more difficult */
5335
5336   /* now sign adjust for both left & right */
5337
5338   /* let's see what's needed: */
5339   /* apply negative sign during runtime */
5340   runtimeSign = FALSE;
5341   /* negative sign from literals */
5342   compiletimeSign = FALSE;
5343
5344   if (!lUnsigned)
5345     {
5346       if (AOP_TYPE(left) == AOP_LIT)
5347         {
5348           /* signed literal */
5349           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5350           if (val < 0)
5351             compiletimeSign = TRUE;
5352         }
5353       else
5354         /* signed but not literal */
5355         runtimeSign = TRUE;
5356     }
5357
5358   if (!rUnsigned)
5359     {
5360       if (AOP_TYPE(right) == AOP_LIT)
5361         {
5362           /* signed literal */
5363           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5364           if (val < 0)
5365             compiletimeSign ^= TRUE;
5366         }
5367       else
5368         /* signed but not literal */
5369         runtimeSign = TRUE;
5370     }
5371
5372   /* initialize F0, which stores the runtime sign */
5373   if (runtimeSign)
5374     {
5375       if (compiletimeSign)
5376         emitcode ("setb", "F0"); /* set sign flag */
5377       else
5378         emitcode ("clr", "F0"); /* reset sign flag */
5379     }
5380
5381   /* save the signs of the operands */
5382   if (AOP_TYPE(right) == AOP_LIT)
5383     {
5384       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5385
5386       if (!rUnsigned && val < 0)
5387         emitcode ("mov", "b,#0x%02x", -val);
5388       else
5389         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5390     }
5391   else /* ! literal */
5392     {
5393       if (rUnsigned)
5394         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5395       else
5396         {
5397           MOVA (aopGet (right, 0, FALSE, FALSE));
5398           lbl = newiTempLabel (NULL);
5399           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5400           emitcode ("cpl", "F0"); /* complement sign flag */
5401           emitcode ("cpl", "a");  /* 2's complement */
5402           emitcode ("inc", "a");
5403           emitLabel (lbl);
5404           emitcode ("mov", "b,a");
5405         }
5406     }
5407
5408   if (AOP_TYPE(left) == AOP_LIT)
5409     {
5410       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5411
5412       if (!lUnsigned && val < 0)
5413         emitcode ("mov", "a,#0x%02x", -val);
5414       else
5415         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5416     }
5417   else /* ! literal */
5418     {
5419       MOVA (aopGet (left, 0, FALSE, FALSE));
5420
5421       if (!lUnsigned)
5422         {
5423           lbl = newiTempLabel (NULL);
5424           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5425           emitcode ("cpl", "F0"); /* complement sign flag */
5426           emitcode ("cpl", "a");  /* 2's complement */
5427           emitcode ("inc", "a");
5428           emitLabel (lbl);
5429         }
5430     }
5431
5432   /* now the division */
5433   emitcode ("div", "ab");
5434
5435   if (runtimeSign || compiletimeSign)
5436     {
5437       lbl = newiTempLabel (NULL);
5438       if (runtimeSign)
5439         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5440       emitcode ("cpl", "a"); /* lsb 2's complement */
5441       emitcode ("inc", "a");
5442       emitLabel (lbl);
5443
5444       accuse = aopPut (result, "a", 0);
5445       if (size > 0)
5446         {
5447           /* msb is 0x00 or 0xff depending on the sign */
5448           if (runtimeSign)
5449             {
5450               if (accuse)
5451                 {
5452                   emitcode ("push", "acc");
5453                   pushedA = TRUE;
5454                 }
5455               emitcode ("mov", "c,F0");
5456               emitcode ("subb", "a,acc");
5457               while (size--)
5458                 aopPut (result, "a", offset++);
5459             }
5460           else /* compiletimeSign */
5461             {
5462               if (aopPutUsesAcc (result, "#0xFF", offset))
5463                 {
5464                   emitcode ("push", "acc");
5465                   pushedA = TRUE;
5466                 }
5467               while (size--)
5468                 aopPut (result, "#0xff", offset++);
5469             }
5470         }
5471     }
5472   else
5473     {
5474       aopPut (result, "a", 0);
5475       while (size--)
5476         aopPut (result, zero, offset++);
5477     }
5478
5479   if (pushedA)
5480     emitcode ("pop", "acc");
5481   popB (pushedB);
5482 }
5483
5484 /*-----------------------------------------------------------------*/
5485 /* genDiv - generates code for division                            */
5486 /*-----------------------------------------------------------------*/
5487 static void
5488 genDiv (iCode * ic)
5489 {
5490   operand *left = IC_LEFT (ic);
5491   operand *right = IC_RIGHT (ic);
5492   operand *result = IC_RESULT (ic);
5493
5494   D (emitcode (";", "genDiv"));
5495
5496   /* assign the asmops */
5497   aopOp (left, ic, FALSE);
5498   aopOp (right, ic, FALSE);
5499   aopOp (result, ic, TRUE);
5500
5501   /* special cases first */
5502   /* both are bits */
5503   if (AOP_TYPE (left) == AOP_CRY &&
5504       AOP_TYPE (right) == AOP_CRY)
5505     {
5506       genDivbits (left, right, result);
5507       goto release;
5508     }
5509
5510   /* if both are of size == 1 */
5511   if (AOP_SIZE (left) == 1 &&
5512       AOP_SIZE (right) == 1)
5513     {
5514       genDivOneByte (left, right, result);
5515       goto release;
5516     }
5517
5518   /* should have been converted to function call */
5519   assert (0);
5520 release:
5521   freeAsmop (result, NULL, ic, TRUE);
5522   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5523   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5524 }
5525
5526 /*-----------------------------------------------------------------*/
5527 /* genModbits :- modulus of bits                                   */
5528 /*-----------------------------------------------------------------*/
5529 static void
5530 genModbits (operand * left,
5531             operand * right,
5532             operand * result)
5533 {
5534   char *l;
5535   bool pushedB;
5536
5537   D (emitcode (";", "genModbits"));
5538
5539   pushedB = pushB ();
5540
5541   /* the result must be bit */
5542   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5543   l = aopGet (left, 0, FALSE, FALSE);
5544
5545   MOVA (l);
5546
5547   emitcode ("div", "ab");
5548   emitcode ("mov", "a,b");
5549   emitcode ("rrc", "a");
5550
5551   popB (pushedB);
5552
5553   aopPut (result, "c", 0);
5554 }
5555
5556 /*-----------------------------------------------------------------*/
5557 /* genModOneByte : 8 bit modulus                                   */
5558 /*-----------------------------------------------------------------*/
5559 static void
5560 genModOneByte (operand * left,
5561                operand * right,
5562                operand * result)
5563 {
5564   bool lUnsigned, rUnsigned, pushedB;
5565   bool runtimeSign, compiletimeSign;
5566   symbol *lbl;
5567   int size, offset;
5568
5569   D (emitcode (";", "genModOneByte"));
5570
5571   size = AOP_SIZE (result) - 1;
5572   offset = 1;
5573   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5574   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5575
5576   /* if right is a literal, check it for 2^n */
5577   if (AOP_TYPE(right) == AOP_LIT)
5578     {
5579       unsigned char val = abs((int) operandLitValue(right));
5580       symbol *lbl2 = NULL;
5581
5582       switch (val)
5583         {
5584           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5585           case 2:
5586           case 4:
5587           case 8:
5588           case 16:
5589           case 32:
5590           case 64:
5591           case 128:
5592             if (lUnsigned)
5593               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5594                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5595               /* because iCode should have been changed to genAnd  */
5596               /* see file "SDCCopt.c", function "convertToFcall()" */
5597
5598             MOVA (aopGet (left, 0, FALSE, FALSE));
5599             emitcode ("mov", "c,acc.7");
5600             emitcode ("anl", "a,#0x%02x", val - 1);
5601             lbl = newiTempLabel (NULL);
5602             emitcode ("jz", "%05d$", (lbl->key + 100));
5603             emitcode ("jnc", "%05d$", (lbl->key + 100));
5604             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5605             if (size)
5606               {
5607                 int size2 = size;
5608                 int offs2 = offset;
5609
5610                 aopPut (result, "a", 0);
5611                 while (size2--)
5612                   aopPut (result, "#0xff", offs2++);
5613                 lbl2 = newiTempLabel (NULL);
5614                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5615               }
5616             emitLabel (lbl);
5617             aopPut (result, "a", 0);
5618             while (size--)
5619               aopPut (result, zero, offset++);
5620             if (lbl2)
5621               {
5622                 emitLabel (lbl2);
5623               }
5624             return;
5625
5626           default:
5627             break;
5628         }
5629     }
5630
5631   pushedB = pushB ();
5632
5633   /* signed or unsigned */
5634   if (lUnsigned && rUnsigned)
5635     {
5636       /* unsigned is easy */
5637       MOVB (aopGet (right, 0, FALSE, FALSE));
5638       MOVA (aopGet (left, 0, FALSE, FALSE));
5639       emitcode ("div", "ab");
5640       aopPut (result, "b", 0);
5641       while (size--)
5642         aopPut (result, zero, offset++);
5643
5644       popB (pushedB);
5645       return;
5646     }
5647
5648   /* signed is a little bit more difficult */
5649
5650   /* now sign adjust for both left & right */
5651
5652   /* modulus: sign of the right operand has no influence on the result! */
5653   if (AOP_TYPE(right) == AOP_LIT)
5654     {
5655       signed char val = (char) operandLitValue(right);
5656
5657       if (!rUnsigned && val < 0)
5658         emitcode ("mov", "b,#0x%02x", -val);
5659       else
5660         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5661     }
5662   else /* not literal */
5663     {
5664       if (rUnsigned)
5665         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5666       else
5667         {
5668           MOVA (aopGet (right, 0, FALSE, FALSE));
5669           lbl = newiTempLabel (NULL);
5670           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5671           emitcode ("cpl", "a"); /* 2's complement */
5672           emitcode ("inc", "a");
5673           emitLabel (lbl);
5674           emitcode ("mov", "b,a");
5675         }
5676     }
5677
5678   /* let's see what's needed: */
5679   /* apply negative sign during runtime */
5680   runtimeSign = FALSE;
5681   /* negative sign from literals */
5682   compiletimeSign = FALSE;
5683
5684   /* sign adjust left side */
5685   if (AOP_TYPE(left) == AOP_LIT)
5686     {
5687       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5688
5689       if (!lUnsigned && val < 0)
5690         {
5691           compiletimeSign = TRUE; /* set sign flag */
5692           emitcode ("mov", "a,#0x%02x", -val);
5693         }
5694       else
5695         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5696     }
5697   else /* ! literal */
5698     {
5699       MOVA (aopGet (left, 0, FALSE, FALSE));
5700
5701       if (!lUnsigned)
5702         {
5703           runtimeSign = TRUE;
5704           emitcode ("clr", "F0"); /* clear sign flag */
5705
5706           lbl = newiTempLabel (NULL);
5707           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5708           emitcode ("setb", "F0"); /* set sign flag */
5709           emitcode ("cpl", "a");   /* 2's complement */
5710           emitcode ("inc", "a");
5711           emitLabel (lbl);
5712         }
5713     }
5714
5715   /* now the modulus */
5716   emitcode ("div", "ab");
5717
5718   if (runtimeSign || compiletimeSign)
5719     {
5720       emitcode ("mov", "a,b");
5721       lbl = newiTempLabel (NULL);
5722       if (runtimeSign)
5723         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5724       emitcode ("cpl", "a"); /* 2's complement */
5725       emitcode ("inc", "a");
5726       emitLabel (lbl);
5727
5728       aopPut (result, "a", 0);
5729       if (size > 0)
5730         {
5731           /* msb is 0x00 or 0xff depending on the sign */
5732           if (runtimeSign)
5733             {
5734               emitcode ("mov", "c,F0");
5735               emitcode ("subb", "a,acc");
5736               while (size--)
5737                 aopPut (result, "a", offset++);
5738             }
5739           else /* compiletimeSign */
5740             while (size--)
5741               aopPut (result, "#0xff", offset++);
5742         }
5743     }
5744   else
5745     {
5746       aopPut (result, "b", 0);
5747       while (size--)
5748         aopPut (result, zero, offset++);
5749     }
5750
5751   popB (pushedB);
5752 }
5753
5754 /*-----------------------------------------------------------------*/
5755 /* genMod - generates code for division                            */
5756 /*-----------------------------------------------------------------*/
5757 static void
5758 genMod (iCode * ic)
5759 {
5760   operand *left = IC_LEFT (ic);
5761   operand *right = IC_RIGHT (ic);
5762   operand *result = IC_RESULT (ic);
5763
5764   D (emitcode (";", "genMod"));
5765
5766   /* assign the asmops */
5767   aopOp (left, ic, FALSE);
5768   aopOp (right, ic, FALSE);
5769   aopOp (result, ic, TRUE);
5770
5771   /* special cases first */
5772   /* both are bits */
5773   if (AOP_TYPE (left) == AOP_CRY &&
5774       AOP_TYPE (right) == AOP_CRY)
5775     {
5776       genModbits (left, right, result);
5777       goto release;
5778     }
5779
5780   /* if both are of size == 1 */
5781   if (AOP_SIZE (left) == 1 &&
5782       AOP_SIZE (right) == 1)
5783     {
5784       genModOneByte (left, right, result);
5785       goto release;
5786     }
5787
5788   /* should have been converted to function call */
5789   assert (0);
5790
5791 release:
5792   freeAsmop (result, NULL, ic, TRUE);
5793   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5794   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5795 }
5796
5797 /*-----------------------------------------------------------------*/
5798 /* genIfxJump :- will create a jump depending on the ifx           */
5799 /*-----------------------------------------------------------------*/
5800 static void
5801 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5802 {
5803   symbol *jlbl;
5804   symbol *tlbl = newiTempLabel (NULL);
5805   char *inst;
5806
5807   D (emitcode (";", "genIfxJump"));
5808
5809   /* if true label then we jump if condition
5810      supplied is true */
5811   if (IC_TRUE (ic))
5812     {
5813       jlbl = IC_TRUE (ic);
5814       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5815                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5816     }
5817   else
5818     {
5819       /* false label is present */
5820       jlbl = IC_FALSE (ic);
5821       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5822                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5823     }
5824   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5825     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5826   else
5827     emitcode (inst, "%05d$", tlbl->key + 100);
5828   freeForBranchAsmop (result);
5829   freeForBranchAsmop (right);
5830   freeForBranchAsmop (left);
5831   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5832   emitLabel (tlbl);
5833
5834   /* mark the icode as generated */
5835   ic->generated = 1;
5836 }
5837
5838 /*-----------------------------------------------------------------*/
5839 /* genCmp :- greater or less than comparison                       */
5840 /*-----------------------------------------------------------------*/
5841 static void
5842 genCmp (operand * left, operand * right,
5843         operand * result, iCode * ifx, int sign, iCode *ic)
5844 {
5845   int size, offset = 0;
5846   unsigned long lit = 0L;
5847   bool rightInB;
5848
5849   D (emitcode (";", "genCmp"));
5850
5851   /* if left & right are bit variables */
5852   if (AOP_TYPE (left) == AOP_CRY &&
5853       AOP_TYPE (right) == AOP_CRY)
5854     {
5855       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5856       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5857     }
5858   else
5859     {
5860       /* subtract right from left if at the
5861          end the carry flag is set then we know that
5862          left is greater than right */
5863       size = max (AOP_SIZE (left), AOP_SIZE (right));
5864
5865       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5866       if ((size == 1) && !sign &&
5867           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5868         {
5869           symbol *lbl = newiTempLabel (NULL);
5870           emitcode ("cjne", "%s,%s,%05d$",
5871                     aopGet (left, offset, FALSE, FALSE),
5872                     aopGet (right, offset, FALSE, FALSE),
5873                     lbl->key + 100);
5874           emitLabel (lbl);
5875         }
5876       else
5877         {
5878           if (AOP_TYPE (right) == AOP_LIT)
5879             {
5880               lit = ulFromVal (AOP (right)->aopu.aop_lit);
5881               /* optimize if(x < 0) or if(x >= 0) */
5882               if (lit == 0L)
5883                 {
5884                   if (!sign)
5885                     {
5886                       CLRC;
5887                     }
5888                   else
5889                     {
5890                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5891                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5892                         {
5893                           genIfxJump (ifx, "acc.7", left, right, result);
5894                           freeAsmop (right, NULL, ic, TRUE);
5895                           freeAsmop (left, NULL, ic, TRUE);
5896
5897                           return;
5898                         }
5899                       else
5900                         {
5901                           emitcode ("rlc", "a");
5902                         }
5903                     }
5904                   goto release;
5905                 }
5906               else
5907                 {//nonzero literal
5908                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5909                   while (size && (bytelit == 0))
5910                     {
5911                       offset++;
5912                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5913                       size--;
5914                     }
5915                   CLRC;
5916                   while (size--)
5917                     {
5918                       MOVA (aopGet (left, offset, FALSE, FALSE));
5919                       if (sign && size == 0)
5920                         {
5921                           emitcode ("xrl", "a,#0x80");
5922                           emitcode ("subb", "a,#0x%02x",
5923                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5924                         }
5925                       else
5926                         {
5927                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5928                         }
5929                       offset++;
5930                     }
5931                   goto release;
5932                 }
5933             }
5934           CLRC;
5935           while (size--)
5936             {
5937               bool pushedB = FALSE;
5938               rightInB = aopGetUsesAcc(right, offset);
5939               if (rightInB)
5940                 {
5941                   pushedB = pushB ();
5942                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5943                 }
5944               MOVA (aopGet (left, offset, FALSE, FALSE));
5945               if (sign && size == 0)
5946                 {
5947                   emitcode ("xrl", "a,#0x80");
5948                   if (!rightInB)
5949                     {
5950                       pushedB = pushB ();
5951                       rightInB++;
5952                       MOVB (aopGet (right, offset, FALSE, FALSE));
5953                     }
5954                   emitcode ("xrl", "b,#0x80");
5955                   emitcode ("subb", "a,b");
5956                 }
5957               else
5958                 {
5959                   if (rightInB)
5960                     emitcode ("subb", "a,b");
5961                   else
5962                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5963                 }
5964               if (rightInB)
5965                 popB (pushedB);
5966               offset++;
5967             }
5968         }
5969     }
5970
5971 release:
5972   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5973   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5974   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5975     {
5976       outBitC (result);
5977     }
5978   else
5979     {
5980       /* if the result is used in the next
5981          ifx conditional branch then generate
5982          code a little differently */
5983       if (ifx)
5984         {
5985           genIfxJump (ifx, "c", NULL, NULL, result);
5986         }
5987       else
5988         {
5989           outBitC (result);
5990         }
5991       /* leave the result in acc */
5992     }
5993 }
5994
5995 /*-----------------------------------------------------------------*/
5996 /* genCmpGt :- greater than comparison                             */
5997 /*-----------------------------------------------------------------*/
5998 static void
5999 genCmpGt (iCode * ic, iCode * ifx)
6000 {
6001   operand *left, *right, *result;
6002   sym_link *letype, *retype;
6003   int sign;
6004
6005   D (emitcode (";", "genCmpGt"));
6006
6007   left = IC_LEFT (ic);
6008   right = IC_RIGHT (ic);
6009   result = IC_RESULT (ic);
6010
6011   letype = getSpec (operandType (left));
6012   retype = getSpec (operandType (right));
6013   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6014            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6015   /* assign the asmops */
6016   aopOp (result, ic, TRUE);
6017   aopOp (left, ic, FALSE);
6018   aopOp (right, ic, FALSE);
6019
6020   genCmp (right, left, result, ifx, sign, ic);
6021
6022   freeAsmop (result, NULL, ic, TRUE);
6023 }
6024
6025 /*-----------------------------------------------------------------*/
6026 /* genCmpLt - less than comparisons                                */
6027 /*-----------------------------------------------------------------*/
6028 static void
6029 genCmpLt (iCode * ic, iCode * ifx)
6030 {
6031   operand *left, *right, *result;
6032   sym_link *letype, *retype;
6033   int sign;
6034
6035   D (emitcode (";", "genCmpLt"));
6036
6037   left = IC_LEFT (ic);
6038   right = IC_RIGHT (ic);
6039   result = IC_RESULT (ic);
6040
6041   letype = getSpec (operandType (left));
6042   retype = getSpec (operandType (right));
6043   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6044            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6045   /* assign the asmops */
6046   aopOp (result, ic, TRUE);
6047   aopOp (left, ic, FALSE);
6048   aopOp (right, ic, FALSE);
6049
6050   genCmp (left, right, result, ifx, sign, ic);
6051
6052   freeAsmop (result, NULL, ic, TRUE);
6053 }
6054
6055 /*-----------------------------------------------------------------*/
6056 /* gencjneshort - compare and jump if not equal                    */
6057 /*-----------------------------------------------------------------*/
6058 static void
6059 gencjneshort (operand * left, operand * right, symbol * lbl)
6060 {
6061   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6062   int offset = 0;
6063   unsigned long lit = 0L;
6064
6065   D (emitcode (";", "gencjneshort"));
6066
6067   /* if the left side is a literal or
6068      if the right is in a pointer register and left
6069      is not */
6070   if ((AOP_TYPE (left) == AOP_LIT)  ||
6071       (AOP_TYPE (left) == AOP_IMMD) ||
6072       (AOP_TYPE (left) == AOP_DIR)  ||
6073       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6074     {
6075       operand *t = right;
6076       right = left;
6077       left = t;
6078     }
6079
6080   if (AOP_TYPE (right) == AOP_LIT)
6081     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6082
6083   /* if the right side is a literal then anything goes */
6084   if (AOP_TYPE (right) == AOP_LIT &&
6085       AOP_TYPE (left) != AOP_DIR  &&
6086       AOP_TYPE (left) != AOP_IMMD)
6087     {
6088       while (size--)
6089         {
6090           emitcode ("cjne", "%s,%s,%05d$",
6091                     aopGet (left, offset, FALSE, FALSE),
6092                     aopGet (right, offset, FALSE, FALSE),
6093                     lbl->key + 100);
6094           offset++;
6095         }
6096     }
6097
6098   /* if the right side is in a register or in direct space or
6099      if the left is a pointer register & right is not */
6100   else if (AOP_TYPE (right) == AOP_REG ||
6101            AOP_TYPE (right) == AOP_DIR ||
6102            AOP_TYPE (right) == AOP_LIT ||
6103            AOP_TYPE (right) == AOP_IMMD ||
6104            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6105            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6106     {
6107       while (size--)
6108         {
6109           MOVA (aopGet (left, offset, FALSE, FALSE));
6110           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6111               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6112             emitcode ("jnz", "%05d$", lbl->key + 100);
6113           else
6114             emitcode ("cjne", "a,%s,%05d$",
6115                       aopGet (right, offset, FALSE, TRUE),
6116                       lbl->key + 100);
6117           offset++;
6118         }
6119     }
6120   else
6121     {
6122       /* right is a pointer reg need both a & b */
6123       while (size--)
6124         {
6125           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6126           wassertl(!BINUSE, "B was in use");
6127           MOVB (aopGet (left, offset, FALSE, FALSE));
6128           MOVA (aopGet (right, offset, FALSE, FALSE));
6129           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6130           offset++;
6131         }
6132     }
6133 }
6134
6135 /*-----------------------------------------------------------------*/
6136 /* gencjne - compare and jump if not equal                         */
6137 /*-----------------------------------------------------------------*/
6138 static void
6139 gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
6140 {
6141   symbol *tlbl = newiTempLabel (NULL);
6142
6143   D (emitcode (";", "gencjne"));
6144
6145   gencjneshort (left, right, lbl);
6146
6147   if (useCarry)
6148       SETC;
6149   else
6150       MOVA (one);
6151   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6152   emitLabel (lbl);
6153   if (useCarry)
6154       CLRC;
6155   else
6156       MOVA (zero);
6157   emitLabel (tlbl);
6158 }
6159
6160 /*-----------------------------------------------------------------*/
6161 /* genCmpEq - generates code for equal to                          */
6162 /*-----------------------------------------------------------------*/
6163 static void
6164 genCmpEq (iCode * ic, iCode * ifx)
6165 {
6166   bool swappedLR = FALSE;
6167   operand *left, *right, *result;
6168
6169   D (emitcode (";", "genCmpEq"));
6170
6171   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6172   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6173   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6174
6175   /* if literal, literal on the right or
6176      if the right is in a pointer register and left
6177      is not */
6178   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6179       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6180     {
6181       operand *t = IC_RIGHT (ic);
6182       IC_RIGHT (ic) = IC_LEFT (ic);
6183       IC_LEFT (ic) = t;
6184       swappedLR = TRUE;
6185     }
6186
6187   if (ifx && !AOP_SIZE (result))
6188     {
6189       symbol *tlbl;
6190       /* if they are both bit variables */
6191       if (AOP_TYPE (left) == AOP_CRY &&
6192           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6193         {
6194           if (AOP_TYPE (right) == AOP_LIT)
6195             {
6196               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6197               if (lit == 0L)
6198                 {
6199                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6200                   emitcode ("cpl", "c");
6201                 }
6202               else if (lit == 1L)
6203                 {
6204                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6205                 }
6206               else
6207                 {
6208                   emitcode ("clr", "c");
6209                 }
6210               /* AOP_TYPE(right) == AOP_CRY */
6211             }
6212           else
6213             {
6214               symbol *lbl = newiTempLabel (NULL);
6215               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6216               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6217               emitcode ("cpl", "c");
6218               emitLabel (lbl);
6219             }
6220           /* if true label then we jump if condition
6221              supplied is true */
6222           tlbl = newiTempLabel (NULL);
6223           if (IC_TRUE (ifx))
6224             {
6225               emitcode ("jnc", "%05d$", tlbl->key + 100);
6226               freeForBranchAsmop (result);
6227               freeForBranchAsmop (right);
6228               freeForBranchAsmop (left);
6229               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6230             }
6231           else
6232             {
6233               emitcode ("jc", "%05d$", tlbl->key + 100);
6234               freeForBranchAsmop (result);
6235               freeForBranchAsmop (right);
6236               freeForBranchAsmop (left);
6237               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6238             }
6239           emitLabel (tlbl);
6240         }
6241       else
6242         {
6243           tlbl = newiTempLabel (NULL);
6244           gencjneshort (left, right, tlbl);
6245           if (IC_TRUE (ifx))
6246             {
6247               freeForBranchAsmop (result);
6248               freeForBranchAsmop (right);
6249               freeForBranchAsmop (left);
6250               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6251               emitLabel (tlbl);
6252             }
6253           else
6254             {
6255               symbol *lbl = newiTempLabel (NULL);
6256               emitcode ("sjmp", "%05d$", lbl->key + 100);
6257               emitLabel (tlbl);
6258               freeForBranchAsmop (result);
6259               freeForBranchAsmop (right);
6260               freeForBranchAsmop (left);
6261               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6262               emitLabel (lbl);
6263             }
6264         }
6265       /* mark the icode as generated */
6266       ifx->generated = 1;
6267       goto release;
6268     }
6269
6270   /* if they are both bit variables */
6271   if (AOP_TYPE (left) == AOP_CRY &&
6272       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6273     {
6274       if (AOP_TYPE (right) == AOP_LIT)
6275         {
6276           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6277           if (lit == 0L)
6278             {
6279               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6280               emitcode ("cpl", "c");
6281             }
6282           else if (lit == 1L)
6283             {
6284               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6285             }
6286           else
6287             {
6288               emitcode ("clr", "c");
6289             }
6290           /* AOP_TYPE(right) == AOP_CRY */
6291         }
6292       else
6293         {
6294           symbol *lbl = newiTempLabel (NULL);
6295           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6296           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6297           emitcode ("cpl", "c");
6298           emitLabel (lbl);
6299         }
6300       /* c = 1 if egal */
6301       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6302         {
6303           outBitC (result);
6304           goto release;
6305         }
6306       if (ifx)
6307         {
6308           genIfxJump (ifx, "c", left, right, result);
6309           goto release;
6310         }
6311       /* if the result is used in an arithmetic operation
6312          then put the result in place */
6313       outBitC (result);
6314     }
6315   else
6316     {
6317       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6318         {
6319           gencjne (left, right, newiTempLabel (NULL), TRUE);
6320           aopPut (result, "c", 0);
6321           goto release;
6322         }
6323       gencjne (left, right, newiTempLabel (NULL), FALSE);
6324       if (ifx)
6325         {
6326           genIfxJump (ifx, "a", left, right, result);
6327           goto release;
6328         }
6329       /* if the result is used in an arithmetic operation
6330          then put the result in place */
6331       if (AOP_TYPE (result) != AOP_CRY)
6332         outAcc (result);
6333       /* leave the result in acc */
6334     }
6335
6336 release:
6337   freeAsmop (result, NULL, ic, TRUE);
6338   if (!swappedLR)
6339     {
6340       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6341       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6342     }
6343   else
6344     {
6345       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6346       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6347     }
6348 }
6349
6350 /*-----------------------------------------------------------------*/
6351 /* ifxForOp - returns the icode containing the ifx for operand     */
6352 /*-----------------------------------------------------------------*/
6353 static iCode *
6354 ifxForOp (operand * op, iCode * ic)
6355 {
6356   /* if true symbol then needs to be assigned */
6357   if (IS_TRUE_SYMOP (op))
6358     return NULL;
6359
6360   /* if this has register type condition and
6361      the next instruction is ifx with the same operand
6362      and live to of the operand is upto the ifx only then */
6363   if (ic->next &&
6364       ic->next->op == IFX &&
6365       IC_COND (ic->next)->key == op->key &&
6366       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6367     return ic->next;
6368
6369   return NULL;
6370 }
6371
6372 /*-----------------------------------------------------------------*/
6373 /* hasInc - operand is incremented before any other use            */
6374 /*-----------------------------------------------------------------*/
6375 static iCode *
6376 hasInc (operand *op, iCode *ic, int osize)
6377 {
6378   sym_link *type = operandType(op);
6379   sym_link *retype = getSpec (type);
6380   iCode *lic = ic->next;
6381   int isize ;
6382
6383   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6384   if (!IS_SYMOP(op)) return NULL;
6385
6386   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6387   if (IS_AGGREGATE(type->next)) return NULL;
6388   if (osize != (isize = getSize(type->next))) return NULL;
6389
6390   while (lic) {
6391     /* if operand of the form op = op + <sizeof *op> */
6392     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6393         isOperandEqual(IC_RESULT(lic),op) &&
6394         isOperandLiteral(IC_RIGHT(lic)) &&
6395         operandLitValue(IC_RIGHT(lic)) == isize) {
6396       return lic;
6397     }
6398     /* if the operand used or deffed */
6399     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6400       return NULL;
6401     }
6402     /* if GOTO or IFX */
6403     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6404     lic = lic->next;
6405   }
6406   return NULL;
6407 }
6408
6409 /*-----------------------------------------------------------------*/
6410 /* genAndOp - for && operation                                     */
6411 /*-----------------------------------------------------------------*/
6412 static void
6413 genAndOp (iCode * ic)
6414 {
6415   operand *left, *right, *result;
6416   symbol *tlbl;
6417
6418   D (emitcode (";", "genAndOp"));
6419
6420   /* note here that && operations that are in an
6421      if statement are taken away by backPatchLabels
6422      only those used in arthmetic operations remain */
6423   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6424   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6425   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6426
6427   /* if both are bit variables */
6428   if (AOP_TYPE (left) == AOP_CRY &&
6429       AOP_TYPE (right) == AOP_CRY)
6430     {
6431       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6432       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6433       outBitC (result);
6434     }
6435   else
6436     {
6437       tlbl = newiTempLabel (NULL);
6438       toBoolean (left);
6439       emitcode ("jz", "%05d$", tlbl->key + 100);
6440       toBoolean (right);
6441       emitLabel (tlbl);
6442       outBitAcc (result);
6443     }
6444
6445   freeAsmop (result, NULL, ic, TRUE);
6446   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6447   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6448 }
6449
6450
6451 /*-----------------------------------------------------------------*/
6452 /* genOrOp - for || operation                                      */
6453 /*-----------------------------------------------------------------*/
6454 static void
6455 genOrOp (iCode * ic)
6456 {
6457   operand *left, *right, *result;
6458   symbol *tlbl;
6459
6460   D (emitcode (";", "genOrOp"));
6461
6462   /* note here that || operations that are in an
6463      if statement are taken away by backPatchLabels
6464      only those used in arthmetic operations remain */
6465   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6466   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6467   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6468
6469   /* if both are bit variables */
6470   if (AOP_TYPE (left) == AOP_CRY &&
6471       AOP_TYPE (right) == AOP_CRY)
6472     {
6473       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6474       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6475       outBitC (result);
6476     }
6477   else
6478     {
6479       tlbl = newiTempLabel (NULL);
6480       toBoolean (left);
6481       emitcode ("jnz", "%05d$", tlbl->key + 100);
6482       toBoolean (right);
6483       emitLabel (tlbl);
6484       outBitAcc (result);
6485     }
6486
6487   freeAsmop (result, NULL, ic, TRUE);
6488   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6489   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6490 }
6491
6492 /*-----------------------------------------------------------------*/
6493 /* isLiteralBit - test if lit == 2^n                               */
6494 /*-----------------------------------------------------------------*/
6495 static int
6496 isLiteralBit (unsigned long lit)
6497 {
6498   unsigned long pw[32] =
6499   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6500    0x100L, 0x200L, 0x400L, 0x800L,
6501    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6502    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6503    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6504    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6505    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6506   int idx;
6507
6508   for (idx = 0; idx < 32; idx++)
6509     if (lit == pw[idx])
6510       return idx + 1;
6511   return 0;
6512 }
6513
6514 /*-----------------------------------------------------------------*/
6515 /* continueIfTrue -                                                */
6516 /*-----------------------------------------------------------------*/
6517 static void
6518 continueIfTrue (iCode * ic)
6519 {
6520   if (IC_TRUE (ic))
6521     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6522   ic->generated = 1;
6523 }
6524
6525 /*-----------------------------------------------------------------*/
6526 /* jmpIfTrue -                                                     */
6527 /*-----------------------------------------------------------------*/
6528 static void
6529 jumpIfTrue (iCode * ic)
6530 {
6531   if (!IC_TRUE (ic))
6532     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6533   ic->generated = 1;
6534 }
6535
6536 /*-----------------------------------------------------------------*/
6537 /* jmpTrueOrFalse -                                                */
6538 /*-----------------------------------------------------------------*/
6539 static void
6540 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6541 {
6542   // ugly but optimized by peephole
6543   if (IC_TRUE (ic))
6544     {
6545       symbol *nlbl = newiTempLabel (NULL);
6546       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6547       emitLabel (tlbl);
6548       freeForBranchAsmop (result);
6549       freeForBranchAsmop (right);
6550       freeForBranchAsmop (left);
6551       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6552       emitLabel (nlbl);
6553     }
6554   else
6555     {
6556       freeForBranchAsmop (result);
6557       freeForBranchAsmop (right);
6558       freeForBranchAsmop (left);
6559       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6560       emitLabel (tlbl);
6561     }
6562   ic->generated = 1;
6563 }
6564
6565 /*-----------------------------------------------------------------*/
6566 /* genAnd  - code for and                                          */
6567 /*-----------------------------------------------------------------*/
6568 static void
6569 genAnd (iCode * ic, iCode * ifx)
6570 {
6571   operand *left, *right, *result;
6572   int size, offset = 0;
6573   unsigned long lit = 0L;
6574   int bytelit = 0;
6575   char buffer[10];
6576
6577   D (emitcode (";", "genAnd"));
6578
6579   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6580   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6581   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6582
6583 #ifdef DEBUG_TYPE
6584   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6585             AOP_TYPE (result),
6586             AOP_TYPE (left), AOP_TYPE (right));
6587   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6588             AOP_SIZE (result),
6589             AOP_SIZE (left), AOP_SIZE (right));
6590 #endif
6591
6592   /* if left is a literal & right is not then exchange them */
6593   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6594       AOP_NEEDSACC (left))
6595     {
6596       operand *tmp = right;
6597       right = left;
6598       left = tmp;
6599     }
6600
6601   /* if result = right then exchange left and right */
6602   if (sameRegs (AOP (result), AOP (right)))
6603     {
6604       operand *tmp = right;
6605       right = left;
6606       left = tmp;
6607     }
6608
6609   /* if right is bit then exchange them */
6610   if (AOP_TYPE (right) == AOP_CRY &&
6611       AOP_TYPE (left) != AOP_CRY)
6612     {
6613       operand *tmp = right;
6614       right = left;
6615       left = tmp;
6616     }
6617   if (AOP_TYPE (right) == AOP_LIT)
6618     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6619
6620   size = AOP_SIZE (result);
6621
6622   // if(bit & yy)
6623   // result = bit & yy;
6624   if (AOP_TYPE (left) == AOP_CRY)
6625     {
6626       // c = bit & literal;
6627       if (AOP_TYPE (right) == AOP_LIT)
6628         {
6629           if (lit & 1)
6630             {
6631               if (size && sameRegs (AOP (result), AOP (left)))
6632                 // no change
6633                 goto release;
6634               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6635             }
6636           else
6637             {
6638               // bit(result) = 0;
6639               if (size && (AOP_TYPE (result) == AOP_CRY))
6640                 {
6641                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6642                   goto release;
6643                 }
6644               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6645                 {
6646                   jumpIfTrue (ifx);
6647                   goto release;
6648                 }
6649               emitcode ("clr", "c");
6650             }
6651         }
6652       else
6653         {
6654           if (AOP_TYPE (right) == AOP_CRY)
6655             {
6656               // c = bit & bit;
6657               if (IS_OP_ACCUSE (left))
6658                 {
6659                   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6660                 }
6661               else
6662                 {
6663                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6664                   emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6665                 }
6666             }
6667           else
6668             {
6669               // c = bit & val;
6670               MOVA (aopGet (right, 0, FALSE, FALSE));
6671               // c = lsb
6672               emitcode ("rrc", "a");
6673               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6674             }
6675         }
6676       // bit = c
6677       // val = c
6678       if (size)
6679         outBitC (result);
6680       // if(bit & ...)
6681       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6682         genIfxJump (ifx, "c", left, right, result);
6683       goto release;
6684     }
6685
6686   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6687   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6688   if ((AOP_TYPE (right) == AOP_LIT) &&
6689       (AOP_TYPE (result) == AOP_CRY) &&
6690       (AOP_TYPE (left) != AOP_CRY))
6691     {
6692       int posbit = isLiteralBit (lit);
6693       /* left &  2^n */
6694       if (posbit)
6695         {
6696           posbit--;
6697           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6698           // bit = left & 2^n
6699           if (size)
6700             {
6701               switch (posbit & 0x07)
6702                 {
6703                   case 0: emitcode ("rrc", "a");
6704                           break;
6705                   case 7: emitcode ("rlc", "a");
6706                           break;
6707                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6708                           break;
6709                 }
6710             }
6711           // if(left &  2^n)
6712           else
6713             {
6714               if (ifx)
6715                 {
6716                   SNPRINTF (buffer, sizeof(buffer),
6717                             "acc.%d", posbit & 0x07);
6718                   genIfxJump (ifx, buffer, left, right, result);
6719                 }
6720               else
6721                 {// what is this case? just found it in ds390/gen.c
6722                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6723                 }
6724               goto release;
6725             }
6726         }
6727       else
6728         {
6729           symbol *tlbl = newiTempLabel (NULL);
6730           int sizel = AOP_SIZE (left);
6731           if (size)
6732             emitcode ("setb", "c");
6733           while (sizel--)
6734             {
6735               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6736                 {
6737                   MOVA (aopGet (left, offset, FALSE, FALSE));
6738                   // byte ==  2^n ?
6739                   if ((posbit = isLiteralBit (bytelit)) != 0)
6740                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6741                   else
6742                     {
6743                       if (bytelit != 0x0FFL)
6744                         emitcode ("anl", "a,%s",
6745                                   aopGet (right, offset, FALSE, TRUE));
6746                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6747                     }
6748                 }
6749               offset++;
6750             }
6751           // bit = left & literal
6752           if (size)
6753             {
6754               emitcode ("clr", "c");
6755               emitLabel (tlbl);
6756             }
6757           // if(left & literal)
6758           else
6759             {
6760               if (ifx)
6761                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6762               else
6763                 emitLabel (tlbl);
6764               goto release;
6765             }
6766         }
6767       outBitC (result);
6768       goto release;
6769     }
6770
6771   /* if left is same as result */
6772   if (sameRegs (AOP (result), AOP (left)))
6773     {
6774       for (; size--; offset++)
6775         {
6776           if (AOP_TYPE (right) == AOP_LIT)
6777             {
6778               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6779               if (bytelit == 0x0FF)
6780                 {
6781                   /* dummy read of volatile operand */
6782                   if (isOperandVolatile (left, FALSE))
6783                     MOVA (aopGet (left, offset, FALSE, FALSE));
6784                   else
6785                     continue;
6786                 }
6787               else if (bytelit == 0)
6788                 {
6789                   aopPut (result, zero, offset);
6790                 }
6791               else if (IS_AOP_PREG (result))
6792                 {
6793                   MOVA (aopGet (left, offset, FALSE, TRUE));
6794                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6795                   aopPut (result, "a", offset);
6796                 }
6797               else
6798                 emitcode ("anl", "%s,%s",
6799                           aopGet (left, offset, FALSE, TRUE),
6800                           aopGet (right, offset, FALSE, FALSE));
6801             }
6802           else
6803             {
6804               if (AOP_TYPE (left) == AOP_ACC)
6805                 {
6806                   if (offset)
6807                     emitcode("mov", "a,b");
6808                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6809                 }
6810               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6811                 {
6812                   MOVB (aopGet (left, offset, FALSE, FALSE));
6813                   MOVA (aopGet (right, offset, FALSE, FALSE));
6814                   emitcode ("anl", "a,b");
6815                   aopPut (result, "a", offset);
6816                 }
6817               else if (aopGetUsesAcc (left, offset))
6818                 {
6819                   MOVA (aopGet (left, offset, FALSE, FALSE));
6820                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6821                   aopPut (result, "a", offset);
6822                 }
6823               else
6824                 {
6825                   MOVA (aopGet (right, offset, FALSE, FALSE));
6826                   if (IS_AOP_PREG (result))
6827                     {
6828                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6829                       aopPut (result, "a", offset);
6830                     }
6831                   else
6832                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6833                 }
6834             }
6835         }
6836     }
6837   else
6838     {
6839       // left & result in different registers
6840       if (AOP_TYPE (result) == AOP_CRY)
6841         {
6842           // result = bit
6843           // if(size), result in bit
6844           // if(!size && ifx), conditional oper: if(left & right)
6845           symbol *tlbl = newiTempLabel (NULL);
6846           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6847           if (size)
6848             emitcode ("setb", "c");
6849           while (sizer--)
6850             {
6851               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6852                   && AOP_TYPE(left)==AOP_ACC)
6853                 {
6854                   if (offset)
6855                     emitcode("mov", "a,b");
6856                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6857                 }
6858               else if (AOP_TYPE(left)==AOP_ACC)
6859                 {
6860                   if (!offset)
6861                     {
6862                       bool pushedB = pushB ();
6863                       emitcode("mov", "b,a");
6864                       MOVA (aopGet (right, offset, FALSE, FALSE));
6865                       emitcode("anl", "a,b");
6866                       popB (pushedB);
6867                     }
6868                   else
6869                     {
6870                       MOVA (aopGet (right, offset, FALSE, FALSE));
6871                       emitcode("anl", "a,b");
6872                     }
6873                 }
6874               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6875                 {
6876                   MOVB (aopGet (left, offset, FALSE, FALSE));
6877                   MOVA (aopGet (right, offset, FALSE, FALSE));
6878                   emitcode ("anl", "a,b");
6879                 }
6880               else if (aopGetUsesAcc (left, offset))
6881                 {
6882                   MOVA (aopGet (left, offset, FALSE, FALSE));
6883                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6884                     }
6885               else
6886                 {
6887                   MOVA (aopGet (right, offset, FALSE, FALSE));
6888                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6889                 }
6890
6891               emitcode ("jnz", "%05d$", tlbl->key + 100);
6892               offset++;
6893             }
6894           if (size)
6895             {
6896               CLRC;
6897               emitLabel (tlbl);
6898               outBitC (result);
6899             }
6900           else if (ifx)
6901             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6902           else
6903             emitLabel (tlbl);
6904         }
6905       else
6906         {
6907           for (; (size--); offset++)
6908             {
6909               // normal case
6910               // result = left & right
6911               if (AOP_TYPE (right) == AOP_LIT)
6912                 {
6913                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6914                   if (bytelit == 0x0FF)
6915                     {
6916                       aopPut (result,
6917                               aopGet (left, offset, FALSE, FALSE),
6918                               offset);
6919                       continue;
6920                     }
6921                   else if (bytelit == 0)
6922                     {
6923                       /* dummy read of volatile operand */
6924                       if (isOperandVolatile (left, FALSE))
6925                         MOVA (aopGet (left, offset, FALSE, FALSE));
6926                       aopPut (result, zero, offset);
6927                       continue;
6928                     }
6929                   else if (AOP_TYPE (left) == AOP_ACC)
6930                     {
6931                       if (!offset)
6932                         {
6933                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6934                           aopPut (result, "a", offset);
6935                           continue;
6936                         }
6937                       else
6938                         {
6939                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6940                           aopPut (result, "b", offset);
6941                           continue;
6942                         }
6943                     }
6944                 }
6945               // faster than result <- left, anl result,right
6946               // and better if result is SFR
6947               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6948                   && AOP_TYPE(left)==AOP_ACC)
6949                 {
6950                   if (offset)
6951                     emitcode("mov", "a,b");
6952                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6953                 }
6954               else if (AOP_TYPE(left)==AOP_ACC)
6955                 {
6956                   if (!offset)
6957                     {
6958                       bool pushedB = pushB ();
6959                       emitcode("mov", "b,a");
6960                       MOVA (aopGet (right, offset, FALSE, FALSE));
6961                       emitcode("anl", "a,b");
6962                       popB (pushedB);
6963                     }
6964                   else
6965                     {
6966                       MOVA (aopGet (right, offset, FALSE, FALSE));
6967                       emitcode("anl", "a,b");
6968                     }
6969                 }
6970               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6971                 {
6972                   MOVB (aopGet (left, offset, FALSE, FALSE));
6973                   MOVA (aopGet (right, offset, FALSE, FALSE));
6974                   emitcode ("anl", "a,b");
6975                 }
6976               else if (aopGetUsesAcc (left, offset))
6977                 {
6978                   MOVA (aopGet (left, offset, FALSE, FALSE));
6979                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6980                 }
6981               else
6982                 {
6983                   MOVA (aopGet (right, offset, FALSE, FALSE));
6984                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6985                 }
6986               aopPut (result, "a", offset);
6987             }
6988         }
6989     }
6990
6991 release:
6992   freeAsmop (result, NULL, ic, TRUE);
6993   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6994   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6995 }
6996
6997 /*-----------------------------------------------------------------*/
6998 /* genOr  - code for or                                            */
6999 /*-----------------------------------------------------------------*/
7000 static void
7001 genOr (iCode * ic, iCode * ifx)
7002 {
7003   operand *left, *right, *result;
7004   int size, offset = 0;
7005   unsigned long lit = 0L;
7006   int bytelit = 0;
7007
7008   D (emitcode (";", "genOr"));
7009
7010   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7011   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7012   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7013
7014 #ifdef DEBUG_TYPE
7015   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7016             AOP_TYPE (result),
7017             AOP_TYPE (left), AOP_TYPE (right));
7018   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7019             AOP_SIZE (result),
7020             AOP_SIZE (left), AOP_SIZE (right));
7021 #endif
7022
7023   /* if left is a literal & right is not then exchange them */
7024   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7025       AOP_NEEDSACC (left))
7026     {
7027       operand *tmp = right;
7028       right = left;
7029       left = tmp;
7030     }
7031
7032   /* if result = right then exchange them */
7033   if (sameRegs (AOP (result), AOP (right)))
7034     {
7035       operand *tmp = right;
7036       right = left;
7037       left = tmp;
7038     }
7039
7040   /* if right is bit then exchange them */
7041   if (AOP_TYPE (right) == AOP_CRY &&
7042       AOP_TYPE (left) != AOP_CRY)
7043     {
7044       operand *tmp = right;
7045       right = left;
7046       left = tmp;
7047     }
7048   if (AOP_TYPE (right) == AOP_LIT)
7049     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7050
7051   size = AOP_SIZE (result);
7052
7053   // if(bit | yy)
7054   // xx = bit | yy;
7055   if (AOP_TYPE (left) == AOP_CRY)
7056     {
7057       if (AOP_TYPE (right) == AOP_LIT)
7058         {
7059           // c = bit | literal;
7060           if (lit)
7061             {
7062               // lit != 0 => result = 1
7063               if (AOP_TYPE (result) == AOP_CRY)
7064                 {
7065                   if (size)
7066                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7067                   else if (ifx)
7068                     continueIfTrue (ifx);
7069                   goto release;
7070                 }
7071               emitcode ("setb", "c");
7072             }
7073           else
7074             {
7075               // lit == 0 => result = left
7076               if (size && sameRegs (AOP (result), AOP (left)))
7077                 goto release;
7078               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7079             }
7080         }
7081       else
7082         {
7083           if (AOP_TYPE (right) == AOP_CRY)
7084             {
7085               // c = bit | bit;
7086               if (IS_OP_ACCUSE (left))
7087                 {
7088                   emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7089                 }
7090               else
7091                 {
7092                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7093                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7094                 }
7095             }
7096           else
7097             {
7098               // c = bit | val;
7099               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7100                 {
7101                   symbol *tlbl = newiTempLabel (NULL);
7102                   emitcode ("jb", "%s,%05d$",
7103                             AOP (left)->aopu.aop_dir, tlbl->key + 100);
7104                   toBoolean (right);
7105                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7106                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7107                   goto release;
7108                 }
7109               else
7110                 {
7111                   toCarry (right);
7112                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7113                 }
7114             }
7115         }
7116       // bit = c
7117       // val = c
7118       if (size)
7119         outBitC (result);
7120       // if(bit | ...)
7121       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7122         genIfxJump (ifx, "c", left, right, result);
7123       goto release;
7124     }
7125
7126   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7127   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7128   if ((AOP_TYPE (right) == AOP_LIT) &&
7129       (AOP_TYPE (result) == AOP_CRY) &&
7130       (AOP_TYPE (left) != AOP_CRY))
7131     {
7132       if (lit)
7133         {
7134           // result = 1
7135           if (size)
7136             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7137           else
7138             continueIfTrue (ifx);
7139           goto release;
7140         }
7141       else
7142         {
7143           // lit = 0, result = boolean(left)
7144           if (size)
7145             emitcode ("setb", "c");
7146           toBoolean (right);
7147           if (size)
7148             {
7149               symbol *tlbl = newiTempLabel (NULL);
7150               emitcode ("jnz", "%05d$", tlbl->key + 100);
7151               CLRC;
7152               emitLabel (tlbl);
7153             }
7154           else
7155             {
7156               genIfxJump (ifx, "a", left, right, result);
7157               goto release;
7158             }
7159         }
7160       outBitC (result);
7161       goto release;
7162     }
7163
7164   /* if left is same as result */
7165   if (sameRegs (AOP (result), AOP (left)))
7166     {
7167       for (; size--; offset++)
7168         {
7169           if (AOP_TYPE (right) == AOP_LIT)
7170             {
7171               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7172               if (bytelit == 0)
7173                 {
7174                   /* dummy read of volatile operand */
7175                   if (isOperandVolatile (left, FALSE))
7176                     MOVA (aopGet (left, offset, FALSE, FALSE));
7177                   else
7178                     continue;
7179                 }
7180               else if (bytelit == 0x0FF)
7181                 {
7182                   aopPut (result, "#0xFF", offset);
7183                 }
7184               else if (IS_AOP_PREG (left))
7185                 {
7186                   MOVA (aopGet (left, offset, FALSE, TRUE));
7187                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7188                   aopPut (result, "a", offset);
7189                 }
7190               else
7191                 {
7192                   emitcode ("orl", "%s,%s",
7193                             aopGet (left, offset, FALSE, TRUE),
7194                             aopGet (right, offset, FALSE, FALSE));
7195                 }
7196             }
7197           else
7198             {
7199               if (AOP_TYPE (left) == AOP_ACC)
7200                 {
7201                   if (offset)
7202                     emitcode("mov", "a,b");
7203                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7204                 }
7205               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7206                 {
7207                   MOVB (aopGet (left, offset, FALSE, FALSE));
7208                   MOVA (aopGet (right, offset, FALSE, FALSE));
7209                   emitcode ("orl", "a,b");
7210                   aopPut (result, "a", offset);
7211                 }
7212               else if (aopGetUsesAcc (left, offset))
7213                 {
7214                   MOVA (aopGet (left, offset, FALSE, FALSE));
7215                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7216                   aopPut (result, "a", offset);
7217                 }
7218               else
7219                 {
7220                   MOVA (aopGet (right, offset, FALSE, FALSE));
7221                   if (IS_AOP_PREG (left))
7222                     {
7223                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7224                       aopPut (result, "a", offset);
7225                     }
7226                   else
7227                     {
7228                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7229                     }
7230                 }
7231             }
7232         }
7233     }
7234   else
7235     {
7236       // left & result in different registers
7237       if (AOP_TYPE (result) == AOP_CRY)
7238         {
7239           // result = bit
7240           // if(size), result in bit
7241           // if(!size && ifx), conditional oper: if(left | right)
7242           symbol *tlbl = newiTempLabel (NULL);
7243           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7244           if (size)
7245             emitcode ("setb", "c");
7246           while (sizer--)
7247             {
7248               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7249                   && AOP_TYPE(left)==AOP_ACC)
7250                 {
7251                   if (offset)
7252                     emitcode("mov", "a,b");
7253                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7254                 }
7255               else if (AOP_TYPE(left)==AOP_ACC)
7256                 {
7257                   if (!offset)
7258                     {
7259                       bool pushedB = pushB ();
7260                       emitcode("mov", "b,a");
7261                       MOVA (aopGet (right, offset, FALSE, FALSE));
7262                       emitcode("orl", "a,b");
7263                       popB (pushedB);
7264                     }
7265                   else
7266                     {
7267                       MOVA (aopGet (right, offset, FALSE, FALSE));
7268                       emitcode("orl", "a,b");
7269                     }
7270                 }
7271               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7272                 {
7273                   MOVB (aopGet (left, offset, FALSE, FALSE));
7274                   MOVA (aopGet (right, offset, FALSE, FALSE));
7275                   emitcode ("orl", "a,b");
7276                 }
7277               else if (aopGetUsesAcc (left, offset))
7278                 {
7279                   MOVA (aopGet (left, offset, FALSE, FALSE));
7280                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7281                 }
7282               else
7283                 {
7284                   MOVA (aopGet (right, offset, FALSE, FALSE));
7285                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7286               }
7287
7288               emitcode ("jnz", "%05d$", tlbl->key + 100);
7289               offset++;
7290             }
7291           if (size)
7292             {
7293               CLRC;
7294               emitLabel (tlbl);
7295               outBitC (result);
7296             }
7297           else if (ifx)
7298             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7299           else
7300             emitLabel (tlbl);
7301         }
7302       else
7303         {
7304           for (; (size--); offset++)
7305             {
7306               // normal case
7307               // result = left | right
7308               if (AOP_TYPE (right) == AOP_LIT)
7309                 {
7310                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7311                   if (bytelit == 0)
7312                     {
7313                       aopPut (result,
7314                               aopGet (left, offset, FALSE, FALSE),
7315                               offset);
7316                       continue;
7317                     }
7318                   else if (bytelit == 0x0FF)
7319                     {
7320                       /* dummy read of volatile operand */
7321                       if (isOperandVolatile (left, FALSE))
7322                         MOVA (aopGet (left, offset, FALSE, FALSE));
7323                       aopPut (result, "#0xFF", offset);
7324                       continue;
7325                     }
7326                 }
7327               // faster than result <- left, orl result,right
7328               // and better if result is SFR
7329               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7330                   && AOP_TYPE(left)==AOP_ACC)
7331                 {
7332                   if (offset)
7333                     emitcode("mov", "a,b");
7334                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7335                 }
7336               else if (AOP_TYPE(left)==AOP_ACC)
7337                 {
7338                   if (!offset)
7339                     {
7340                       bool pushedB = pushB ();
7341                       emitcode("mov", "b,a");
7342                       MOVA (aopGet (right, offset, FALSE, FALSE));
7343                       emitcode("orl", "a,b");
7344                       popB (pushedB);
7345                     }
7346                   else
7347                     {
7348                       MOVA (aopGet (right, offset, FALSE, FALSE));
7349                       emitcode("orl", "a,b");
7350                     }
7351                 }
7352               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7353                 {
7354                   MOVB (aopGet (left, offset, FALSE, FALSE));
7355                   MOVA (aopGet (right, offset, FALSE, FALSE));
7356                   emitcode ("orl", "a,b");
7357                 }
7358               else if (aopGetUsesAcc (left, offset))
7359                 {
7360                   MOVA (aopGet (left, offset, FALSE, FALSE));
7361                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7362                 }
7363               else
7364                 {
7365                   MOVA (aopGet (right, offset, FALSE, FALSE));
7366                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7367                 }
7368               aopPut (result, "a", offset);
7369             }
7370         }
7371     }
7372
7373 release:
7374   freeAsmop (result, NULL, ic, TRUE);
7375   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7376   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7377 }
7378
7379 /*-----------------------------------------------------------------*/
7380 /* genXor - code for xclusive or                                   */
7381 /*-----------------------------------------------------------------*/
7382 static void
7383 genXor (iCode * ic, iCode * ifx)
7384 {
7385   operand *left, *right, *result;
7386   int size, offset = 0;
7387   unsigned long lit = 0L;
7388   int bytelit = 0;
7389
7390   D (emitcode (";", "genXor"));
7391
7392   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7393   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7394   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7395
7396 #ifdef DEBUG_TYPE
7397   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7398             AOP_TYPE (result),
7399             AOP_TYPE (left), AOP_TYPE (right));
7400   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7401             AOP_SIZE (result),
7402             AOP_SIZE (left), AOP_SIZE (right));
7403 #endif
7404
7405   /* if left is a literal & right is not ||
7406      if left needs acc & right does not */
7407   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7408       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7409     {
7410       operand *tmp = right;
7411       right = left;
7412       left = tmp;
7413     }
7414
7415   /* if result = right then exchange them */
7416   if (sameRegs (AOP (result), AOP (right)))
7417     {
7418       operand *tmp = right;
7419       right = left;
7420       left = tmp;
7421     }
7422
7423   /* if right is bit then exchange them */
7424   if (AOP_TYPE (right) == AOP_CRY &&
7425       AOP_TYPE (left) != AOP_CRY)
7426     {
7427       operand *tmp = right;
7428       right = left;
7429       left = tmp;
7430     }
7431
7432   if (AOP_TYPE (right) == AOP_LIT)
7433     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7434
7435   size = AOP_SIZE (result);
7436
7437   // if(bit ^ yy)
7438   // xx = bit ^ yy;
7439   if (AOP_TYPE (left) == AOP_CRY)
7440     {
7441       if (AOP_TYPE (right) == AOP_LIT)
7442         {
7443           // c = bit & literal;
7444           if (lit >> 1)
7445             {
7446               // lit>>1  != 0 => result = 1
7447               if (AOP_TYPE (result) == AOP_CRY)
7448                 {
7449                   if (size)
7450                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7451                   else if (ifx)
7452                     continueIfTrue (ifx);
7453                   goto release;
7454                 }
7455               emitcode ("setb", "c");
7456             }
7457           else
7458             {
7459               // lit == (0 or 1)
7460               if (lit == 0)
7461                 {
7462                   // lit == 0, result = left
7463                   if (size && sameRegs (AOP (result), AOP (left)))
7464                     goto release;
7465                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7466                 }
7467               else
7468                 {
7469                   // lit == 1, result = not(left)
7470                   if (size && sameRegs (AOP (result), AOP (left)))
7471                     {
7472                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7473                       goto release;
7474                     }
7475                   else
7476                     {
7477                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7478                       emitcode ("cpl", "c");
7479                     }
7480                 }
7481             }
7482         }
7483       else
7484         {
7485           // right != literal
7486           symbol *tlbl = newiTempLabel (NULL);
7487           if (AOP_TYPE (right) == AOP_CRY)
7488             {
7489               // c = bit ^ bit;
7490               if (IS_OP_ACCUSE (left))
7491                 {// left already is in the carry
7492                   operand *tmp = right;
7493                   right = left;
7494                   left = tmp;
7495                 }
7496               else
7497                 {
7498                   toCarry (right);
7499                 }
7500             }
7501           else
7502             {
7503               // c = bit ^ val
7504               toCarry (right);
7505             }
7506           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7507           emitcode ("cpl", "c");
7508           emitLabel (tlbl);
7509         }
7510       // bit = c
7511       // val = c
7512       if (size)
7513         outBitC (result);
7514       // if(bit ^ ...)
7515       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7516         genIfxJump (ifx, "c", left, right, result);
7517       goto release;
7518     }
7519
7520   /* if left is same as result */
7521   if (sameRegs (AOP (result), AOP (left)))
7522     {
7523       for (; size--; offset++)
7524         {
7525           if (AOP_TYPE (right) == AOP_LIT)
7526             {
7527               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7528               if (bytelit == 0)
7529                 {
7530                   /* dummy read of volatile operand */
7531                   if (isOperandVolatile (left, FALSE))
7532                     MOVA (aopGet (left, offset, FALSE, FALSE));
7533                   else
7534                     continue;
7535                 }
7536               else if (IS_AOP_PREG (left))
7537                 {
7538                   MOVA (aopGet (left, offset, FALSE, TRUE));
7539                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7540                   aopPut (result, "a", offset);
7541                 }
7542               else
7543                 {
7544                   emitcode ("xrl", "%s,%s",
7545                             aopGet (left, offset, FALSE, TRUE),
7546                             aopGet (right, offset, FALSE, FALSE));
7547                 }
7548             }
7549           else
7550             {
7551               if (AOP_TYPE (left) == AOP_ACC)
7552                 {
7553                   if (offset)
7554                     emitcode("mov", "a,b");
7555                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7556                 }
7557               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7558                 {
7559                   MOVB (aopGet (left, offset, FALSE, FALSE));
7560                   MOVA (aopGet (right, offset, FALSE, FALSE));
7561                   emitcode ("xrl", "a,b");
7562                   aopPut (result, "a", offset);
7563                 }
7564               else if (aopGetUsesAcc (left, offset))
7565                 {
7566                   MOVA (aopGet (left, offset, FALSE, FALSE));
7567                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7568                   aopPut (result, "a", offset);
7569                 }
7570               else
7571                 {
7572                   MOVA (aopGet (right, offset, FALSE, FALSE));
7573                   if (IS_AOP_PREG (left))
7574                     {
7575                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7576                       aopPut (result, "a", offset);
7577                     }
7578                   else
7579                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7580                 }
7581             }
7582         }
7583     }
7584   else
7585     {
7586       // left & result in different registers
7587       if (AOP_TYPE (result) == AOP_CRY)
7588         {
7589           // result = bit
7590           // if(size), result in bit
7591           // if(!size && ifx), conditional oper: if(left ^ right)
7592           symbol *tlbl = newiTempLabel (NULL);
7593           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7594
7595           if (size)
7596             emitcode ("setb", "c");
7597           while (sizer--)
7598             {
7599               if ((AOP_TYPE (right) == AOP_LIT) &&
7600                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7601                 {
7602                   MOVA (aopGet (left, offset, FALSE, FALSE));
7603                 }
7604               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7605                   && AOP_TYPE(left)==AOP_ACC)
7606                 {
7607                   if (offset)
7608                     emitcode("mov", "a,b");
7609                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7610                 }
7611               else if (AOP_TYPE(left)==AOP_ACC)
7612                 {
7613                   if (!offset)
7614                     {
7615                       bool pushedB = pushB ();
7616                       emitcode("mov", "b,a");
7617                       MOVA (aopGet (right, offset, FALSE, FALSE));
7618                       emitcode("xrl", "a,b");
7619                       popB (pushedB);
7620                     }
7621                   else
7622                     {
7623                       MOVA (aopGet (right, offset, FALSE, FALSE));
7624                       emitcode("xrl", "a,b");
7625                     }
7626                 }
7627               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7628                 {
7629                   MOVB (aopGet (left, offset, FALSE, FALSE));
7630                   MOVA (aopGet (right, offset, FALSE, FALSE));
7631                   emitcode ("xrl", "a,b");
7632                 }
7633               else if (aopGetUsesAcc (left, offset))
7634                 {
7635                   MOVA (aopGet (left, offset, FALSE, FALSE));
7636                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7637                 }
7638               else
7639                 {
7640                   MOVA (aopGet (right, offset, FALSE, FALSE));
7641                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7642                 }
7643
7644               emitcode ("jnz", "%05d$", tlbl->key + 100);
7645               offset++;
7646             }
7647           if (size)
7648             {
7649               CLRC;
7650               emitLabel (tlbl);
7651               outBitC (result);
7652             }
7653           else if (ifx)
7654             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7655         }
7656       else
7657         {
7658           for (; (size--); offset++)
7659             {
7660               // normal case
7661               // result = left ^ right
7662               if (AOP_TYPE (right) == AOP_LIT)
7663                 {
7664                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7665                   if (bytelit == 0)
7666                     {
7667                       aopPut (result,
7668                               aopGet (left, offset, FALSE, FALSE),
7669                               offset);
7670                       continue;
7671                     }
7672                 }
7673               // faster than result <- left, xrl result,right
7674               // and better if result is SFR
7675               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7676                   && AOP_TYPE(left)==AOP_ACC)
7677                 {
7678                   if (offset)
7679                     emitcode("mov", "a,b");
7680                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7681                 }
7682               else if (AOP_TYPE(left)==AOP_ACC)
7683                 {
7684                   if (!offset)
7685                     {
7686                       bool pushedB = pushB ();
7687                       emitcode("mov", "b,a");
7688                       MOVA (aopGet (right, offset, FALSE, FALSE));
7689                       emitcode("xrl", "a,b");
7690                       popB (pushedB);
7691                     }
7692                   else
7693                     {
7694                       MOVA (aopGet (right, offset, FALSE, FALSE));
7695                       emitcode("xrl", "a,b");
7696                     }
7697                 }
7698               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7699                 {
7700                   MOVB (aopGet (left, offset, FALSE, FALSE));
7701                   MOVA (aopGet (right, offset, FALSE, FALSE));
7702                   emitcode ("xrl", "a,b");
7703                 }
7704               else if (aopGetUsesAcc (left, offset))
7705                 {
7706                   MOVA (aopGet (left, offset, FALSE, FALSE));
7707                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7708                 }
7709               else
7710                 {
7711                   MOVA (aopGet (right, offset, FALSE, FALSE));
7712                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7713                 }
7714               aopPut (result, "a", offset);
7715             }
7716         }
7717     }
7718
7719 release:
7720   freeAsmop (result, NULL, ic, TRUE);
7721   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7722   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7723 }
7724
7725 /*-----------------------------------------------------------------*/
7726 /* genInline - write the inline code out                           */
7727 /*-----------------------------------------------------------------*/
7728 static void
7729 genInline (iCode * ic)
7730 {
7731   char *buffer, *bp, *bp1;
7732   bool inComment = FALSE;
7733
7734   D (emitcode (";", "genInline"));
7735
7736   _G.inLine += (!options.asmpeep);
7737
7738   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7739
7740   /* emit each line as a code */
7741   while (*bp)
7742     {
7743       switch (*bp)
7744         {
7745         case ';':
7746           inComment = TRUE;
7747           ++bp;
7748           break;
7749
7750         case '\n':
7751           inComment = FALSE;
7752           *bp++ = '\0';
7753           emitcode (bp1, "");
7754           bp1 = bp;
7755           break;
7756
7757         default:
7758           /* Add \n for labels, not dirs such as c:\mydir */
7759           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7760             {
7761               ++bp;
7762               *bp = '\0';
7763               ++bp;
7764               emitcode (bp1, "");
7765               bp1 = bp;
7766             }
7767           else
7768             ++bp;
7769           break;
7770         }
7771     }
7772   if (bp1 != bp)
7773     emitcode (bp1, "");
7774
7775   Safe_free (buffer);
7776
7777   _G.inLine -= (!options.asmpeep);
7778 }
7779
7780 /*-----------------------------------------------------------------*/
7781 /* genRRC - rotate right with carry                                */
7782 /*-----------------------------------------------------------------*/
7783 static void
7784 genRRC (iCode * ic)
7785 {
7786   operand *left, *result;
7787   int size, offset;
7788   char *l;
7789
7790   D (emitcode (";", "genRRC"));
7791
7792   /* rotate right with carry */
7793   left = IC_LEFT (ic);
7794   result = IC_RESULT (ic);
7795   aopOp (left, ic, FALSE);
7796   aopOp (result, ic, FALSE);
7797
7798   /* move it to the result */
7799   size = AOP_SIZE (result);
7800   offset = size - 1;
7801   if (size == 1) { /* special case for 1 byte */
7802       l = aopGet (left, offset, FALSE, FALSE);
7803       MOVA (l);
7804       emitcode ("rr", "a");
7805       goto release;
7806   }
7807   /* no need to clear carry, bit7 will be written later */
7808   while (size--)
7809     {
7810       l = aopGet (left, offset, FALSE, FALSE);
7811       MOVA (l);
7812       emitcode ("rrc", "a");
7813       if (AOP_SIZE (result) > 1)
7814         aopPut (result, "a", offset--);
7815     }
7816   /* now we need to put the carry into the
7817      highest order byte of the result */
7818   if (AOP_SIZE (result) > 1)
7819     {
7820       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7821       MOVA (l);
7822     }
7823   emitcode ("mov", "acc.7,c");
7824  release:
7825   aopPut (result, "a", AOP_SIZE (result) - 1);
7826   freeAsmop (result, NULL, ic, TRUE);
7827   freeAsmop (left, NULL, ic, TRUE);
7828 }
7829
7830 /*-----------------------------------------------------------------*/
7831 /* genRLC - generate code for rotate left with carry               */
7832 /*-----------------------------------------------------------------*/
7833 static void
7834 genRLC (iCode * ic)
7835 {
7836   operand *left, *result;
7837   int size, offset;
7838   char *l;
7839
7840   D (emitcode (";", "genRLC"));
7841
7842   /* rotate right with carry */
7843   left = IC_LEFT (ic);
7844   result = IC_RESULT (ic);
7845   aopOp (left, ic, FALSE);
7846   aopOp (result, ic, FALSE);
7847
7848   /* move it to the result */
7849   size = AOP_SIZE (result);
7850   offset = 0;
7851   if (size--)
7852     {
7853       l = aopGet (left, offset, FALSE, FALSE);
7854       MOVA (l);
7855       if (size == 0) { /* special case for 1 byte */
7856               emitcode("rl","a");
7857               goto release;
7858       }
7859       emitcode("rlc","a"); /* bit0 will be written later */
7860       if (AOP_SIZE (result) > 1)
7861         {
7862           aopPut (result, "a", offset++);
7863         }
7864
7865       while (size--)
7866         {
7867           l = aopGet (left, offset, FALSE, FALSE);
7868           MOVA (l);
7869           emitcode ("rlc", "a");
7870           if (AOP_SIZE (result) > 1)
7871             aopPut (result, "a", offset++);
7872         }
7873     }
7874   /* now we need to put the carry into the
7875      highest order byte of the result */
7876   if (AOP_SIZE (result) > 1)
7877     {
7878       l = aopGet (result, 0, FALSE, FALSE);
7879       MOVA (l);
7880     }
7881   emitcode ("mov", "acc.0,c");
7882  release:
7883   aopPut (result, "a", 0);
7884   freeAsmop (result, NULL, ic, TRUE);
7885   freeAsmop (left, NULL, ic, TRUE);
7886 }
7887
7888 /*-----------------------------------------------------------------*/
7889 /* genGetHbit - generates code get highest order bit               */
7890 /*-----------------------------------------------------------------*/
7891 static void
7892 genGetHbit (iCode * ic)
7893 {
7894   operand *left, *result;
7895
7896   D (emitcode (";", "genGetHbit"));
7897
7898   left = IC_LEFT (ic);
7899   result = IC_RESULT (ic);
7900   aopOp (left, ic, FALSE);
7901   aopOp (result, ic, FALSE);
7902
7903   /* get the highest order byte into a */
7904   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7905   if (AOP_TYPE (result) == AOP_CRY)
7906     {
7907       emitcode ("rlc", "a");
7908       outBitC (result);
7909     }
7910   else
7911     {
7912       emitcode ("rl", "a");
7913       emitcode ("anl", "a,#0x01");
7914       outAcc (result);
7915     }
7916
7917   freeAsmop (result, NULL, ic, TRUE);
7918   freeAsmop (left, NULL, ic, TRUE);
7919 }
7920
7921 /*-----------------------------------------------------------------*/
7922 /* genGetAbit - generates code get a single bit                    */
7923 /*-----------------------------------------------------------------*/
7924 static void
7925 genGetAbit (iCode * ic)
7926 {
7927   operand *left, *right, *result;
7928   int shCount;
7929
7930   D (emitcode (";", "genGetAbit"));
7931
7932   left = IC_LEFT (ic);
7933   right = IC_RIGHT (ic);
7934   result = IC_RESULT (ic);
7935   aopOp (left, ic, FALSE);
7936   aopOp (right, ic, FALSE);
7937   aopOp (result, ic, FALSE);
7938
7939   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7940
7941   /* get the needed byte into a */
7942   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7943   shCount %= 8;
7944   if (AOP_TYPE (result) == AOP_CRY)
7945     {
7946       if ((shCount) == 7)
7947           emitcode ("rlc", "a");
7948       else if ((shCount) == 0)
7949           emitcode ("rrc", "a");
7950       else
7951           emitcode ("mov", "c,acc[%d]", shCount);
7952       outBitC (result);
7953     }
7954   else
7955     {
7956       switch (shCount)
7957         {
7958         case 2:
7959           emitcode ("rr", "a");
7960           //fallthrough
7961         case 1:
7962           emitcode ("rr", "a");
7963           //fallthrough
7964         case 0:
7965           emitcode ("anl", "a,#0x01");
7966           break;
7967         case 3:
7968         case 5:
7969           emitcode ("mov", "c,acc[%d]", shCount);
7970           emitcode ("clr", "a");
7971           emitcode ("rlc", "a");
7972           break;
7973         case 4:
7974           emitcode ("swap", "a");
7975           emitcode ("anl", "a,#0x01");
7976           break;
7977         case 6:
7978           emitcode ("rl", "a");
7979           //fallthrough
7980         case 7:
7981           emitcode ("rl", "a");
7982           emitcode ("anl", "a,#0x01");
7983           break;
7984         }
7985       outAcc (result);
7986     }
7987
7988   freeAsmop (result, NULL, ic, TRUE);
7989   freeAsmop (right, NULL, ic, TRUE);
7990   freeAsmop (left, NULL, ic, TRUE);
7991 }
7992
7993 /*-----------------------------------------------------------------*/
7994 /* genGetByte - generates code get a single byte                   */
7995 /*-----------------------------------------------------------------*/
7996 static void
7997 genGetByte (iCode * ic)
7998 {
7999   operand *left, *right, *result;
8000   int offset;
8001
8002   D (emitcode (";", "genGetByte"));
8003
8004   left = IC_LEFT (ic);
8005   right = IC_RIGHT (ic);
8006   result = IC_RESULT (ic);
8007   aopOp (left, ic, FALSE);
8008   aopOp (right, ic, FALSE);
8009   aopOp (result, ic, FALSE);
8010
8011   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8012   aopPut (result,
8013           aopGet (left, offset, FALSE, FALSE),
8014           0);
8015
8016   freeAsmop (result, NULL, ic, TRUE);
8017   freeAsmop (right, NULL, ic, TRUE);
8018   freeAsmop (left, NULL, ic, TRUE);
8019 }
8020
8021 /*-----------------------------------------------------------------*/
8022 /* genGetWord - generates code get two bytes                       */
8023 /*-----------------------------------------------------------------*/
8024 static void
8025 genGetWord (iCode * ic)
8026 {
8027   operand *left, *right, *result;
8028   int offset;
8029
8030   D (emitcode (";", "genGetWord"));
8031
8032   left = IC_LEFT (ic);
8033   right = IC_RIGHT (ic);
8034   result = IC_RESULT (ic);
8035   aopOp (left, ic, FALSE);
8036   aopOp (right, ic, FALSE);
8037   aopOp (result, ic, FALSE);
8038
8039   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8040   aopPut (result,
8041           aopGet (left, offset, FALSE, FALSE),
8042           0);
8043   aopPut (result,
8044           aopGet (left, offset+1, FALSE, FALSE),
8045           1);
8046
8047   freeAsmop (result, NULL, ic, TRUE);
8048   freeAsmop (right, NULL, ic, TRUE);
8049   freeAsmop (left, NULL, ic, TRUE);
8050 }
8051
8052 /*-----------------------------------------------------------------*/
8053 /* genSwap - generates code to swap nibbles or bytes               */
8054 /*-----------------------------------------------------------------*/
8055 static void
8056 genSwap (iCode * ic)
8057 {
8058   operand *left, *result;
8059
8060   D(emitcode (";", "genSwap"));
8061
8062   left = IC_LEFT (ic);
8063   result = IC_RESULT (ic);
8064   aopOp (left, ic, FALSE);
8065   aopOp (result, ic, FALSE);
8066
8067   switch (AOP_SIZE (left))
8068     {
8069     case 1: /* swap nibbles in byte */
8070       MOVA (aopGet (left, 0, FALSE, FALSE));
8071       emitcode ("swap", "a");
8072       aopPut (result, "a", 0);
8073       break;
8074     case 2: /* swap bytes in word */
8075       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8076         {
8077           MOVA (aopGet (left, 0, FALSE, FALSE));
8078           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8079           aopPut (result, "a", 1);
8080         }
8081       else if (operandsEqu (left, result))
8082         {
8083           char * reg = "a";
8084           bool pushedB = FALSE, leftInB = FALSE;
8085
8086           MOVA (aopGet (left, 0, FALSE, FALSE));
8087           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8088             {
8089               pushedB = pushB ();
8090               emitcode ("mov", "b,a");
8091               reg = "b";
8092               leftInB = TRUE;
8093             }
8094           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8095           aopPut (result, reg, 1);
8096
8097           if (leftInB)
8098             popB (pushedB);
8099         }
8100       else
8101         {
8102           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8103           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8104         }
8105       break;
8106     default:
8107       wassertl(FALSE, "unsupported SWAP operand size");
8108     }
8109
8110   freeAsmop (result, NULL, ic, TRUE);
8111   freeAsmop (left, NULL, ic, TRUE);
8112 }
8113
8114 /*-----------------------------------------------------------------*/
8115 /* AccRol - rotate left accumulator by known count                 */
8116 /*-----------------------------------------------------------------*/
8117 static void
8118 AccRol (int shCount)
8119 {
8120   shCount &= 0x0007;            // shCount : 0..7
8121
8122   switch (shCount)
8123     {
8124     case 0:
8125       break;
8126     case 1:
8127       emitcode ("rl", "a");
8128       break;
8129     case 2:
8130       emitcode ("rl", "a");
8131       emitcode ("rl", "a");
8132       break;
8133     case 3:
8134       emitcode ("swap", "a");
8135       emitcode ("rr", "a");
8136       break;
8137     case 4:
8138       emitcode ("swap", "a");
8139       break;
8140     case 5:
8141       emitcode ("swap", "a");
8142       emitcode ("rl", "a");
8143       break;
8144     case 6:
8145       emitcode ("rr", "a");
8146       emitcode ("rr", "a");
8147       break;
8148     case 7:
8149       emitcode ("rr", "a");
8150       break;
8151     }
8152 }
8153
8154 /*-----------------------------------------------------------------*/
8155 /* AccLsh - left shift accumulator by known count                  */
8156 /*-----------------------------------------------------------------*/
8157 static void
8158 AccLsh (int shCount)
8159 {
8160   if (shCount != 0)
8161     {
8162       if (shCount == 1)
8163         emitcode ("add", "a,acc");
8164       else if (shCount == 2)
8165         {
8166           emitcode ("add", "a,acc");
8167           emitcode ("add", "a,acc");
8168         }
8169       else
8170         {
8171           /* rotate left accumulator */
8172           AccRol (shCount);
8173           /* and kill the lower order bits */
8174           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8175         }
8176     }
8177 }
8178
8179 /*-----------------------------------------------------------------*/
8180 /* AccRsh - right shift accumulator by known count                 */
8181 /*-----------------------------------------------------------------*/
8182 static void
8183 AccRsh (int shCount)
8184 {
8185   if (shCount != 0)
8186     {
8187       if (shCount == 1)
8188         {
8189           CLRC;
8190           emitcode ("rrc", "a");
8191         }
8192       else
8193         {
8194           /* rotate right accumulator */
8195           AccRol (8 - shCount);
8196           /* and kill the higher order bits */
8197           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8198         }
8199     }
8200 }
8201
8202 /*-----------------------------------------------------------------*/
8203 /* AccSRsh - signed right shift accumulator by known count                 */
8204 /*-----------------------------------------------------------------*/
8205 static void
8206 AccSRsh (int shCount)
8207 {
8208   symbol *tlbl;
8209   if (shCount != 0)
8210     {
8211       if (shCount == 1)
8212         {
8213           emitcode ("mov", "c,acc.7");
8214           emitcode ("rrc", "a");
8215         }
8216       else if (shCount == 2)
8217         {
8218           emitcode ("mov", "c,acc.7");
8219           emitcode ("rrc", "a");
8220           emitcode ("mov", "c,acc.7");
8221           emitcode ("rrc", "a");
8222         }
8223       else
8224         {
8225           tlbl = newiTempLabel (NULL);
8226           /* rotate right accumulator */
8227           AccRol (8 - shCount);
8228           /* and kill the higher order bits */
8229           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8230           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8231           emitcode ("orl", "a,#0x%02x",
8232                     (unsigned char) ~SRMask[shCount]);
8233           emitLabel (tlbl);
8234         }
8235     }
8236 }
8237
8238 /*-----------------------------------------------------------------*/
8239 /* shiftR1Left2Result - shift right one byte from left to result   */
8240 /*-----------------------------------------------------------------*/
8241 static void
8242 shiftR1Left2Result (operand * left, int offl,
8243                     operand * result, int offr,
8244                     int shCount, int sign)
8245 {
8246   MOVA (aopGet (left, offl, FALSE, FALSE));
8247   /* shift right accumulator */
8248   if (sign)
8249     AccSRsh (shCount);
8250   else
8251     AccRsh (shCount);
8252   aopPut (result, "a", offr);
8253 }
8254
8255 /*-----------------------------------------------------------------*/
8256 /* shiftL1Left2Result - shift left one byte from left to result    */
8257 /*-----------------------------------------------------------------*/
8258 static void
8259 shiftL1Left2Result (operand * left, int offl,
8260                     operand * result, int offr, int shCount)
8261 {
8262   char *l;
8263   l = aopGet (left, offl, FALSE, FALSE);
8264   MOVA (l);
8265   /* shift left accumulator */
8266   AccLsh (shCount);
8267   aopPut (result, "a", offr);
8268 }
8269
8270 /*-----------------------------------------------------------------*/
8271 /* movLeft2Result - move byte from left to result                  */
8272 /*-----------------------------------------------------------------*/
8273 static void
8274 movLeft2Result (operand * left, int offl,
8275                 operand * result, int offr, int sign)
8276 {
8277   char *l;
8278   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8279     {
8280       l = aopGet (left, offl, FALSE, FALSE);
8281
8282       if (*l == '@' && (IS_AOP_PREG (result)))
8283         {
8284           emitcode ("mov", "a,%s", l);
8285           aopPut (result, "a", offr);
8286         }
8287       else
8288         {
8289           if (!sign)
8290             {
8291               aopPut (result, l, offr);
8292             }
8293           else
8294             {
8295               /* MSB sign in acc.7 ! */
8296               if (getDataSize (left) == offl + 1)
8297                 {
8298                   MOVA (l);
8299                   aopPut (result, "a", offr);
8300                 }
8301             }
8302         }
8303     }
8304 }
8305
8306 /*-----------------------------------------------------------------*/
8307 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8308 /*-----------------------------------------------------------------*/
8309 static void
8310 AccAXRrl1 (char *x)
8311 {
8312   emitcode ("rrc", "a");
8313   emitcode ("xch", "a,%s", x);
8314   emitcode ("rrc", "a");
8315   emitcode ("xch", "a,%s", x);
8316 }
8317
8318 /*-----------------------------------------------------------------*/
8319 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8320 /*-----------------------------------------------------------------*/
8321 static void
8322 AccAXLrl1 (char *x)
8323 {
8324   emitcode ("xch", "a,%s", x);
8325   emitcode ("rlc", "a");
8326   emitcode ("xch", "a,%s", x);
8327   emitcode ("rlc", "a");
8328 }
8329
8330 /*-----------------------------------------------------------------*/
8331 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8332 /*-----------------------------------------------------------------*/
8333 static void
8334 AccAXLsh1 (char *x)
8335 {
8336   emitcode ("xch", "a,%s", x);
8337   emitcode ("add", "a,acc");
8338   emitcode ("xch", "a,%s", x);
8339   emitcode ("rlc", "a");
8340 }
8341
8342 /*-----------------------------------------------------------------*/
8343 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8344 /*-----------------------------------------------------------------*/
8345 static void
8346 AccAXLsh (char *x, int shCount)
8347 {
8348   switch (shCount)
8349     {
8350     case 0:
8351       break;
8352     case 1:
8353       AccAXLsh1 (x);
8354       break;
8355     case 2:
8356       AccAXLsh1 (x);
8357       AccAXLsh1 (x);
8358       break;
8359     case 3:
8360     case 4:
8361     case 5:                     // AAAAABBB:CCCCCDDD
8362
8363       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8364
8365       emitcode ("anl", "a,#0x%02x",
8366                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8367
8368       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8369
8370       AccRol (shCount);         // DDDCCCCC:BBB00000
8371
8372       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8373
8374       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8375
8376       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8377
8378       emitcode ("anl", "a,#0x%02x",
8379                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8380
8381       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8382
8383       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8384
8385       break;
8386     case 6:                     // AAAAAABB:CCCCCCDD
8387       emitcode ("anl", "a,#0x%02x",
8388                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8389       emitcode ("mov", "c,acc.0");      // c = B
8390       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8391 #if 0 // REMOVE ME
8392       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8393       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8394 #else
8395       emitcode("rrc","a");
8396       emitcode("xch","a,%s", x);
8397       emitcode("rrc","a");
8398       emitcode("mov","c,acc.0"); //<< get correct bit
8399       emitcode("xch","a,%s", x);
8400
8401       emitcode("rrc","a");
8402       emitcode("xch","a,%s", x);
8403       emitcode("rrc","a");
8404       emitcode("xch","a,%s", x);
8405 #endif
8406       break;
8407     case 7:                     // a:x <<= 7
8408
8409       emitcode ("anl", "a,#0x%02x",
8410                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8411
8412       emitcode ("mov", "c,acc.0");      // c = B
8413
8414       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8415
8416       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8417
8418       break;
8419     default:
8420       break;
8421     }
8422 }
8423
8424 /*-----------------------------------------------------------------*/
8425 /* AccAXRsh - right shift a:x known count (0..7)                   */
8426 /*-----------------------------------------------------------------*/
8427 static void
8428 AccAXRsh (char *x, int shCount)
8429 {
8430   switch (shCount)
8431     {
8432     case 0:
8433       break;
8434     case 1:
8435       CLRC;
8436       AccAXRrl1 (x);            // 0->a:x
8437
8438       break;
8439     case 2:
8440       CLRC;
8441       AccAXRrl1 (x);            // 0->a:x
8442
8443       CLRC;
8444       AccAXRrl1 (x);            // 0->a:x
8445
8446       break;
8447     case 3:
8448     case 4:
8449     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8450
8451       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8452
8453       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8454
8455       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8456
8457       emitcode ("anl", "a,#0x%02x",
8458                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8459
8460       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8461
8462       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8463
8464       emitcode ("anl", "a,#0x%02x",
8465                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8466
8467       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8468
8469       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8470
8471       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8472
8473       break;
8474     case 6:                     // AABBBBBB:CCDDDDDD
8475
8476       emitcode ("mov", "c,acc.7");
8477       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8478
8479       emitcode ("mov", "c,acc.7");
8480       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8481
8482       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8483
8484       emitcode ("anl", "a,#0x%02x",
8485                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8486
8487       break;
8488     case 7:                     // ABBBBBBB:CDDDDDDD
8489
8490       emitcode ("mov", "c,acc.7");      // c = A
8491
8492       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8493
8494       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8495
8496       emitcode ("anl", "a,#0x%02x",
8497                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8498
8499       break;
8500     default:
8501       break;
8502     }
8503 }
8504
8505 /*-----------------------------------------------------------------*/
8506 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8507 /*-----------------------------------------------------------------*/
8508 static void
8509 AccAXRshS (char *x, int shCount)
8510 {
8511   symbol *tlbl;
8512   switch (shCount)
8513     {
8514     case 0:
8515       break;
8516     case 1:
8517       emitcode ("mov", "c,acc.7");
8518       AccAXRrl1 (x);            // s->a:x
8519
8520       break;
8521     case 2:
8522       emitcode ("mov", "c,acc.7");
8523       AccAXRrl1 (x);            // s->a:x
8524
8525       emitcode ("mov", "c,acc.7");
8526       AccAXRrl1 (x);            // s->a:x
8527
8528       break;
8529     case 3:
8530     case 4:
8531     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8532
8533       tlbl = newiTempLabel (NULL);
8534       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8535
8536       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8537
8538       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8539
8540       emitcode ("anl", "a,#0x%02x",
8541                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8542
8543       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8544
8545       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8546
8547       emitcode ("anl", "a,#0x%02x",
8548                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8549
8550       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8551
8552       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8553
8554       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8555
8556       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8557       emitcode ("orl", "a,#0x%02x",
8558                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8559
8560       emitLabel (tlbl);
8561       break;                    // SSSSAAAA:BBBCCCCC
8562
8563     case 6:                     // AABBBBBB:CCDDDDDD
8564
8565       tlbl = newiTempLabel (NULL);
8566       emitcode ("mov", "c,acc.7");
8567       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8568
8569       emitcode ("mov", "c,acc.7");
8570       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8571
8572       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8573
8574       emitcode ("anl", "a,#0x%02x",
8575                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8576
8577       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8578       emitcode ("orl", "a,#0x%02x",
8579                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8580
8581       emitLabel (tlbl);
8582       break;
8583     case 7:                     // ABBBBBBB:CDDDDDDD
8584
8585       tlbl = newiTempLabel (NULL);
8586       emitcode ("mov", "c,acc.7");      // c = A
8587
8588       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8589
8590       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8591
8592       emitcode ("anl", "a,#0x%02x",
8593                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8594
8595       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8596       emitcode ("orl", "a,#0x%02x",
8597                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8598
8599       emitLabel (tlbl);
8600       break;
8601     default:
8602       break;
8603     }
8604 }
8605
8606 /*-----------------------------------------------------------------*/
8607 /* shiftL2Left2Result - shift left two bytes from left to result   */
8608 /*-----------------------------------------------------------------*/
8609 static void
8610 shiftL2Left2Result (operand * left, int offl,
8611                     operand * result, int offr, int shCount)
8612 {
8613   char * x;
8614   bool pushedB = FALSE;
8615   bool usedB = FALSE;
8616
8617   if (sameRegs (AOP (result), AOP (left)) &&
8618       ((offl + MSB16) == offr))
8619     {
8620       /* don't crash result[offr] */
8621       MOVA (aopGet (left, offl, FALSE, FALSE));
8622       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8623       usedB = !strncmp(x, "b", 1);
8624     }
8625   else if (aopGetUsesAcc (result, offr))
8626     {
8627       movLeft2Result (left, offl, result, offr, 0);
8628       pushedB = pushB ();
8629       usedB = TRUE;
8630       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8631       MOVA (aopGet (result, offr, FALSE, FALSE));
8632       emitcode ("xch", "a,b");
8633       x = "b";
8634     }
8635   else
8636     {
8637       movLeft2Result (left, offl, result, offr, 0);
8638       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8639       x = aopGet (result, offr, FALSE, FALSE);
8640     }
8641   /* ax << shCount (x = lsb(result)) */
8642   AccAXLsh (x, shCount);
8643   if (usedB)
8644     {
8645       emitcode ("xch", "a,b");
8646       aopPut (result, "a", offr);
8647       aopPut (result, "b", offr + MSB16);
8648       popB (pushedB);
8649     }
8650   else
8651     {
8652       aopPut (result, "a", offr + MSB16);
8653     }
8654 }
8655
8656
8657 /*-----------------------------------------------------------------*/
8658 /* shiftR2Left2Result - shift right two bytes from left to result  */
8659 /*-----------------------------------------------------------------*/
8660 static void
8661 shiftR2Left2Result (operand * left, int offl,
8662                     operand * result, int offr,
8663                     int shCount, int sign)
8664 {
8665   char * x;
8666   bool pushedB = FALSE;
8667   bool usedB = FALSE;
8668
8669   if (sameRegs (AOP (result), AOP (left)) &&
8670       ((offl + MSB16) == offr))
8671     {
8672       /* don't crash result[offr] */
8673       MOVA (aopGet (left, offl, FALSE, FALSE));
8674       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8675       usedB = !strncmp(x, "b", 1);
8676     }
8677   else if (aopGetUsesAcc (result, offr))
8678     {
8679       movLeft2Result (left, offl, result, offr, 0);
8680       pushedB = pushB ();
8681       usedB = TRUE;
8682       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8683       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8684       x = "b";
8685     }
8686   else
8687     {
8688       movLeft2Result (left, offl, result, offr, 0);
8689       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8690       x = aopGet (result, offr, FALSE, FALSE);
8691     }
8692   /* a:x >> shCount (x = lsb(result)) */
8693   if (sign)
8694     AccAXRshS (x, shCount);
8695   else
8696     AccAXRsh (x, shCount);
8697   if (usedB)
8698     {
8699       emitcode ("xch", "a,b");
8700       aopPut (result, "a", offr);
8701       emitcode ("xch", "a,b");
8702       popB (pushedB);
8703     }
8704   if (getDataSize (result) > 1)
8705     aopPut (result, "a", offr + MSB16);
8706 }
8707
8708 /*-----------------------------------------------------------------*/
8709 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8710 /*-----------------------------------------------------------------*/
8711 static void
8712 shiftLLeftOrResult (operand * left, int offl,
8713                     operand * result, int offr, int shCount)
8714 {
8715   MOVA (aopGet (left, offl, FALSE, FALSE));
8716   /* shift left accumulator */
8717   AccLsh (shCount);
8718   /* or with result */
8719   if (aopGetUsesAcc (result, offr))
8720     {
8721       emitcode ("xch", "a,b");
8722       MOVA (aopGet (result, offr, FALSE, FALSE));
8723       emitcode ("orl", "a,b");
8724     }
8725   else
8726     {
8727       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8728     }
8729   /* back to result */
8730   aopPut (result, "a", offr);
8731 }
8732
8733 /*-----------------------------------------------------------------*/
8734 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8735 /*-----------------------------------------------------------------*/
8736 static void
8737 shiftRLeftOrResult (operand * left, int offl,
8738                     operand * result, int offr, int shCount)
8739 {
8740   MOVA (aopGet (left, offl, FALSE, FALSE));
8741   /* shift right accumulator */
8742   AccRsh (shCount);
8743   /* or with result */
8744   if (aopGetUsesAcc(result, offr))
8745     {
8746       emitcode ("xch", "a,b");
8747       MOVA (aopGet (result, offr, FALSE, FALSE));
8748       emitcode ("orl", "a,b");
8749     }
8750   else
8751     {
8752       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8753     }
8754   /* back to result */
8755   aopPut (result, "a", offr);
8756 }
8757
8758 /*-----------------------------------------------------------------*/
8759 /* genlshOne - left shift a one byte quantity by known count       */
8760 /*-----------------------------------------------------------------*/
8761 static void
8762 genlshOne (operand * result, operand * left, int shCount)
8763 {
8764   D (emitcode (";", "genlshOne"));
8765
8766   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8767 }
8768
8769 /*-----------------------------------------------------------------*/
8770 /* genlshTwo - left shift two bytes by known amount != 0           */
8771 /*-----------------------------------------------------------------*/
8772 static void
8773 genlshTwo (operand * result, operand * left, int shCount)
8774 {
8775   int size;
8776
8777   D (emitcode (";", "genlshTwo"));
8778
8779   size = getDataSize (result);
8780
8781   /* if shCount >= 8 */
8782   if (shCount >= 8)
8783     {
8784       shCount -= 8;
8785
8786       if (size > 1)
8787         {
8788           if (shCount)
8789             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8790           else
8791             movLeft2Result (left, LSB, result, MSB16, 0);
8792         }
8793       aopPut (result, zero, LSB);
8794     }
8795
8796   /*  1 <= shCount <= 7 */
8797   else
8798     {
8799       if (size == 1)
8800         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8801       else
8802         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8803     }
8804 }
8805
8806 /*-----------------------------------------------------------------*/
8807 /* shiftLLong - shift left one long from left to result            */
8808 /* offl = LSB or MSB16                                             */
8809 /*-----------------------------------------------------------------*/
8810 static void
8811 shiftLLong (operand * left, operand * result, int offr)
8812 {
8813   char *l;
8814   int size = AOP_SIZE (result);
8815
8816   if (size >= LSB + offr)
8817     {
8818       l = aopGet (left, LSB, FALSE, FALSE);
8819       MOVA (l);
8820       emitcode ("add", "a,acc");
8821       if (sameRegs (AOP (left), AOP (result)) &&
8822           size >= MSB16 + offr && offr != LSB)
8823         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8824       else
8825         aopPut (result, "a", LSB + offr);
8826     }
8827
8828   if (size >= MSB16 + offr)
8829     {
8830       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8831         {
8832           l = aopGet (left, MSB16, FALSE, FALSE);
8833           MOVA (l);
8834         }
8835       emitcode ("rlc", "a");
8836       if (sameRegs (AOP (left), AOP (result)) &&
8837           size >= MSB24 + offr && offr != LSB)
8838         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8839       else
8840         aopPut (result, "a", MSB16 + offr);
8841     }
8842
8843   if (size >= MSB24 + offr)
8844     {
8845       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8846         {
8847           l = aopGet (left, MSB24, FALSE, FALSE);
8848           MOVA (l);
8849         }
8850       emitcode ("rlc", "a");
8851       if (sameRegs (AOP (left), AOP (result)) &&
8852           size >= MSB32 + offr && offr != LSB)
8853         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8854       else
8855         aopPut (result, "a", MSB24 + offr);
8856     }
8857
8858   if (size > MSB32 + offr)
8859     {
8860       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8861         {
8862           l = aopGet (left, MSB32, FALSE, FALSE);
8863           MOVA (l);
8864         }
8865       emitcode ("rlc", "a");
8866       aopPut (result, "a", MSB32 + offr);
8867     }
8868   if (offr != LSB)
8869     aopPut (result, zero, LSB);
8870 }
8871
8872 /*-----------------------------------------------------------------*/
8873 /* genlshFour - shift four byte by a known amount != 0             */
8874 /*-----------------------------------------------------------------*/
8875 static void
8876 genlshFour (operand * result, operand * left, int shCount)
8877 {
8878   int size;
8879
8880   D (emitcode (";", "genlshFour"));
8881
8882   size = AOP_SIZE (result);
8883
8884   /* if shifting more that 3 bytes */
8885   if (shCount >= 24)
8886     {
8887       shCount -= 24;
8888       if (shCount)
8889         /* lowest order of left goes to the highest
8890            order of the destination */
8891         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8892       else
8893         movLeft2Result (left, LSB, result, MSB32, 0);
8894       aopPut (result, zero, LSB);
8895       aopPut (result, zero, MSB16);
8896       aopPut (result, zero, MSB24);
8897       return;
8898     }
8899
8900   /* more than two bytes */
8901   else if (shCount >= 16)
8902     {
8903       /* lower order two bytes goes to higher order two bytes */
8904       shCount -= 16;
8905       /* if some more remaining */
8906       if (shCount)
8907         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8908       else
8909         {
8910           movLeft2Result (left, MSB16, result, MSB32, 0);
8911           movLeft2Result (left, LSB, result, MSB24, 0);
8912         }
8913       aopPut (result, zero, MSB16);
8914       aopPut (result, zero, LSB);
8915       return;
8916     }
8917
8918   /* if more than 1 byte */
8919   else if (shCount >= 8)
8920     {
8921       /* lower order three bytes goes to higher order  three bytes */
8922       shCount -= 8;
8923       if (size == 2)
8924         {
8925           if (shCount)
8926             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8927           else
8928             movLeft2Result (left, LSB, result, MSB16, 0);
8929         }
8930       else
8931         {                       /* size = 4 */
8932           if (shCount == 0)
8933             {
8934               movLeft2Result (left, MSB24, result, MSB32, 0);
8935               movLeft2Result (left, MSB16, result, MSB24, 0);
8936               movLeft2Result (left, LSB, result, MSB16, 0);
8937               aopPut (result, zero, LSB);
8938             }
8939           else if (shCount == 1)
8940             shiftLLong (left, result, MSB16);
8941           else
8942             {
8943               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8944               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8945               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8946               aopPut (result, zero, LSB);
8947             }
8948         }
8949     }
8950
8951   /* 1 <= shCount <= 7 */
8952   else if (shCount <= 2)
8953     {
8954       shiftLLong (left, result, LSB);
8955       if (shCount == 2)
8956         shiftLLong (result, result, LSB);
8957     }
8958   /* 3 <= shCount <= 7, optimize */
8959   else
8960     {
8961       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8962       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8963       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8964     }
8965 }
8966
8967 /*-----------------------------------------------------------------*/
8968 /* genLeftShiftLiteral - left shifting by known count              */
8969 /*-----------------------------------------------------------------*/
8970 static void
8971 genLeftShiftLiteral (operand * left,
8972                      operand * right,
8973                      operand * result,
8974                      iCode * ic)
8975 {
8976   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
8977   int size;
8978
8979   D (emitcode (";", "genLeftShiftLiteral"));
8980
8981   freeAsmop (right, NULL, ic, TRUE);
8982
8983   aopOp (left, ic, FALSE);
8984   aopOp (result, ic, FALSE);
8985
8986   size = getSize (operandType (result));
8987
8988 #if VIEW_SIZE
8989   emitcode ("; shift left ", "result %d, left %d", size,
8990             AOP_SIZE (left));
8991 #endif
8992
8993   /* I suppose that the left size >= result size */
8994   if (shCount == 0)
8995     {
8996       while (size--)
8997         {
8998           movLeft2Result (left, size, result, size, 0);
8999         }
9000     }
9001   else if (shCount >= (size * 8))
9002     {
9003       while (size--)
9004         {
9005           aopPut (result, zero, size);
9006         }
9007     }
9008   else
9009     {
9010       switch (size)
9011         {
9012         case 1:
9013           genlshOne (result, left, shCount);
9014           break;
9015
9016         case 2:
9017           genlshTwo (result, left, shCount);
9018           break;
9019
9020         case 4:
9021           genlshFour (result, left, shCount);
9022           break;
9023         default:
9024           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9025                   "*** ack! mystery literal shift!\n");
9026           break;
9027         }
9028     }
9029   freeAsmop (result, NULL, ic, TRUE);
9030   freeAsmop (left, NULL, ic, TRUE);
9031 }
9032
9033 /*-----------------------------------------------------------------*/
9034 /* genLeftShift - generates code for left shifting                 */
9035 /*-----------------------------------------------------------------*/
9036 static void
9037 genLeftShift (iCode * ic)
9038 {
9039   operand *left, *right, *result;
9040   int size, offset;
9041   char *l;
9042   symbol *tlbl, *tlbl1;
9043   bool pushedB;
9044
9045   D (emitcode (";", "genLeftShift"));
9046
9047   right = IC_RIGHT (ic);
9048   left = IC_LEFT (ic);
9049   result = IC_RESULT (ic);
9050
9051   aopOp (right, ic, FALSE);
9052
9053   /* if the shift count is known then do it
9054      as efficiently as possible */
9055   if (AOP_TYPE (right) == AOP_LIT)
9056     {
9057       genLeftShiftLiteral (left, right, result, ic);
9058       return;
9059     }
9060
9061   /* shift count is unknown then we have to form
9062      a loop get the loop count in B : Note: we take
9063      only the lower order byte since shifting
9064      more that 32 bits make no sense anyway, ( the
9065      largest size of an object can be only 32 bits ) */
9066
9067   pushedB = pushB ();
9068   MOVB (aopGet (right, 0, FALSE, FALSE));
9069   emitcode ("inc", "b");
9070   freeAsmop (right, NULL, ic, TRUE);
9071   aopOp (left, ic, FALSE);
9072   aopOp (result, ic, FALSE);
9073
9074   /* now move the left to the result if they are not the same */
9075   if (!sameRegs (AOP (left), AOP (result)) &&
9076       AOP_SIZE (result) > 1)
9077     {
9078
9079       size = AOP_SIZE (result);
9080       offset = 0;
9081       while (size--)
9082         {
9083           l = aopGet (left, offset, FALSE, TRUE);
9084           if (*l == '@' && (IS_AOP_PREG (result)))
9085             {
9086
9087               emitcode ("mov", "a,%s", l);
9088               aopPut (result, "a", offset);
9089             }
9090           else
9091             aopPut (result, l, offset);
9092           offset++;
9093         }
9094     }
9095
9096   tlbl = newiTempLabel (NULL);
9097   size = AOP_SIZE (result);
9098   offset = 0;
9099   tlbl1 = newiTempLabel (NULL);
9100
9101   /* if it is only one byte then */
9102   if (size == 1)
9103     {
9104       symbol *tlbl1 = newiTempLabel (NULL);
9105
9106       l = aopGet (left, 0, FALSE, FALSE);
9107       MOVA (l);
9108       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9109       emitLabel (tlbl);
9110       emitcode ("add", "a,acc");
9111       emitLabel (tlbl1);
9112       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9113       popB (pushedB);
9114       aopPut (result, "a", 0);
9115       goto release;
9116     }
9117
9118   reAdjustPreg (AOP (result));
9119
9120   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9121   emitLabel (tlbl);
9122   l = aopGet (result, offset, FALSE, FALSE);
9123   MOVA (l);
9124   emitcode ("add", "a,acc");
9125   aopPut (result, "a", offset++);
9126   while (--size)
9127     {
9128       l = aopGet (result, offset, FALSE, FALSE);
9129       MOVA (l);
9130       emitcode ("rlc", "a");
9131       aopPut (result, "a", offset++);
9132     }
9133   reAdjustPreg (AOP (result));
9134
9135   emitLabel (tlbl1);
9136   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9137   popB (pushedB);
9138 release:
9139   freeAsmop (result, NULL, ic, TRUE);
9140   freeAsmop (left, NULL, ic, TRUE);
9141 }
9142
9143 /*-----------------------------------------------------------------*/
9144 /* genrshOne - right shift a one byte quantity by known count      */
9145 /*-----------------------------------------------------------------*/
9146 static void
9147 genrshOne (operand * result, operand * left,
9148            int shCount, int sign)
9149 {
9150   D (emitcode (";", "genrshOne"));
9151
9152   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9153 }
9154
9155 /*-----------------------------------------------------------------*/
9156 /* genrshTwo - right shift two bytes by known amount != 0          */
9157 /*-----------------------------------------------------------------*/
9158 static void
9159 genrshTwo (operand * result, operand * left,
9160            int shCount, int sign)
9161 {
9162   D (emitcode (";", "genrshTwo"));
9163
9164   /* if shCount >= 8 */
9165   if (shCount >= 8)
9166     {
9167       shCount -= 8;
9168       if (shCount)
9169         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9170       else
9171         movLeft2Result (left, MSB16, result, LSB, sign);
9172       addSign (result, MSB16, sign);
9173     }
9174
9175   /*  1 <= shCount <= 7 */
9176   else
9177     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9178 }
9179
9180 /*-----------------------------------------------------------------*/
9181 /* shiftRLong - shift right one long from left to result           */
9182 /* offl = LSB or MSB16                                             */
9183 /*-----------------------------------------------------------------*/
9184 static void
9185 shiftRLong (operand * left, int offl,
9186             operand * result, int sign)
9187 {
9188   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9189
9190   if (overlapping && offl>1)
9191     {
9192       // we are in big trouble, but this shouldn't happen
9193       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9194     }
9195
9196   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9197
9198   if (offl==MSB16)
9199     {
9200       // shift is > 8
9201       if (sign)
9202         {
9203           emitcode ("rlc", "a");
9204           emitcode ("subb", "a,acc");
9205           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9206             {
9207               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9208             }
9209           else
9210             {
9211               aopPut (result, "a", MSB32);
9212               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9213             }
9214         }
9215       else
9216         {
9217           if (aopPutUsesAcc (result, zero, MSB32))
9218             {
9219               emitcode("xch", "a,b");
9220               aopPut (result, zero, MSB32);
9221               emitcode("xch", "a,b");
9222             }
9223           else
9224             {
9225               aopPut (result, zero, MSB32);
9226             }
9227         }
9228     }
9229
9230   if (!sign)
9231     {
9232       emitcode ("clr", "c");
9233     }
9234   else
9235     {
9236       emitcode ("mov", "c,acc.7");
9237     }
9238
9239   emitcode ("rrc", "a");
9240
9241   if (overlapping && offl==MSB16 &&
9242       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9243     {
9244       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9245     }
9246   else
9247     {
9248       aopPut (result, "a", MSB32 - offl);
9249       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9250     }
9251
9252   emitcode ("rrc", "a");
9253   if (overlapping && offl==MSB16 &&
9254       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9255     {
9256       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9257     }
9258   else
9259     {
9260       aopPut (result, "a", MSB24 - offl);
9261       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9262     }
9263
9264   emitcode ("rrc", "a");
9265   if (offl != LSB)
9266     {
9267       aopPut (result, "a", MSB16 - offl);
9268     }
9269   else
9270     {
9271       if (overlapping &&
9272           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9273         {
9274           xch_a_aopGet (left, LSB, FALSE, FALSE);
9275         }
9276       else
9277         {
9278           aopPut (result, "a", MSB16 - offl);
9279           MOVA (aopGet (left, LSB, FALSE, FALSE));
9280         }
9281       emitcode ("rrc", "a");
9282       aopPut (result, "a", LSB);
9283     }
9284 }
9285
9286 /*-----------------------------------------------------------------*/
9287 /* genrshFour - shift four byte by a known amount != 0             */
9288 /*-----------------------------------------------------------------*/
9289 static void
9290 genrshFour (operand * result, operand * left,
9291             int shCount, int sign)
9292 {
9293   D (emitcode (";", "genrshFour"));
9294
9295   /* if shifting more that 3 bytes */
9296   if (shCount >= 24)
9297     {
9298       shCount -= 24;
9299       if (shCount)
9300         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9301       else
9302         movLeft2Result (left, MSB32, result, LSB, sign);
9303       addSign (result, MSB16, sign);
9304     }
9305   else if (shCount >= 16)
9306     {
9307       shCount -= 16;
9308       if (shCount)
9309         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9310       else
9311         {
9312           movLeft2Result (left, MSB24, result, LSB, 0);
9313           movLeft2Result (left, MSB32, result, MSB16, sign);
9314         }
9315       addSign (result, MSB24, sign);
9316     }
9317   else if (shCount >= 8)
9318     {
9319       shCount -= 8;
9320       if (shCount == 1)
9321         {
9322           shiftRLong (left, MSB16, result, sign);
9323         }
9324       else if (shCount == 0)
9325         {
9326           movLeft2Result (left, MSB16, result, LSB, 0);
9327           movLeft2Result (left, MSB24, result, MSB16, 0);
9328           movLeft2Result (left, MSB32, result, MSB24, sign);
9329           addSign (result, MSB32, sign);
9330         }
9331       else
9332         {
9333           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9334           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9335           /* the last shift is signed */
9336           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9337           addSign (result, MSB32, sign);
9338         }
9339     }
9340   else
9341     {
9342       /* 1 <= shCount <= 7 */
9343       if (shCount <= 2)
9344         {
9345           shiftRLong (left, LSB, result, sign);
9346           if (shCount == 2)
9347             shiftRLong (result, LSB, result, sign);
9348         }
9349       else
9350         {
9351           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9352           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9353           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9354         }
9355     }
9356 }
9357
9358 /*-----------------------------------------------------------------*/
9359 /* genRightShiftLiteral - right shifting by known count            */
9360 /*-----------------------------------------------------------------*/
9361 static void
9362 genRightShiftLiteral (operand * left,
9363                       operand * right,
9364                       operand * result,
9365                       iCode * ic,
9366                       int sign)
9367 {
9368   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9369   int size;
9370
9371   D (emitcode (";", "genRightShiftLiteral"));
9372
9373   freeAsmop (right, NULL, ic, TRUE);
9374
9375   aopOp (left, ic, FALSE);
9376   aopOp (result, ic, FALSE);
9377
9378 #if VIEW_SIZE
9379   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9380             AOP_SIZE (left));
9381 #endif
9382
9383   size = getDataSize (left);
9384   /* test the LEFT size !!! */
9385
9386   /* I suppose that the left size >= result size */
9387   if (shCount == 0)
9388     {
9389       size = getDataSize (result);
9390       while (size--)
9391         movLeft2Result (left, size, result, size, 0);
9392     }
9393
9394   else if (shCount >= (size * 8))
9395     {
9396       if (sign)
9397         {
9398           /* get sign in acc.7 */
9399           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9400         }
9401       addSign (result, LSB, sign);
9402     }
9403   else
9404     {
9405       switch (size)
9406         {
9407         case 1:
9408           genrshOne (result, left, shCount, sign);
9409           break;
9410
9411         case 2:
9412           genrshTwo (result, left, shCount, sign);
9413           break;
9414
9415         case 4:
9416           genrshFour (result, left, shCount, sign);
9417           break;
9418         default:
9419           break;
9420         }
9421     }
9422   freeAsmop (result, NULL, ic, TRUE);
9423   freeAsmop (left, NULL, ic, TRUE);
9424 }
9425
9426 /*-----------------------------------------------------------------*/
9427 /* genSignedRightShift - right shift of signed number              */
9428 /*-----------------------------------------------------------------*/
9429 static void
9430 genSignedRightShift (iCode * ic)
9431 {
9432   operand *right, *left, *result;
9433   int size, offset;
9434   char *l;
9435   symbol *tlbl, *tlbl1;
9436   bool pushedB;
9437
9438   D (emitcode (";", "genSignedRightShift"));
9439
9440   /* we do it the hard way put the shift count in b
9441      and loop thru preserving the sign */
9442
9443   right = IC_RIGHT (ic);
9444   left = IC_LEFT (ic);
9445   result = IC_RESULT (ic);
9446
9447   aopOp (right, ic, FALSE);
9448
9449
9450   if (AOP_TYPE (right) == AOP_LIT)
9451     {
9452       genRightShiftLiteral (left, right, result, ic, 1);
9453       return;
9454     }
9455   /* shift count is unknown then we have to form
9456      a loop get the loop count in B : Note: we take
9457      only the lower order byte since shifting
9458      more that 32 bits make no sense anyway, ( the
9459      largest size of an object can be only 32 bits ) */
9460
9461   pushedB = pushB ();
9462   MOVB (aopGet (right, 0, FALSE, FALSE));
9463   emitcode ("inc", "b");
9464   freeAsmop (right, NULL, ic, TRUE);
9465   aopOp (left, ic, FALSE);
9466   aopOp (result, ic, FALSE);
9467
9468   /* now move the left to the result if they are not the
9469      same */
9470   if (!sameRegs (AOP (left), AOP (result)) &&
9471       AOP_SIZE (result) > 1)
9472     {
9473
9474       size = AOP_SIZE (result);
9475       offset = 0;
9476       while (size--)
9477         {
9478           l = aopGet (left, offset, FALSE, TRUE);
9479           if (*l == '@' && IS_AOP_PREG (result))
9480             {
9481
9482               emitcode ("mov", "a,%s", l);
9483               aopPut (result, "a", offset);
9484             }
9485           else
9486             aopPut (result, l, offset);
9487           offset++;
9488         }
9489     }
9490
9491   /* mov the highest order bit to OVR */
9492   tlbl = newiTempLabel (NULL);
9493   tlbl1 = newiTempLabel (NULL);
9494
9495   size = AOP_SIZE (result);
9496   offset = size - 1;
9497   MOVA (aopGet (left, offset, FALSE, FALSE));
9498   emitcode ("rlc", "a");
9499   emitcode ("mov", "ov,c");
9500   /* if it is only one byte then */
9501   if (size == 1)
9502     {
9503       l = aopGet (left, 0, FALSE, FALSE);
9504       MOVA (l);
9505       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9506       emitLabel (tlbl);
9507       emitcode ("mov", "c,ov");
9508       emitcode ("rrc", "a");
9509       emitLabel (tlbl1);
9510       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9511       popB (pushedB);
9512       aopPut (result, "a", 0);
9513       goto release;
9514     }
9515
9516   reAdjustPreg (AOP (result));
9517   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9518   emitLabel (tlbl);
9519   emitcode ("mov", "c,ov");
9520   while (size--)
9521     {
9522       l = aopGet (result, offset, FALSE, FALSE);
9523       MOVA (l);
9524       emitcode ("rrc", "a");
9525       aopPut (result, "a", offset--);
9526     }
9527   reAdjustPreg (AOP (result));
9528   emitLabel (tlbl1);
9529   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9530   popB (pushedB);
9531
9532 release:
9533   freeAsmop (result, NULL, ic, TRUE);
9534   freeAsmop (left, NULL, ic, TRUE);
9535 }
9536
9537 /*-----------------------------------------------------------------*/
9538 /* genRightShift - generate code for right shifting                */
9539 /*-----------------------------------------------------------------*/
9540 static void
9541 genRightShift (iCode * ic)
9542 {
9543   operand *right, *left, *result;
9544   sym_link *letype;
9545   int size, offset;
9546   char *l;
9547   symbol *tlbl, *tlbl1;
9548   bool pushedB;
9549
9550   D (emitcode (";", "genRightShift"));
9551
9552   /* if signed then we do it the hard way preserve the
9553      sign bit moving it inwards */
9554   letype = getSpec (operandType (IC_LEFT (ic)));
9555
9556   if (!SPEC_USIGN (letype))
9557     {
9558       genSignedRightShift (ic);
9559       return;
9560     }
9561
9562   /* signed & unsigned types are treated the same : i.e. the
9563      signed is NOT propagated inwards : quoting from the
9564      ANSI - standard : "for E1 >> E2, is equivalent to division
9565      by 2**E2 if unsigned or if it has a non-negative value,
9566      otherwise the result is implementation defined ", MY definition
9567      is that the sign does not get propagated */
9568
9569   right = IC_RIGHT (ic);
9570   left = IC_LEFT (ic);
9571   result = IC_RESULT (ic);
9572
9573   aopOp (right, ic, FALSE);
9574
9575   /* if the shift count is known then do it
9576      as efficiently as possible */
9577   if (AOP_TYPE (right) == AOP_LIT)
9578     {
9579       genRightShiftLiteral (left, right, result, ic, 0);
9580       return;
9581     }
9582
9583   /* shift count is unknown then we have to form
9584      a loop get the loop count in B : Note: we take
9585      only the lower order byte since shifting
9586      more that 32 bits make no sense anyway, ( the
9587      largest size of an object can be only 32 bits ) */
9588
9589   pushedB = pushB ();
9590   MOVB (aopGet (right, 0, FALSE, FALSE));
9591   emitcode ("inc", "b");
9592   freeAsmop (right, NULL, ic, TRUE);
9593   aopOp (left, ic, FALSE);
9594   aopOp (result, ic, FALSE);
9595
9596   /* now move the left to the result if they are not the
9597      same */
9598   if (!sameRegs (AOP (left), AOP (result)) &&
9599       AOP_SIZE (result) > 1)
9600     {
9601       size = AOP_SIZE (result);
9602       offset = 0;
9603       while (size--)
9604         {
9605           l = aopGet (left, offset, FALSE, TRUE);
9606           if (*l == '@' && IS_AOP_PREG (result))
9607             {
9608
9609               emitcode ("mov", "a,%s", l);
9610               aopPut (result, "a", offset);
9611             }
9612           else
9613             aopPut (result, l, offset);
9614           offset++;
9615         }
9616     }
9617
9618   tlbl = newiTempLabel (NULL);
9619   tlbl1 = newiTempLabel (NULL);
9620   size = AOP_SIZE (result);
9621   offset = size - 1;
9622
9623   /* if it is only one byte then */
9624   if (size == 1)
9625     {
9626       l = aopGet (left, 0, FALSE, FALSE);
9627       MOVA (l);
9628       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9629       emitLabel (tlbl);
9630       CLRC;
9631       emitcode ("rrc", "a");
9632       emitLabel (tlbl1);
9633       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9634       popB (pushedB);
9635       aopPut (result, "a", 0);
9636       goto release;
9637     }
9638
9639   reAdjustPreg (AOP (result));
9640   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9641   emitLabel (tlbl);
9642   CLRC;
9643   while (size--)
9644     {
9645       l = aopGet (result, offset, FALSE, FALSE);
9646       MOVA (l);
9647       emitcode ("rrc", "a");
9648       aopPut (result, "a", offset--);
9649     }
9650   reAdjustPreg (AOP (result));
9651
9652   emitLabel (tlbl1);
9653   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9654   popB (pushedB);
9655
9656 release:
9657   freeAsmop (result, NULL, ic, TRUE);
9658   freeAsmop (left, NULL, ic, TRUE);
9659 }
9660
9661 /*-----------------------------------------------------------------*/
9662 /* emitPtrByteGet - emits code to get a byte into A through a      */
9663 /*                  pointer register (R0, R1, or DPTR). The        */
9664 /*                  original value of A can be preserved in B.     */
9665 /*-----------------------------------------------------------------*/
9666 static void
9667 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9668 {
9669   switch (p_type)
9670     {
9671     case IPOINTER:
9672     case POINTER:
9673       if (preserveAinB)
9674         emitcode ("mov", "b,a");
9675       emitcode ("mov", "a,@%s", rname);
9676       break;
9677
9678     case PPOINTER:
9679       if (preserveAinB)
9680         emitcode ("mov", "b,a");
9681       emitcode ("movx", "a,@%s", rname);
9682       break;
9683
9684     case FPOINTER:
9685       if (preserveAinB)
9686         emitcode ("mov", "b,a");
9687       emitcode ("movx", "a,@dptr");
9688       break;
9689
9690     case CPOINTER:
9691       if (preserveAinB)
9692         emitcode ("mov", "b,a");
9693       emitcode ("clr", "a");
9694       emitcode ("movc", "a,@a+dptr");
9695       break;
9696
9697     case GPOINTER:
9698       if (preserveAinB)
9699         {
9700           emitcode ("push", "b");
9701           emitcode ("push", "acc");
9702         }
9703       emitcode ("lcall", "__gptrget");
9704       if (preserveAinB)
9705         emitcode ("pop", "b");
9706       break;
9707     }
9708 }
9709
9710 /*-----------------------------------------------------------------*/
9711 /* emitPtrByteSet - emits code to set a byte from src through a    */
9712 /*                  pointer register (R0, R1, or DPTR).            */
9713 /*-----------------------------------------------------------------*/
9714 static void
9715 emitPtrByteSet (char *rname, int p_type, char *src)
9716 {
9717   switch (p_type)
9718     {
9719     case IPOINTER:
9720     case POINTER:
9721       if (*src=='@')
9722         {
9723           MOVA (src);
9724           emitcode ("mov", "@%s,a", rname);
9725         }
9726       else
9727         emitcode ("mov", "@%s,%s", rname, src);
9728       break;
9729
9730     case PPOINTER:
9731       MOVA (src);
9732       emitcode ("movx", "@%s,a", rname);
9733       break;
9734
9735     case FPOINTER:
9736       MOVA (src);
9737       emitcode ("movx", "@dptr,a");
9738       break;
9739
9740     case GPOINTER:
9741       MOVA (src);
9742       emitcode ("lcall", "__gptrput");
9743       break;
9744     }
9745 }
9746
9747 /*-----------------------------------------------------------------*/
9748 /* genUnpackBits - generates code for unpacking bits               */
9749 /*-----------------------------------------------------------------*/
9750 static char*
9751 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9752 {
9753   int offset = 0;       /* result byte offset */
9754   int rsize;            /* result size */
9755   int rlen = 0;         /* remaining bitfield length */
9756   sym_link *etype;      /* bitfield type information */
9757   int blen;             /* bitfield length */
9758   int bstr;             /* bitfield starting bit within byte */
9759   static char* const accBits[] = {"acc.0", "acc.1", "acc.2", "acc.3",
9760                                   "acc.4", "acc.5", "acc.6", "acc.7"};
9761
9762   D(emitcode (";", "genUnpackBits"));
9763
9764   etype = getSpec (operandType (result));
9765   rsize = getSize (operandType (result));
9766   blen = SPEC_BLEN (etype);
9767   bstr = SPEC_BSTR (etype);
9768
9769   if (ifx && blen <= 8)
9770     {
9771       emitPtrByteGet (rname, ptype, FALSE);
9772       if (blen == 1)
9773         {
9774           return accBits[bstr];;
9775         }
9776       else
9777         {
9778           if (blen < 8)
9779             emitcode ("anl", "a,#0x%02x",
9780                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9781           return "a";
9782         }
9783     }
9784   wassert (!ifx);
9785
9786   /* If the bitfield length is less than a byte */
9787   if (blen < 8)
9788     {
9789       emitPtrByteGet (rname, ptype, FALSE);
9790       AccRol (8 - bstr);
9791       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9792       if (!SPEC_USIGN (etype))
9793         {
9794           /* signed bitfield */
9795           symbol *tlbl = newiTempLabel (NULL);
9796
9797           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9798           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9799           emitLabel (tlbl);
9800         }
9801       aopPut (result, "a", offset++);
9802       goto finish;
9803     }
9804
9805   /* Bit field did not fit in a byte. Copy all
9806      but the partial byte at the end.  */
9807   for (rlen=blen;rlen>=8;rlen-=8)
9808     {
9809       emitPtrByteGet (rname, ptype, FALSE);
9810       aopPut (result, "a", offset++);
9811       if (rlen>8)
9812         emitcode ("inc", "%s", rname);
9813     }
9814
9815   /* Handle the partial byte at the end */
9816   if (rlen)
9817     {
9818       emitPtrByteGet (rname, ptype, FALSE);
9819       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9820       if (!SPEC_USIGN (etype))
9821         {
9822           /* signed bitfield */
9823           symbol *tlbl = newiTempLabel (NULL);
9824
9825           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9826           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9827           emitLabel (tlbl);
9828         }
9829       aopPut (result, "a", offset++);
9830     }
9831
9832 finish:
9833   if (offset < rsize)
9834     {
9835       char *source;
9836
9837       if (SPEC_USIGN (etype))
9838         source = zero;
9839       else
9840         {
9841           /* signed bitfield: sign extension with 0x00 or 0xff */
9842           emitcode ("rlc", "a");
9843           emitcode ("subb", "a,acc");
9844
9845           source = "a";
9846         }
9847       rsize -= offset;
9848       while (rsize--)
9849         aopPut (result, source, offset++);
9850     }
9851   return NULL;
9852 }
9853
9854
9855 /*-----------------------------------------------------------------*/
9856 /* genDataPointerGet - generates code when ptr offset is known     */
9857 /*-----------------------------------------------------------------*/
9858 static void
9859 genDataPointerGet (operand * left,
9860                    operand * result,
9861                    iCode * ic)
9862 {
9863   char *l;
9864   char buffer[256];
9865   int size, offset = 0;
9866
9867   D (emitcode (";", "genDataPointerGet"));
9868
9869   aopOp (result, ic, TRUE);
9870
9871   /* get the string representation of the name */
9872   l = aopGet (left, 0, FALSE, TRUE);
9873   l++; // remove #
9874   size = AOP_SIZE (result);
9875   while (size--)
9876     {
9877       if (offset)
9878         {
9879           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9880         }
9881       else
9882         {
9883           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9884         }
9885       aopPut (result, buffer, offset++);
9886     }
9887
9888   freeAsmop (result, NULL, ic, TRUE);
9889   freeAsmop (left, NULL, ic, TRUE);
9890 }
9891
9892 /*-----------------------------------------------------------------*/
9893 /* genNearPointerGet - emitcode for near pointer fetch             */
9894 /*-----------------------------------------------------------------*/
9895 static void
9896 genNearPointerGet (operand * left,
9897                    operand * result,
9898                    iCode * ic,
9899                    iCode * pi,
9900                    iCode * ifx)
9901 {
9902   asmop *aop = NULL;
9903   regs *preg = NULL;
9904   char *rname;
9905   char *ifxCond = "a";
9906   sym_link *rtype, *retype;
9907   sym_link *ltype = operandType (left);
9908
9909   D (emitcode (";", "genNearPointerGet"));
9910
9911   rtype = operandType (result);
9912   retype = getSpec (rtype);
9913
9914   aopOp (left, ic, FALSE);
9915
9916   /* if left is rematerialisable and
9917      result is not bitfield variable type and
9918      the left is pointer to data space i.e
9919      lower 128 bytes of space */
9920   if (AOP_TYPE (left) == AOP_IMMD &&
9921       !IS_BITFIELD (retype) &&
9922       DCL_TYPE (ltype) == POINTER)
9923     {
9924       genDataPointerGet (left, result, ic);
9925       return;
9926     }
9927
9928   //aopOp (result, ic, FALSE);
9929   aopOp (result, ic, result?TRUE:FALSE);
9930
9931  /* if the value is already in a pointer register
9932      then don't need anything more */
9933   if (!AOP_INPREG (AOP (left)))
9934     {
9935       if (IS_AOP_PREG (left))
9936         {
9937           // Aha, it is a pointer, just in disguise.
9938           rname = aopGet (left, 0, FALSE, FALSE);
9939           if (*rname != '@')
9940             {
9941               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9942                       __FILE__, __LINE__);
9943             }
9944           else
9945             {
9946               // Expected case.
9947               emitcode ("mov", "a%s,%s", rname + 1, rname);
9948               rname++;  // skip the '@'.
9949             }
9950         }
9951       else
9952         {
9953           /* otherwise get a free pointer register */
9954           aop = newAsmop (0);
9955           preg = getFreePtr (ic, &aop, FALSE);
9956           emitcode ("mov", "%s,%s",
9957                     preg->name,
9958                     aopGet (left, 0, FALSE, TRUE));
9959           rname = preg->name;
9960         }
9961     }
9962   else
9963     rname = aopGet (left, 0, FALSE, FALSE);
9964
9965   /* if bitfield then unpack the bits */
9966   if (IS_BITFIELD (retype))
9967     ifxCond = genUnpackBits (result, rname, POINTER, ifx);
9968   else
9969     {
9970       /* we have can just get the values */
9971       int size = AOP_SIZE (result);
9972       int offset = 0;
9973
9974       while (size--)
9975         {
9976           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9977             {
9978
9979               emitcode ("mov", "a,@%s", rname);
9980               if (!ifx)
9981                 aopPut (result, "a", offset);
9982             }
9983           else
9984             {
9985               char buffer[80];
9986
9987               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9988               aopPut (result, buffer, offset);
9989             }
9990           offset++;
9991           if (size || pi)
9992             emitcode ("inc", "%s", rname);
9993         }
9994     }
9995
9996   /* now some housekeeping stuff */
9997   if (aop)       /* we had to allocate for this iCode */
9998     {
9999       if (pi) { /* post increment present */
10000         aopPut (left, rname, 0);
10001       }
10002       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10003     }
10004   else
10005     {
10006       /* we did not allocate which means left
10007          already in a pointer register, then
10008          if size > 0 && this could be used again
10009          we have to point it back to where it
10010          belongs */
10011       if ((AOP_SIZE (result) > 1 &&
10012            !OP_SYMBOL (left)->remat &&
10013            (OP_SYMBOL (left)->liveTo > ic->seq ||
10014             ic->depth)) &&
10015           !pi)
10016         {
10017           int size = AOP_SIZE (result) - 1;
10018           while (size--)
10019             emitcode ("dec", "%s", rname);
10020         }
10021     }
10022
10023   if (ifx && !ifx->generated)
10024     {
10025       genIfxJump (ifx, ifxCond, left, NULL, result);
10026     }
10027
10028   /* done */
10029   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10030   freeAsmop (left, NULL, ic, TRUE);
10031   if (pi) pi->generated = 1;
10032 }
10033
10034 /*-----------------------------------------------------------------*/
10035 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10036 /*-----------------------------------------------------------------*/
10037 static void
10038 genPagedPointerGet (operand * left,
10039                     operand * result,
10040                     iCode * ic,
10041                     iCode *pi,
10042                     iCode *ifx)
10043 {
10044   asmop *aop = NULL;
10045   regs *preg = NULL;
10046   char *rname;
10047   char *ifxCond = "a";
10048   sym_link *rtype, *retype;
10049
10050   D (emitcode (";", "genPagedPointerGet"));
10051
10052   rtype = operandType (result);
10053   retype = getSpec (rtype);
10054
10055   aopOp (left, ic, FALSE);
10056
10057   aopOp (result, ic, FALSE);
10058
10059   /* if the value is already in a pointer register
10060      then don't need anything more */
10061   if (!AOP_INPREG (AOP (left)))
10062     {
10063       /* otherwise get a free pointer register */
10064       aop = newAsmop (0);
10065       preg = getFreePtr (ic, &aop, FALSE);
10066       emitcode ("mov", "%s,%s",
10067                 preg->name,
10068                 aopGet (left, 0, FALSE, TRUE));
10069       rname = preg->name;
10070     }
10071   else
10072     rname = aopGet (left, 0, FALSE, FALSE);
10073
10074   /* if bitfield then unpack the bits */
10075   if (IS_BITFIELD (retype))
10076     ifxCond = genUnpackBits (result, rname, PPOINTER, ifx);
10077   else
10078     {
10079       /* we have can just get the values */
10080       int size = AOP_SIZE (result);
10081       int offset = 0;
10082
10083       while (size--)
10084         {
10085
10086           emitcode ("movx", "a,@%s", rname);
10087           if (!ifx)
10088             aopPut (result, "a", offset);
10089
10090           offset++;
10091
10092           if (size || pi)
10093             emitcode ("inc", "%s", rname);
10094         }
10095     }
10096
10097   /* now some housekeeping stuff */
10098   if (aop) /* we had to allocate for this iCode */
10099     {
10100       if (pi)
10101         aopPut (left, rname, 0);
10102       freeAsmop (NULL, aop, ic, TRUE);
10103     }
10104   else
10105     {
10106       /* we did not allocate which means left
10107          already in a pointer register, then
10108          if size > 0 && this could be used again
10109          we have to point it back to where it
10110          belongs */
10111       if ((AOP_SIZE (result) > 1 &&
10112            !OP_SYMBOL (left)->remat &&
10113            (OP_SYMBOL (left)->liveTo > ic->seq ||
10114             ic->depth)) &&
10115           !pi)
10116         {
10117           int size = AOP_SIZE (result) - 1;
10118           while (size--)
10119             emitcode ("dec", "%s", rname);
10120         }
10121     }
10122
10123   if (ifx && !ifx->generated)
10124     {
10125       genIfxJump (ifx, ifxCond, left, NULL, result);
10126     }
10127
10128   /* done */
10129   freeAsmop (result, NULL, ic, TRUE);
10130   freeAsmop (left, NULL, ic, TRUE);
10131   if (pi) pi->generated = 1;
10132 }
10133
10134 /*--------------------------------------------------------------------*/
10135 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10136 /*--------------------------------------------------------------------*/
10137 static void
10138 loadDptrFromOperand (operand *op, bool loadBToo)
10139 {
10140   if (AOP_TYPE (op) != AOP_STR)
10141     {
10142       /* if this is rematerializable */
10143       if (AOP_TYPE (op) == AOP_IMMD)
10144         {
10145           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10146           if (loadBToo)
10147             {
10148               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10149                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10150               else
10151                 {
10152                   wassertl(FALSE, "need pointerCode");
10153                   emitcode (";", "mov b,???");
10154                   /* genPointerGet and genPointerSet originally did different
10155                   ** things for this case. Both seem wrong.
10156                   ** from genPointerGet:
10157                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10158                   ** from genPointerSet:
10159                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10160                   */
10161                 }
10162             }
10163         }
10164       else if (AOP_TYPE (op) == AOP_DPTR)
10165         {
10166           if (loadBToo)
10167             {
10168               MOVA (aopGet (op, 0, FALSE, FALSE));
10169               emitcode ("push", "acc");
10170               MOVA (aopGet (op, 1, FALSE, FALSE));
10171               emitcode ("push", "acc");
10172               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10173               emitcode ("pop", "dph");
10174               emitcode ("pop", "dpl");
10175             }
10176           else
10177             {
10178               MOVA (aopGet (op, 0, FALSE, FALSE));
10179               emitcode ("push", "acc");
10180               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10181               emitcode ("pop", "dpl");
10182             }
10183         }
10184       else
10185         {                       /* we need to get it byte by byte */
10186           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10187           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10188           if (loadBToo)
10189             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10190         }
10191     }
10192 }
10193
10194 /*-----------------------------------------------------------------*/
10195 /* genFarPointerGet - get value from far space                     */
10196 /*-----------------------------------------------------------------*/
10197 static void
10198 genFarPointerGet (operand * left,
10199                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10200 {
10201   int size, offset;
10202   char *ifxCond = "a";
10203   sym_link *retype = getSpec (operandType (result));
10204
10205   D (emitcode (";", "genFarPointerGet"));
10206
10207   aopOp (left, ic, FALSE);
10208   loadDptrFromOperand (left, FALSE);
10209
10210   /* so dptr now contains the address */
10211   aopOp (result, ic, FALSE);
10212
10213   /* if bit then unpack */
10214   if (IS_BITFIELD (retype))
10215     ifxCond = genUnpackBits (result, "dptr", FPOINTER, ifx);
10216   else
10217     {
10218       size = AOP_SIZE (result);
10219       offset = 0;
10220
10221       while (size--)
10222         {
10223           emitcode ("movx", "a,@dptr");
10224           if (!ifx)
10225             aopPut (result, "a", offset++);
10226           if (size || pi)
10227             emitcode ("inc", "dptr");
10228         }
10229     }
10230
10231   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10232     {
10233       aopPut (left, "dpl", 0);
10234       aopPut (left, "dph", 1);
10235       pi->generated = 1;
10236     }
10237
10238   if (ifx && !ifx->generated)
10239     {
10240       genIfxJump (ifx, ifxCond, left, NULL, result);
10241     }
10242
10243   freeAsmop (result, NULL, ic, TRUE);
10244   freeAsmop (left, NULL, ic, TRUE);
10245 }
10246
10247 /*-----------------------------------------------------------------*/
10248 /* genCodePointerGet - get value from code space                   */
10249 /*-----------------------------------------------------------------*/
10250 static void
10251 genCodePointerGet (operand * left,
10252                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10253 {
10254   int size, offset;
10255   char *ifxCond = "a";
10256   sym_link *retype = getSpec (operandType (result));
10257
10258   D (emitcode (";", "genCodePointerGet"));
10259
10260   aopOp (left, ic, FALSE);
10261   loadDptrFromOperand (left, FALSE);
10262
10263   /* so dptr now contains the address */
10264   aopOp (result, ic, FALSE);
10265
10266   /* if bit then unpack */
10267   if (IS_BITFIELD (retype))
10268     ifxCond = genUnpackBits (result, "dptr", CPOINTER, ifx);
10269   else
10270     {
10271       size = AOP_SIZE (result);
10272       offset = 0;
10273
10274       while (size--)
10275         {
10276           emitcode ("clr", "a");
10277           emitcode ("movc", "a,@a+dptr");
10278           if (!ifx)
10279             aopPut (result, "a", offset++);
10280           if (size || pi)
10281             emitcode ("inc", "dptr");
10282         }
10283     }
10284
10285   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10286     {
10287       aopPut (left, "dpl", 0);
10288       aopPut (left, "dph", 1);
10289       pi->generated = 1;
10290     }
10291
10292   if (ifx && !ifx->generated)
10293     {
10294       genIfxJump (ifx, ifxCond, left, NULL, result);
10295     }
10296
10297   freeAsmop (result, NULL, ic, TRUE);
10298   freeAsmop (left, NULL, ic, TRUE);
10299 }
10300
10301 /*-----------------------------------------------------------------*/
10302 /* genGenPointerGet - get value from generic pointer space         */
10303 /*-----------------------------------------------------------------*/
10304 static void
10305 genGenPointerGet (operand * left,
10306                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10307 {
10308   int size, offset;
10309   char *ifxCond = "a";
10310   sym_link *retype = getSpec (operandType (result));
10311
10312   D (emitcode (";", "genGenPointerGet"));
10313
10314   aopOp (left, ic, FALSE);
10315   loadDptrFromOperand (left, TRUE);
10316
10317   /* so dptr now contains the address */
10318   aopOp (result, ic, FALSE);
10319
10320   /* if bit then unpack */
10321   if (IS_BITFIELD (retype))
10322     {
10323       ifxCond = genUnpackBits (result, "dptr", GPOINTER, ifx);
10324     }
10325   else
10326     {
10327       size = AOP_SIZE (result);
10328       offset = 0;
10329
10330       while (size--)
10331         {
10332           emitcode ("lcall", "__gptrget");
10333           if (!ifx)
10334             aopPut (result, "a", offset++);
10335           if (size || pi)
10336             emitcode ("inc", "dptr");
10337         }
10338     }
10339
10340   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10341     {
10342       aopPut (left, "dpl", 0);
10343       aopPut (left, "dph", 1);
10344       pi->generated = 1;
10345     }
10346
10347   if (ifx && !ifx->generated)
10348     {
10349       genIfxJump (ifx, ifxCond, left, NULL, result);
10350     }
10351
10352   freeAsmop (result, NULL, ic, TRUE);
10353   freeAsmop (left, NULL, ic, TRUE);
10354 }
10355
10356 /*-----------------------------------------------------------------*/
10357 /* genPointerGet - generate code for pointer get                   */
10358 /*-----------------------------------------------------------------*/
10359 static void
10360 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10361 {
10362   operand *left, *result;
10363   sym_link *type, *etype;
10364   int p_type;
10365
10366   D (emitcode (";", "genPointerGet"));
10367
10368   left = IC_LEFT (ic);
10369   result = IC_RESULT (ic);
10370
10371   if (getSize (operandType (result))>1)
10372     ifx = NULL;
10373
10374   /* depending on the type of pointer we need to
10375      move it to the correct pointer register */
10376   type = operandType (left);
10377   etype = getSpec (type);
10378   /* if left is of type of pointer then it is simple */
10379   if (IS_PTR (type) && !IS_FUNC (type->next))
10380     {
10381       p_type = DCL_TYPE (type);
10382     }
10383   else
10384     {
10385       /* we have to go by the storage class */
10386       p_type = PTR_TYPE (SPEC_OCLS (etype));
10387     }
10388
10389   /* special case when cast remat */
10390   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10391       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10392     {
10393       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10394       type = operandType (left);
10395       p_type = DCL_TYPE (type);
10396     }
10397   /* now that we have the pointer type we assign
10398      the pointer values */
10399   switch (p_type)
10400     {
10401
10402     case POINTER:
10403     case IPOINTER:
10404       genNearPointerGet (left, result, ic, pi, ifx);
10405       break;
10406
10407     case PPOINTER:
10408       genPagedPointerGet (left, result, ic, pi, ifx);
10409       break;
10410
10411     case FPOINTER:
10412       genFarPointerGet (left, result, ic, pi, ifx);
10413       break;
10414
10415     case CPOINTER:
10416       genCodePointerGet (left, result, ic, pi, ifx);
10417       break;
10418
10419     case GPOINTER:
10420       genGenPointerGet (left, result, ic, pi, ifx);
10421       break;
10422     }
10423 }
10424
10425
10426 /*-----------------------------------------------------------------*/
10427 /* genPackBits - generates code for packed bit storage             */
10428 /*-----------------------------------------------------------------*/
10429 static void
10430 genPackBits (sym_link * etype,
10431              operand * right,
10432              char *rname, int p_type)
10433 {
10434   int offset = 0;       /* source byte offset */
10435   int rlen = 0;         /* remaining bitfield length */
10436   int blen;             /* bitfield length */
10437   int bstr;             /* bitfield starting bit within byte */
10438   int litval;           /* source literal value (if AOP_LIT) */
10439   unsigned char mask;   /* bitmask within current byte */
10440
10441   D(emitcode (";", "genPackBits"));
10442
10443   blen = SPEC_BLEN (etype);
10444   bstr = SPEC_BSTR (etype);
10445
10446   /* If the bitfield length is less than a byte */
10447   if (blen < 8)
10448     {
10449       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10450               (unsigned char) (0xFF >> (8 - bstr)));
10451
10452       if (AOP_TYPE (right) == AOP_LIT)
10453         {
10454           /* Case with a bitfield length <8 and literal source
10455           */
10456           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10457           litval <<= bstr;
10458           litval &= (~mask) & 0xff;
10459           emitPtrByteGet (rname, p_type, FALSE);
10460           if ((mask|litval)!=0xff)
10461             emitcode ("anl","a,#0x%02x", mask);
10462           if (litval)
10463             emitcode ("orl","a,#0x%02x", litval);
10464         }
10465       else
10466         {
10467           if ((blen==1) && (p_type!=GPOINTER))
10468             {
10469               /* Case with a bitfield length == 1 and no generic pointer
10470               */
10471               if (AOP_TYPE (right) == AOP_CRY)
10472                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10473               else
10474                 {
10475                   MOVA (aopGet (right, 0, FALSE, FALSE));
10476                   emitcode ("rrc","a");
10477                 }
10478               emitPtrByteGet (rname, p_type, FALSE);
10479               emitcode ("mov","acc.%d,c",bstr);
10480             }
10481           else
10482             {
10483               bool pushedB;
10484               /* Case with a bitfield length < 8 and arbitrary source
10485               */
10486               MOVA (aopGet (right, 0, FALSE, FALSE));
10487               /* shift and mask source value */
10488               AccLsh (bstr);
10489               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10490
10491               pushedB = pushB ();
10492               /* transfer A to B and get next byte */
10493               emitPtrByteGet (rname, p_type, TRUE);
10494
10495               emitcode ("anl", "a,#0x%02x", mask);
10496               emitcode ("orl", "a,b");
10497               if (p_type == GPOINTER)
10498                 emitcode ("pop", "b");
10499
10500               popB (pushedB);
10501            }
10502         }
10503
10504       emitPtrByteSet (rname, p_type, "a");
10505       return;
10506     }
10507
10508   /* Bit length is greater than 7 bits. In this case, copy  */
10509   /* all except the partial byte at the end                 */
10510   for (rlen=blen;rlen>=8;rlen-=8)
10511     {
10512       emitPtrByteSet (rname, p_type,
10513                       aopGet (right, offset++, FALSE, TRUE) );
10514       if (rlen>8)
10515         emitcode ("inc", "%s", rname);
10516     }
10517
10518   /* If there was a partial byte at the end */
10519   if (rlen)
10520     {
10521       mask = (((unsigned char) -1 << rlen) & 0xff);
10522
10523       if (AOP_TYPE (right) == AOP_LIT)
10524         {
10525           /* Case with partial byte and literal source
10526           */
10527           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10528           litval >>= (blen-rlen);
10529           litval &= (~mask) & 0xff;
10530           emitPtrByteGet (rname, p_type, FALSE);
10531           if ((mask|litval)!=0xff)
10532             emitcode ("anl","a,#0x%02x", mask);
10533           if (litval)
10534             emitcode ("orl","a,#0x%02x", litval);
10535         }
10536       else
10537         {
10538           bool pushedB;
10539           /* Case with partial byte and arbitrary source
10540           */
10541           MOVA (aopGet (right, offset++, FALSE, FALSE));
10542           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10543
10544           pushedB = pushB ();
10545           /* transfer A to B and get next byte */
10546           emitPtrByteGet (rname, p_type, TRUE);
10547
10548           emitcode ("anl", "a,#0x%02x", mask);
10549           emitcode ("orl", "a,b");
10550           if (p_type == GPOINTER)
10551             emitcode ("pop", "b");
10552
10553           popB (pushedB);
10554         }
10555       emitPtrByteSet (rname, p_type, "a");
10556     }
10557 }
10558
10559
10560 /*-----------------------------------------------------------------*/
10561 /* genDataPointerSet - remat pointer to data space                 */
10562 /*-----------------------------------------------------------------*/
10563 static void
10564 genDataPointerSet (operand * right,
10565                    operand * result,
10566                    iCode * ic)
10567 {
10568   int size, offset = 0;
10569   char *l, buffer[256];
10570
10571   D (emitcode (";", "genDataPointerSet"));
10572
10573   aopOp (right, ic, FALSE);
10574
10575   l = aopGet (result, 0, FALSE, TRUE);
10576   l++; //remove #
10577   size = max (AOP_SIZE (right), AOP_SIZE (result));
10578   while (size--)
10579     {
10580       if (offset)
10581         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10582       else
10583         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10584       emitcode ("mov", "%s,%s", buffer,
10585                 aopGet (right, offset++, FALSE, FALSE));
10586     }
10587
10588   freeAsmop (right, NULL, ic, TRUE);
10589   freeAsmop (result, NULL, ic, TRUE);
10590 }
10591
10592 /*-----------------------------------------------------------------*/
10593 /* genNearPointerSet - emitcode for near pointer put               */
10594 /*-----------------------------------------------------------------*/
10595 static void
10596 genNearPointerSet (operand * right,
10597                    operand * result,
10598                    iCode * ic,
10599                    iCode * pi)
10600 {
10601   asmop *aop = NULL;
10602   regs *preg = NULL;
10603   char *rname, *l;
10604   sym_link *retype, *letype;
10605   sym_link *ptype = operandType (result);
10606
10607   D (emitcode (";", "genNearPointerSet"));
10608
10609   retype = getSpec (operandType (right));
10610   letype = getSpec (ptype);
10611
10612   aopOp (result, ic, FALSE);
10613
10614   /* if the result is rematerializable &
10615      in data space & not a bit variable */
10616   if (AOP_TYPE (result) == AOP_IMMD &&
10617       DCL_TYPE (ptype) == POINTER &&
10618       !IS_BITVAR (retype) &&
10619       !IS_BITVAR (letype))
10620     {
10621       genDataPointerSet (right, result, ic);
10622       return;
10623     }
10624
10625   /* if the value is already in a pointer register
10626      then don't need anything more */
10627   if (!AOP_INPREG (AOP (result)))
10628     {
10629       if (IS_AOP_PREG (result))
10630         {
10631           // Aha, it is a pointer, just in disguise.
10632           rname = aopGet (result, 0, FALSE, FALSE);
10633           if (*rname != '@')
10634             {
10635               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10636                       __FILE__, __LINE__);
10637             }
10638           else
10639             {
10640               // Expected case.
10641               emitcode ("mov", "a%s,%s", rname + 1, rname);
10642               rname++;  // skip the '@'.
10643             }
10644         }
10645       else
10646         {
10647           /* otherwise get a free pointer register */
10648           aop = newAsmop (0);
10649           preg = getFreePtr (ic, &aop, FALSE);
10650           emitcode ("mov", "%s,%s",
10651                     preg->name,
10652                     aopGet (result, 0, FALSE, TRUE));
10653           rname = preg->name;
10654         }
10655     }
10656   else
10657     {
10658       rname = aopGet (result, 0, FALSE, FALSE);
10659     }
10660
10661   aopOp (right, ic, FALSE);
10662
10663   /* if bitfield then unpack the bits */
10664   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10665     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10666   else
10667     {
10668       /* we can just get the values */
10669       int size = AOP_SIZE (right);
10670       int offset = 0;
10671
10672       while (size--)
10673         {
10674           l = aopGet (right, offset, FALSE, TRUE);
10675           if ((*l == '@') || (strcmp (l, "acc") == 0))
10676             {
10677               MOVA (l);
10678               emitcode ("mov", "@%s,a", rname);
10679             }
10680           else
10681             emitcode ("mov", "@%s,%s", rname, l);
10682           if (size || pi)
10683             emitcode ("inc", "%s", rname);
10684           offset++;
10685         }
10686     }
10687
10688   /* now some housekeeping stuff */
10689   if (aop) /* we had to allocate for this iCode */
10690     {
10691       if (pi)
10692         aopPut (result, rname, 0);
10693       freeAsmop (NULL, aop, ic, TRUE);
10694     }
10695   else
10696     {
10697       /* we did not allocate which means left
10698          already in a pointer register, then
10699          if size > 0 && this could be used again
10700          we have to point it back to where it
10701          belongs */
10702       if ((AOP_SIZE (right) > 1 &&
10703            !OP_SYMBOL (result)->remat &&
10704            (OP_SYMBOL (result)->liveTo > ic->seq ||
10705             ic->depth)) &&
10706           !pi)
10707         {
10708           int size = AOP_SIZE (right) - 1;
10709           while (size--)
10710             emitcode ("dec", "%s", rname);
10711         }
10712     }
10713
10714   /* done */
10715   if (pi)
10716     pi->generated = 1;
10717   freeAsmop (right, NULL, ic, TRUE);
10718   freeAsmop (result, NULL, ic, TRUE);
10719 }
10720
10721 /*-----------------------------------------------------------------*/
10722 /* genPagedPointerSet - emitcode for Paged pointer put             */
10723 /*-----------------------------------------------------------------*/
10724 static void
10725 genPagedPointerSet (operand * right,
10726                     operand * result,
10727                     iCode * ic,
10728                     iCode * pi)
10729 {
10730   asmop *aop = NULL;
10731   regs *preg = NULL;
10732   char *rname, *l;
10733   sym_link *retype, *letype;
10734
10735   D (emitcode (";", "genPagedPointerSet"));
10736
10737   retype = getSpec (operandType (right));
10738   letype = getSpec (operandType (result));
10739
10740   aopOp (result, ic, FALSE);
10741
10742   /* if the value is already in a pointer register
10743      then don't need anything more */
10744   if (!AOP_INPREG (AOP (result)))
10745     {
10746       if (IS_AOP_PREG (result))
10747         {
10748           // Aha, it is a pointer, just in disguise.
10749           rname = aopGet (result, 0, FALSE, FALSE);
10750           if (*rname != '@')
10751             {
10752               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10753                       __FILE__, __LINE__);
10754             }
10755           else
10756             {
10757               // Expected case.
10758               emitcode ("mov", "a%s,%s", rname + 1, rname);
10759               rname++;  // skip the '@'.
10760             }
10761         }
10762       else
10763         {
10764           /* otherwise get a free pointer register */
10765           aop = newAsmop (0);
10766           preg = getFreePtr (ic, &aop, FALSE);
10767           emitcode ("mov", "%s,%s",
10768                     preg->name,
10769                     aopGet (result, 0, FALSE, TRUE));
10770           rname = preg->name;
10771         }
10772     }
10773   else
10774     {
10775       rname = aopGet (result, 0, FALSE, FALSE);
10776     }
10777
10778   aopOp (right, ic, FALSE);
10779
10780   /* if bitfield then unpack the bits */
10781   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10782     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10783   else
10784     {
10785       /* we can just get the values */
10786       int size = AOP_SIZE (right);
10787       int offset = 0;
10788
10789       while (size--)
10790         {
10791           l = aopGet (right, offset, FALSE, TRUE);
10792           MOVA (l);
10793           emitcode ("movx", "@%s,a", rname);
10794           if (size || pi)
10795             emitcode ("inc", "%s", rname);
10796           offset++;
10797         }
10798     }
10799
10800   /* now some housekeeping stuff */
10801   if (aop) /* we had to allocate for this iCode */
10802     {
10803       if (pi)
10804         aopPut (result, rname, 0);
10805       freeAsmop (NULL, aop, ic, TRUE);
10806     }
10807   else
10808     {
10809       /* we did not allocate which means left
10810          already in a pointer register, then
10811          if size > 0 && this could be used again
10812          we have to point it back to where it
10813          belongs */
10814       if (AOP_SIZE (right) > 1 &&
10815           !OP_SYMBOL (result)->remat &&
10816           (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) &&
10817           !pi)
10818         {
10819           int size = AOP_SIZE (right) - 1;
10820           while (size--)
10821             emitcode ("dec", "%s", rname);
10822         }
10823     }
10824
10825   /* done */
10826   if (pi)
10827     pi->generated = 1;
10828   freeAsmop (right, NULL, ic, TRUE);
10829   freeAsmop (result, NULL, ic, TRUE);
10830 }
10831
10832 /*-----------------------------------------------------------------*/
10833 /* genFarPointerSet - set value from far space                     */
10834 /*-----------------------------------------------------------------*/
10835 static void
10836 genFarPointerSet (operand * right,
10837                   operand * result, iCode * ic, iCode * pi)
10838 {
10839   int size, offset;
10840   sym_link *retype = getSpec (operandType (right));
10841   sym_link *letype = getSpec (operandType (result));
10842
10843   D(emitcode (";", "genFarPointerSet"));
10844
10845   aopOp (result, ic, FALSE);
10846   loadDptrFromOperand (result, FALSE);
10847
10848   /* so dptr now contains the address */
10849   aopOp (right, ic, FALSE);
10850
10851   /* if bit then unpack */
10852   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10853     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10854   else
10855     {
10856       size = AOP_SIZE (right);
10857       offset = 0;
10858
10859       while (size--)
10860         {
10861           char *l = aopGet (right, offset++, FALSE, FALSE);
10862           MOVA (l);
10863           emitcode ("movx", "@dptr,a");
10864           if (size || pi)
10865             emitcode ("inc", "dptr");
10866         }
10867     }
10868   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10869     aopPut (result, "dpl", 0);
10870     aopPut (result, "dph", 1);
10871     pi->generated=1;
10872   }
10873   freeAsmop (result, NULL, ic, TRUE);
10874   freeAsmop (right, NULL, ic, TRUE);
10875 }
10876
10877 /*-----------------------------------------------------------------*/
10878 /* genGenPointerSet - set value from generic pointer space         */
10879 /*-----------------------------------------------------------------*/
10880 static void
10881 genGenPointerSet (operand * right,
10882                   operand * result, iCode * ic, iCode * pi)
10883 {
10884   int size, offset;
10885   sym_link *retype = getSpec (operandType (right));
10886   sym_link *letype = getSpec (operandType (result));
10887
10888   D (emitcode (";", "genGenPointerSet"));
10889
10890   aopOp (result, ic, FALSE);
10891   loadDptrFromOperand (result, TRUE);
10892
10893   /* so dptr now contains the address */
10894   aopOp (right, ic, FALSE);
10895
10896   /* if bit then unpack */
10897   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10898     {
10899       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10900     }
10901   else
10902     {
10903       size = AOP_SIZE (right);
10904       offset = 0;
10905
10906       while (size--)
10907         {
10908           char *l = aopGet (right, offset++, FALSE, FALSE);
10909           MOVA (l);
10910           emitcode ("lcall", "__gptrput");
10911           if (size || pi)
10912             emitcode ("inc", "dptr");
10913         }
10914     }
10915
10916   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10917     aopPut (result, "dpl", 0);
10918     aopPut (result, "dph", 1);
10919     pi->generated=1;
10920   }
10921   freeAsmop (result, NULL, ic, TRUE);
10922   freeAsmop (right, NULL, ic, TRUE);
10923 }
10924
10925 /*-----------------------------------------------------------------*/
10926 /* genPointerSet - stores the value into a pointer location        */
10927 /*-----------------------------------------------------------------*/
10928 static void
10929 genPointerSet (iCode * ic, iCode *pi)
10930 {
10931   operand *right, *result;
10932   sym_link *type, *etype;
10933   int p_type;
10934
10935   D (emitcode (";", "genPointerSet"));
10936
10937   right = IC_RIGHT (ic);
10938   result = IC_RESULT (ic);
10939
10940   /* depending on the type of pointer we need to
10941      move it to the correct pointer register */
10942   type = operandType (result);
10943   etype = getSpec (type);
10944   /* if left is of type of pointer then it is simple */
10945   if (IS_PTR (type) && !IS_FUNC (type->next))
10946     {
10947       p_type = DCL_TYPE (type);
10948     }
10949   else
10950     {
10951       /* we have to go by the storage class */
10952       p_type = PTR_TYPE (SPEC_OCLS (etype));
10953     }
10954
10955   /* special case when cast remat */
10956   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10957       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10958           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10959           type = operandType (result);
10960           p_type = DCL_TYPE (type);
10961   }
10962
10963   /* now that we have the pointer type we assign
10964      the pointer values */
10965   switch (p_type)
10966     {
10967
10968     case POINTER:
10969     case IPOINTER:
10970       genNearPointerSet (right, result, ic, pi);
10971       break;
10972
10973     case PPOINTER:
10974       genPagedPointerSet (right, result, ic, pi);
10975       break;
10976
10977     case FPOINTER:
10978       genFarPointerSet (right, result, ic, pi);
10979       break;
10980
10981     case GPOINTER:
10982       genGenPointerSet (right, result, ic, pi);
10983       break;
10984
10985     default:
10986       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10987               "genPointerSet: illegal pointer type");
10988     }
10989 }
10990
10991 /*-----------------------------------------------------------------*/
10992 /* genIfx - generate code for Ifx statement                        */
10993 /*-----------------------------------------------------------------*/
10994 static void
10995 genIfx (iCode * ic, iCode * popIc)
10996 {
10997   operand *cond = IC_COND (ic);
10998   int isbit = 0;
10999   char *dup = NULL;
11000
11001   D (emitcode (";", "genIfx"));
11002
11003   aopOp (cond, ic, FALSE);
11004
11005   /* get the value into acc */
11006   if (AOP_TYPE (cond) != AOP_CRY)
11007     {
11008       toBoolean (cond);
11009     }
11010   else
11011     {
11012       isbit = 1;
11013       if (AOP(cond)->aopu.aop_dir)
11014         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11015     }
11016
11017   /* the result is now in the accumulator or a directly addressable bit */
11018   freeAsmop (cond, NULL, ic, TRUE);
11019
11020   /* if there was something to be popped then do it */
11021   if (popIc)
11022     genIpop (popIc);
11023
11024   /* if the condition is a bit variable */
11025   if (isbit && dup)
11026     genIfxJump(ic, dup, NULL, NULL, NULL);
11027   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11028     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
11029   else if (isbit && !IS_ITEMP (cond))
11030     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
11031   else
11032     genIfxJump (ic, "a", NULL, NULL, NULL);
11033
11034   ic->generated = 1;
11035 }
11036
11037 /*-----------------------------------------------------------------*/
11038 /* genAddrOf - generates code for address of                       */
11039 /*-----------------------------------------------------------------*/
11040 static void
11041 genAddrOf (iCode * ic)
11042 {
11043   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11044   int size, offset;
11045
11046   D (emitcode (";", "genAddrOf"));
11047
11048   aopOp (IC_RESULT (ic), ic, FALSE);
11049
11050   /* if the operand is on the stack then we
11051      need to get the stack offset of this
11052      variable */
11053   if (sym->onStack)
11054     {
11055       /* if it has an offset then we need to compute it */
11056       if (sym->stack)
11057         {
11058           int stack_offset = ((sym->stack < 0) ?
11059                               ((char) (sym->stack - _G.nRegsSaved)) :
11060                               ((char) sym->stack)) & 0xff;
11061           if ((abs(stack_offset) == 1) &&
11062               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11063               !isOperandVolatile (IC_RESULT (ic), FALSE))
11064             {
11065               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11066               if (stack_offset > 0)
11067                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11068               else
11069                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11070             }
11071           else
11072             {
11073               emitcode ("mov", "a,%s", SYM_BP (sym));
11074               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11075               aopPut (IC_RESULT (ic), "a", 0);
11076             }
11077         }
11078       else
11079         {
11080           /* we can just move _bp */
11081           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11082         }
11083       /* fill the result with zero */
11084       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11085
11086       offset = 1;
11087       while (size--)
11088         {
11089           aopPut (IC_RESULT (ic), zero, offset++);
11090         }
11091       goto release;
11092     }
11093
11094   /* object not on stack then we need the name */
11095   size = AOP_SIZE (IC_RESULT (ic));
11096   offset = 0;
11097
11098   while (size--)
11099     {
11100       char s[SDCC_NAME_MAX];
11101       if (offset)
11102         sprintf (s, "#(%s >> %d)",
11103                  sym->rname,
11104                  offset * 8);
11105       else
11106         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11107       aopPut (IC_RESULT (ic), s, offset++);
11108     }
11109
11110 release:
11111   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11112
11113 }
11114
11115 /*-----------------------------------------------------------------*/
11116 /* genFarFarAssign - assignment when both are in far space         */
11117 /*-----------------------------------------------------------------*/
11118 static void
11119 genFarFarAssign (operand * result, operand * right, iCode * ic)
11120 {
11121   int size = AOP_SIZE (right);
11122   int offset = 0;
11123   char *l;
11124
11125   D (emitcode (";", "genFarFarAssign"));
11126
11127   /* first push the right side on to the stack */
11128   while (size--)
11129     {
11130       l = aopGet (right, offset++, FALSE, FALSE);
11131       MOVA (l);
11132       emitcode ("push", "acc");
11133     }
11134
11135   freeAsmop (right, NULL, ic, FALSE);
11136   /* now assign DPTR to result */
11137   aopOp (result, ic, FALSE);
11138   size = AOP_SIZE (result);
11139   while (size--)
11140     {
11141       emitcode ("pop", "acc");
11142       aopPut (result, "a", --offset);
11143     }
11144   freeAsmop (result, NULL, ic, FALSE);
11145 }
11146
11147 /*-----------------------------------------------------------------*/
11148 /* genAssign - generate code for assignment                        */
11149 /*-----------------------------------------------------------------*/
11150 static void
11151 genAssign (iCode * ic)
11152 {
11153   operand *result, *right;
11154   int size, offset;
11155   unsigned long lit = 0L;
11156
11157   D (emitcode (";", "genAssign"));
11158
11159   result = IC_RESULT (ic);
11160   right = IC_RIGHT (ic);
11161
11162   /* if they are the same */
11163   if (operandsEqu (result, right) &&
11164       !isOperandVolatile (result, FALSE) &&
11165       !isOperandVolatile (right, FALSE))
11166     return;
11167
11168   aopOp (right, ic, FALSE);
11169
11170   /* special case both in far space */
11171   if (AOP_TYPE (right) == AOP_DPTR &&
11172       IS_TRUE_SYMOP (result) &&
11173       isOperandInFarSpace (result))
11174     {
11175       genFarFarAssign (result, right, ic);
11176       return;
11177     }
11178
11179   aopOp (result, ic, TRUE);
11180
11181   /* if they are the same registers */
11182   if (sameRegs (AOP (right), AOP (result)) &&
11183       !isOperandVolatile (result, FALSE) &&
11184       !isOperandVolatile (right, FALSE))
11185     goto release;
11186
11187   /* if the result is a bit */
11188   if (AOP_TYPE (result) == AOP_CRY)
11189     {
11190       assignBit (result, right);
11191       goto release;
11192     }
11193
11194   /* bit variables done */
11195   /* general case */
11196   size = AOP_SIZE (result);
11197   offset = 0;
11198   if (AOP_TYPE (right) == AOP_LIT)
11199     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11200
11201   if ((size > 1) &&
11202       (AOP_TYPE (result) != AOP_REG) &&
11203       (AOP_TYPE (right) == AOP_LIT) &&
11204       !IS_FLOAT (operandType (right)) &&
11205       (lit < 256L))
11206     {
11207       while ((size) && (lit))
11208         {
11209           aopPut (result,
11210                   aopGet (right, offset, FALSE, FALSE),
11211                   offset);
11212           lit >>= 8;
11213           offset++;
11214           size--;
11215         }
11216       /* And now fill the rest with zeros. */
11217       if (size)
11218         {
11219           emitcode ("clr", "a");
11220         }
11221       while (size--)
11222         {
11223           aopPut (result, "a", offset);
11224           offset++;
11225         }
11226     }
11227   else
11228     {
11229       while (size--)
11230         {
11231           aopPut (result,
11232                   aopGet (right, offset, FALSE, FALSE),
11233                   offset);
11234           offset++;
11235         }
11236     }
11237
11238 release:
11239   freeAsmop (result, NULL, ic, TRUE);
11240   freeAsmop (right, NULL, ic, TRUE);
11241 }
11242
11243 /*-----------------------------------------------------------------*/
11244 /* genJumpTab - generates code for jump table                      */
11245 /*-----------------------------------------------------------------*/
11246 static void
11247 genJumpTab (iCode * ic)
11248 {
11249   symbol *jtab,*jtablo,*jtabhi;
11250   char *l;
11251   unsigned int count;
11252
11253   D (emitcode (";", "genJumpTab"));
11254
11255   count = elementsInSet( IC_JTLABELS (ic) );
11256
11257   if( count <= 16 )
11258     {
11259       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11260          if the switch argument is in a register.
11261          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11262       /* Peephole may not convert ljmp to sjmp or ret
11263          labelIsReturnOnly & labelInRange must check
11264          currPl->ic->op != JUMPTABLE */
11265       aopOp (IC_JTCOND (ic), ic, FALSE);
11266       /* get the condition into accumulator */
11267       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11268       MOVA (l);
11269       /* multiply by three */
11270       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11271         {
11272           emitcode ("mov", "b,#3");
11273           emitcode ("mul", "ab");
11274         }
11275       else
11276         {
11277           emitcode ("add", "a,acc");
11278           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11279         }
11280       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11281
11282       jtab = newiTempLabel (NULL);
11283       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11284       emitcode ("jmp", "@a+dptr");
11285       emitLabel (jtab);
11286       /* now generate the jump labels */
11287       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11288            jtab = setNextItem (IC_JTLABELS (ic)))
11289         emitcode ("ljmp", "%05d$", jtab->key + 100);
11290     }
11291   else
11292     {
11293       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11294          if the switch argument is in a register.
11295          For n>6 this algorithm may be more compact */
11296       jtablo = newiTempLabel (NULL);
11297       jtabhi = newiTempLabel (NULL);
11298
11299       /* get the condition into accumulator.
11300          Using b as temporary storage, if register push/pop is needed */
11301       aopOp (IC_JTCOND (ic), ic, FALSE);
11302       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11303       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11304           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11305         {
11306           // (MB) what if B is in use???
11307           wassertl(!BINUSE, "B was in use");
11308           emitcode ("mov", "b,%s", l);
11309           l = "b";
11310         }
11311       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11312       MOVA (l);
11313       if( count <= 112 )
11314         {
11315           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11316           emitcode ("movc", "a,@a+pc");
11317           emitcode ("push", "acc");
11318
11319           MOVA (l);
11320           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11321           emitcode ("movc", "a,@a+pc");
11322           emitcode ("push", "acc");
11323         }
11324       else
11325         {
11326           /* this scales up to n<=255, but needs two more bytes
11327              and changes dptr */
11328           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11329           emitcode ("movc", "a,@a+dptr");
11330           emitcode ("push", "acc");
11331
11332           MOVA (l);
11333           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11334           emitcode ("movc", "a,@a+dptr");
11335           emitcode ("push", "acc");
11336         }
11337
11338       emitcode ("ret", "");
11339
11340       /* now generate jump table, LSB */
11341       emitLabel (jtablo);
11342       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11343            jtab = setNextItem (IC_JTLABELS (ic)))
11344         emitcode (".db", "%05d$", jtab->key + 100);
11345
11346       /* now generate jump table, MSB */
11347       emitLabel (jtabhi);
11348       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11349            jtab = setNextItem (IC_JTLABELS (ic)))
11350          emitcode (".db", "%05d$>>8", jtab->key + 100);
11351     }
11352 }
11353
11354 /*-----------------------------------------------------------------*/
11355 /* genCast - gen code for casting                                  */
11356 /*-----------------------------------------------------------------*/
11357 static void
11358 genCast (iCode * ic)
11359 {
11360   operand *result = IC_RESULT (ic);
11361   sym_link *ctype = operandType (IC_LEFT (ic));
11362   sym_link *rtype = operandType (IC_RIGHT (ic));
11363   operand *right = IC_RIGHT (ic);
11364   int size, offset;
11365
11366   D (emitcode (";", "genCast"));
11367
11368   /* if they are equivalent then do nothing */
11369   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11370     return;
11371
11372   aopOp (right, ic, FALSE);
11373   aopOp (result, ic, FALSE);
11374
11375   /* if the result is a bit (and not a bitfield) */
11376   if (IS_BIT (OP_SYMBOL (result)->type))
11377     {
11378       assignBit (result, right);
11379       goto release;
11380     }
11381
11382   /* if they are the same size : or less */
11383   if (AOP_SIZE (result) <= AOP_SIZE (right))
11384     {
11385
11386       /* if they are in the same place */
11387       if (sameRegs (AOP (right), AOP (result)))
11388         goto release;
11389
11390       /* if they in different places then copy */
11391       size = AOP_SIZE (result);
11392       offset = 0;
11393       while (size--)
11394         {
11395           aopPut (result,
11396                   aopGet (right, offset, FALSE, FALSE),
11397                   offset);
11398           offset++;
11399         }
11400       goto release;
11401     }
11402
11403   /* if the result is of type pointer */
11404   if (IS_PTR (ctype))
11405     {
11406
11407       int p_type;
11408       sym_link *type = operandType (right);
11409       sym_link *etype = getSpec (type);
11410
11411       /* pointer to generic pointer */
11412       if (IS_GENPTR (ctype))
11413         {
11414           if (IS_PTR (type))
11415             {
11416               p_type = DCL_TYPE (type);
11417             }
11418           else
11419             {
11420               if (SPEC_SCLS(etype)==S_REGISTER) {
11421                 // let's assume it is a generic pointer
11422                 p_type=GPOINTER;
11423               } else {
11424                 /* we have to go by the storage class */
11425                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11426               }
11427             }
11428
11429           /* the first two bytes are known */
11430           size = GPTRSIZE - 1;
11431           offset = 0;
11432           while (size--)
11433             {
11434               aopPut (result,
11435                       aopGet (right, offset, FALSE, FALSE),
11436                       offset);
11437               offset++;
11438             }
11439           /* the last byte depending on type */
11440             {
11441                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11442                 char gpValStr[10];
11443
11444                 if (gpVal == -1)
11445                 {
11446                     // pointerTypeToGPByte will have bitched.
11447                     exit(1);
11448                 }
11449
11450                 sprintf(gpValStr, "#0x%x", gpVal);
11451                 aopPut (result, gpValStr, GPTRSIZE - 1);
11452             }
11453           goto release;
11454         }
11455
11456       /* just copy the pointers */
11457       size = AOP_SIZE (result);
11458       offset = 0;
11459       while (size--)
11460         {
11461           aopPut (result,
11462                   aopGet (right, offset, FALSE, FALSE),
11463                   offset);
11464           offset++;
11465         }
11466       goto release;
11467     }
11468
11469   /* so we now know that the size of destination is greater
11470      than the size of the source */
11471   /* we move to result for the size of source */
11472   size = AOP_SIZE (right);
11473   offset = 0;
11474   while (size--)
11475     {
11476       aopPut (result,
11477               aopGet (right, offset, FALSE, FALSE),
11478               offset);
11479       offset++;
11480     }
11481
11482   /* now depending on the sign of the source && destination */
11483   size = AOP_SIZE (result) - AOP_SIZE (right);
11484   /* if unsigned or not an integral type */
11485   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11486     {
11487       while (size--)
11488         aopPut (result, zero, offset++);
11489     }
11490   else
11491     {
11492       /* we need to extend the sign :{ */
11493       char *l = aopGet (right, AOP_SIZE (right) - 1,
11494                         FALSE, FALSE);
11495       MOVA (l);
11496       emitcode ("rlc", "a");
11497       emitcode ("subb", "a,acc");
11498       while (size--)
11499         aopPut (result, "a", offset++);
11500     }
11501
11502   /* we are done hurray !!!! */
11503
11504 release:
11505   freeAsmop (result, NULL, ic, TRUE);
11506   freeAsmop (right, NULL, ic, TRUE);
11507 }
11508
11509 /*-----------------------------------------------------------------*/
11510 /* genDjnz - generate decrement & jump if not zero instrucion      */
11511 /*-----------------------------------------------------------------*/
11512 static int
11513 genDjnz (iCode * ic, iCode * ifx)
11514 {
11515   symbol *lbl, *lbl1;
11516   if (!ifx)
11517     return 0;
11518
11519   /* if the if condition has a false label
11520      then we cannot save */
11521   if (IC_FALSE (ifx))
11522     return 0;
11523
11524   /* if the minus is not of the form a = a - 1 */
11525   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11526       !IS_OP_LITERAL (IC_RIGHT (ic)))
11527     return 0;
11528
11529   if (operandLitValue (IC_RIGHT (ic)) != 1)
11530     return 0;
11531
11532   /* if the size of this greater than one then no
11533      saving */
11534   if (getSize (operandType (IC_RESULT (ic))) > 1)
11535     return 0;
11536
11537   /* otherwise we can save BIG */
11538
11539   D (emitcode (";", "genDjnz"));
11540
11541   lbl = newiTempLabel (NULL);
11542   lbl1 = newiTempLabel (NULL);
11543
11544   aopOp (IC_RESULT (ic), ic, FALSE);
11545
11546   if (AOP_NEEDSACC(IC_RESULT(ic)))
11547   {
11548       /* If the result is accessed indirectly via
11549        * the accumulator, we must explicitly write
11550        * it back after the decrement.
11551        */
11552       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11553
11554       if (strcmp(rByte, "a"))
11555       {
11556            /* Something is hopelessly wrong */
11557            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11558                    __FILE__, __LINE__);
11559            /* We can just give up; the generated code will be inefficient,
11560             * but what the hey.
11561             */
11562            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11563            return 0;
11564       }
11565       emitcode ("dec", "%s", rByte);
11566       aopPut (IC_RESULT (ic), rByte, 0);
11567       emitcode ("jnz", "%05d$", lbl->key + 100);
11568   }
11569   else if (IS_AOP_PREG (IC_RESULT (ic)))
11570     {
11571       emitcode ("dec", "%s",
11572                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11573       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11574       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11575       ifx->generated = 1;
11576       emitcode ("jnz", "%05d$", lbl->key + 100);
11577     }
11578   else
11579     {
11580       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11581                 lbl->key + 100);
11582     }
11583   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11584   emitLabel (lbl);
11585   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11586   emitLabel (lbl1);
11587
11588   if (!ifx->generated)
11589       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11590   ifx->generated = 1;
11591   return 1;
11592 }
11593
11594 /*-----------------------------------------------------------------*/
11595 /* genReceive - generate code for a receive iCode                  */
11596 /*-----------------------------------------------------------------*/
11597 static void
11598 genReceive (iCode * ic)
11599 {
11600   int size = getSize (operandType (IC_RESULT (ic)));
11601   int offset = 0;
11602
11603   D (emitcode (";", "genReceive"));
11604
11605   if (ic->argreg == 1)
11606     { /* first parameter */
11607       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11608            isOperandInPagedSpace (IC_RESULT (ic))) &&
11609           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11610            IS_TRUE_SYMOP (IC_RESULT (ic))))
11611         {
11612           regs *tempRegs[4];
11613           int receivingA = 0;
11614           int roffset = 0;
11615
11616           for (offset = 0; offset<size; offset++)
11617             if (!strcmp (fReturn[offset], "a"))
11618               receivingA = 1;
11619
11620           if (!receivingA)
11621             {
11622               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11623                 {
11624                   for (offset = size-1; offset>0; offset--)
11625                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11626                   emitcode("mov","a,%s", fReturn[0]);
11627                   _G.accInUse++;
11628                   aopOp (IC_RESULT (ic), ic, FALSE);
11629                   _G.accInUse--;
11630                   aopPut (IC_RESULT (ic), "a", offset);
11631                   for (offset = 1; offset<size; offset++)
11632                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11633                   goto release;
11634                 }
11635             }
11636           else
11637             {
11638               if (getTempRegs(tempRegs, size, ic))
11639                 {
11640                   for (offset = 0; offset<size; offset++)
11641                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11642                   aopOp (IC_RESULT (ic), ic, FALSE);
11643                   for (offset = 0; offset<size; offset++)
11644                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11645                   goto release;
11646                 }
11647             }
11648
11649           offset = fReturnSizeMCS51 - size;
11650           while (size--)
11651             {
11652               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11653                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11654               offset++;
11655             }
11656           aopOp (IC_RESULT (ic), ic, FALSE);
11657           size = AOP_SIZE (IC_RESULT (ic));
11658           offset = 0;
11659           while (size--)
11660             {
11661               emitcode ("pop", "acc");
11662               aopPut (IC_RESULT (ic), "a", offset++);
11663             }
11664         }
11665       else
11666         {
11667           _G.accInUse++;
11668           aopOp (IC_RESULT (ic), ic, FALSE);
11669           _G.accInUse--;
11670           assignResultValue (IC_RESULT (ic), NULL);
11671         }
11672     }
11673   else if (ic->argreg > 12)
11674     { /* bit parameters */
11675       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11676
11677       BitBankUsed = 1;
11678       if (!reg || reg->rIdx != ic->argreg-5)
11679         {
11680           aopOp (IC_RESULT (ic), ic, FALSE);
11681           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11682           outBitC(IC_RESULT (ic));
11683         }
11684     }
11685   else
11686     { /* other parameters */
11687       int rb1off ;
11688       aopOp (IC_RESULT (ic), ic, FALSE);
11689       rb1off = ic->argreg;
11690       while (size--)
11691         {
11692           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11693         }
11694     }
11695
11696 release:
11697   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11698 }
11699
11700 /*-----------------------------------------------------------------*/
11701 /* genDummyRead - generate code for dummy read of volatiles        */
11702 /*-----------------------------------------------------------------*/
11703 static void
11704 genDummyRead (iCode * ic)
11705 {
11706   operand *op;
11707   int size, offset;
11708
11709   D (emitcode(";", "genDummyRead"));
11710
11711   op = IC_RIGHT (ic);
11712   if (op && IS_SYMOP (op))
11713     {
11714       aopOp (op, ic, FALSE);
11715
11716       /* if the result is a bit */
11717       if (AOP_TYPE (op) == AOP_CRY)
11718         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11719       else
11720         {
11721           /* bit variables done */
11722           /* general case */
11723           size = AOP_SIZE (op);
11724           offset = 0;
11725           while (size--)
11726           {
11727             MOVA (aopGet (op, offset, FALSE, FALSE));
11728             offset++;
11729           }
11730         }
11731
11732       freeAsmop (op, NULL, ic, TRUE);
11733     }
11734
11735   op = IC_LEFT (ic);
11736   if (op && IS_SYMOP (op))
11737     {
11738       aopOp (op, ic, FALSE);
11739
11740       /* if the result is a bit */
11741       if (AOP_TYPE (op) == AOP_CRY)
11742         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11743       else
11744         {
11745           /* bit variables done */
11746           /* general case */
11747           size = AOP_SIZE (op);
11748           offset = 0;
11749           while (size--)
11750           {
11751             MOVA (aopGet (op, offset, FALSE, FALSE));
11752             offset++;
11753           }
11754         }
11755
11756       freeAsmop (op, NULL, ic, TRUE);
11757     }
11758 }
11759
11760 /*-----------------------------------------------------------------*/
11761 /* genCritical - generate code for start of a critical sequence    */
11762 /*-----------------------------------------------------------------*/
11763 static void
11764 genCritical (iCode *ic)
11765 {
11766   symbol *tlbl = newiTempLabel (NULL);
11767
11768   D (emitcode(";", "genCritical"));
11769
11770   if (IC_RESULT (ic))
11771     {
11772       aopOp (IC_RESULT (ic), ic, TRUE);
11773       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11774       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11775       aopPut (IC_RESULT (ic), zero, 0);
11776       emitLabel (tlbl);
11777       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11778     }
11779   else
11780     {
11781       emitcode ("setb", "c");
11782       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11783       emitcode ("clr", "c");
11784       emitLabel (tlbl);
11785       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11786     }
11787 }
11788
11789 /*-----------------------------------------------------------------*/
11790 /* genEndCritical - generate code for end of a critical sequence   */
11791 /*-----------------------------------------------------------------*/
11792 static void
11793 genEndCritical (iCode *ic)
11794 {
11795   D(emitcode(";", "genEndCritical"));
11796
11797   if (IC_RIGHT (ic))
11798     {
11799       aopOp (IC_RIGHT (ic), ic, FALSE);
11800       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11801         {
11802           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11803           emitcode ("mov", "ea,c");
11804         }
11805       else
11806         {
11807           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11808             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11809           emitcode ("rrc", "a");
11810           emitcode ("mov", "ea,c");
11811         }
11812       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11813     }
11814   else
11815     {
11816       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11817       emitcode ("mov", "ea,c");
11818     }
11819 }
11820
11821 /*-----------------------------------------------------------------*/
11822 /* gen51Code - generate code for 8051 based controllers            */
11823 /*-----------------------------------------------------------------*/
11824 void
11825 gen51Code (iCode * lic)
11826 {
11827   iCode *ic;
11828   int cln = 0;
11829   /* int cseq = 0; */
11830
11831   _G.currentFunc = NULL;
11832   lineHead = lineCurr = NULL;
11833
11834   /* print the allocation information */
11835   if (allocInfo && currFunc)
11836     printAllocInfo (currFunc, codeOutBuf);
11837   /* if debug information required */
11838   if (options.debug && currFunc)
11839     {
11840       debugFile->writeFunction (currFunc, lic);
11841     }
11842   /* stack pointer name */
11843   if (options.useXstack)
11844     spname = "_spx";
11845   else
11846     spname = "sp";
11847
11848
11849   for (ic = lic; ic; ic = ic->next)
11850     {
11851       _G.current_iCode = ic;
11852
11853       if (ic->lineno && cln != ic->lineno)
11854         {
11855           if (options.debug)
11856             {
11857               debugFile->writeCLine (ic);
11858             }
11859           if (!options.noCcodeInAsm) {
11860             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11861                       printCLine(ic->filename, ic->lineno));
11862           }
11863           cln = ic->lineno;
11864         }
11865       #if 0
11866       if (ic->seqPoint && ic->seqPoint != cseq)
11867         {
11868           emitcode (";", "sequence point %d", ic->seqPoint);
11869           cseq = ic->seqPoint;
11870         }
11871       #endif
11872       if (options.iCodeInAsm) {
11873         char regsInUse[80];
11874         int i;
11875         const char *iLine;
11876
11877         #if 0
11878         for (i=0; i<8; i++) {
11879           sprintf (&regsInUse[i],
11880                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11881         regsInUse[i]=0;
11882         #else
11883         strcpy (regsInUse, "--------");
11884         for (i=0; i < 8; i++) {
11885           if (bitVectBitValue (ic->rMask, i))
11886             {
11887               int offset = regs8051[i].offset;
11888               regsInUse[offset] = offset + '0'; /* show rMask */
11889             }
11890         #endif
11891         }
11892         iLine = printILine(ic);
11893         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11894         dbuf_free(iLine);
11895       }
11896       /* if the result is marked as
11897          spilt and rematerializable or code for
11898          this has already been generated then
11899          do nothing */
11900       if (resultRemat (ic) || ic->generated)
11901         continue;
11902
11903       /* depending on the operation */
11904       switch (ic->op)
11905         {
11906         case '!':
11907           genNot (ic);
11908           break;
11909
11910         case '~':
11911           genCpl (ic);
11912           break;
11913
11914         case UNARYMINUS:
11915           genUminus (ic);
11916           break;
11917
11918         case IPUSH:
11919           genIpush (ic);
11920           break;
11921
11922         case IPOP:
11923           /* IPOP happens only when trying to restore a
11924              spilt live range, if there is an ifx statement
11925              following this pop then the if statement might
11926              be using some of the registers being popped which
11927              would destory the contents of the register so
11928              we need to check for this condition and handle it */
11929           if (ic->next &&
11930               ic->next->op == IFX &&
11931               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11932             genIfx (ic->next, ic);
11933           else
11934             genIpop (ic);
11935           break;
11936
11937         case CALL:
11938           genCall (ic);
11939           break;
11940
11941         case PCALL:
11942           genPcall (ic);
11943           break;
11944
11945         case FUNCTION:
11946           genFunction (ic);
11947           break;
11948
11949         case ENDFUNCTION:
11950           genEndFunction (ic);
11951           break;
11952
11953         case RETURN:
11954           genRet (ic);
11955           break;
11956
11957         case LABEL:
11958           genLabel (ic);
11959           break;
11960
11961         case GOTO:
11962           genGoto (ic);
11963           break;
11964
11965         case '+':
11966           genPlus (ic);
11967           break;
11968
11969         case '-':
11970           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11971             genMinus (ic);
11972           break;
11973
11974         case '*':
11975           genMult (ic);
11976           break;
11977
11978         case '/':
11979           genDiv (ic);
11980           break;
11981
11982         case '%':
11983           genMod (ic);
11984           break;
11985
11986         case '>':
11987           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11988           break;
11989
11990         case '<':
11991           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11992           break;
11993
11994         case LE_OP:
11995         case GE_OP:
11996         case NE_OP:
11997
11998           /* note these two are xlated by algebraic equivalence
11999              in decorateType() in SDCCast.c */
12000           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12001                   "got '>=' or '<=' shouldn't have come here");
12002           break;
12003
12004         case EQ_OP:
12005           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
12006           break;
12007
12008         case AND_OP:
12009           genAndOp (ic);
12010           break;
12011
12012         case OR_OP:
12013           genOrOp (ic);
12014           break;
12015
12016         case '^':
12017           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
12018           break;
12019
12020         case '|':
12021           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
12022           break;
12023
12024         case BITWISEAND:
12025           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
12026           break;
12027
12028         case INLINEASM:
12029           genInline (ic);
12030           break;
12031
12032         case RRC:
12033           genRRC (ic);
12034           break;
12035
12036         case RLC:
12037           genRLC (ic);
12038           break;
12039
12040         case GETHBIT:
12041           genGetHbit (ic);
12042           break;
12043
12044         case GETABIT:
12045           genGetAbit (ic);
12046           break;
12047
12048         case GETBYTE:
12049           genGetByte (ic);
12050           break;
12051
12052         case GETWORD:
12053           genGetWord (ic);
12054           break;
12055
12056         case LEFT_OP:
12057           genLeftShift (ic);
12058           break;
12059
12060         case RIGHT_OP:
12061           genRightShift (ic);
12062           break;
12063
12064         case GET_VALUE_AT_ADDRESS:
12065           genPointerGet (ic,
12066                          hasInc (IC_LEFT (ic), ic,
12067                                  getSize (operandType (IC_RESULT (ic)))),
12068                          ifxForOp (IC_RESULT (ic), ic) );
12069           break;
12070
12071         case '=':
12072           if (POINTER_SET (ic))
12073             genPointerSet (ic,
12074                            hasInc (IC_RESULT (ic), ic,
12075                                    getSize (operandType (IC_RIGHT (ic)))));
12076           else
12077             genAssign (ic);
12078           break;
12079
12080         case IFX:
12081           genIfx (ic, NULL);
12082           break;
12083
12084         case ADDRESS_OF:
12085           genAddrOf (ic);
12086           break;
12087
12088         case JUMPTABLE:
12089           genJumpTab (ic);
12090           break;
12091
12092         case CAST:
12093           genCast (ic);
12094           break;
12095
12096         case RECEIVE:
12097           genReceive (ic);
12098           break;
12099
12100         case SEND:
12101           addSet (&_G.sendSet, ic);
12102           break;
12103
12104         case DUMMY_READ_VOLATILE:
12105           genDummyRead (ic);
12106           break;
12107
12108         case CRITICAL:
12109           genCritical (ic);
12110           break;
12111
12112         case ENDCRITICAL:
12113           genEndCritical (ic);
12114           break;
12115
12116         case SWAP:
12117           genSwap (ic);
12118           break;
12119
12120         default:
12121           ic = ic;
12122         }
12123     }
12124
12125   _G.current_iCode = NULL;
12126
12127   /* now we are ready to call the
12128      peep hole optimizer */
12129   if (!options.nopeep)
12130     peepHole (&lineHead);
12131
12132   /* now do the actual printing */
12133   printLine (lineHead, codeOutBuf);
12134   return;
12135 }