f4016b7510b425d19bc5c4de1ddafa3f905dfba9
[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 - rematerialzes 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               sym_link *from_type = operandType(IC_RIGHT(ic));
733               aop->aopu.aop_immd.from_cast_remat = 1;
734               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
735               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
736               continue;
737       } else break;
738
739       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
740     }
741
742   if (val)
743     {
744       SNPRINTF (buffer, sizeof(buffer),
745                 "(%s %c 0x%04x)",
746                 OP_SYMBOL (IC_LEFT (ic))->rname,
747                 val >= 0 ? '+' : '-',
748                 abs (val) & 0xffff);
749     }
750   else
751     {
752       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
753     }
754
755   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
756   /* set immd2 field if required */
757   if (aop->aopu.aop_immd.from_cast_remat)
758     {
759       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
760       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
761     }
762
763   return aop;
764 }
765
766 /*-----------------------------------------------------------------*/
767 /* regsInCommon - two operands have some registers in common       */
768 /*-----------------------------------------------------------------*/
769 static bool
770 regsInCommon (operand * op1, operand * op2)
771 {
772   symbol *sym1, *sym2;
773   int i;
774
775   /* if they have registers in common */
776   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
777     return FALSE;
778
779   sym1 = OP_SYMBOL (op1);
780   sym2 = OP_SYMBOL (op2);
781
782   if (sym1->nRegs == 0 || sym2->nRegs == 0)
783     return FALSE;
784
785   for (i = 0; i < sym1->nRegs; i++)
786     {
787       int j;
788       if (!sym1->regs[i])
789         continue;
790
791       for (j = 0; j < sym2->nRegs; j++)
792         {
793           if (!sym2->regs[j])
794             continue;
795
796           if (sym2->regs[j] == sym1->regs[i])
797             return TRUE;
798         }
799     }
800
801   return FALSE;
802 }
803
804 /*-----------------------------------------------------------------*/
805 /* operandsEqu - equivalent                                        */
806 /*-----------------------------------------------------------------*/
807 static bool
808 operandsEqu (operand * op1, operand * op2)
809 {
810   symbol *sym1, *sym2;
811
812   /* if they're not symbols */
813   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
814     return FALSE;
815
816   sym1 = OP_SYMBOL (op1);
817   sym2 = OP_SYMBOL (op2);
818
819   /* if both are itemps & one is spilt
820      and the other is not then false */
821   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
822       sym1->isspilt != sym2->isspilt)
823     return FALSE;
824
825   /* if they are the same */
826   if (sym1 == sym2)
827     return TRUE;
828
829   /* if they have the same rname */
830   if (sym1->rname[0] && sym2->rname[0] &&
831       strcmp (sym1->rname, sym2->rname) == 0 &&
832       !(IS_PARM (op2) && IS_ITEMP (op1)))
833     return TRUE;
834
835   /* if left is a tmp & right is not */
836   if (IS_ITEMP (op1) &&
837       !IS_ITEMP (op2) &&
838       sym1->isspilt &&
839       (sym1->usl.spillLoc == sym2))
840     return TRUE;
841
842   if (IS_ITEMP (op2) &&
843       !IS_ITEMP (op1) &&
844       sym2->isspilt &&
845       sym1->level > 0 &&
846       (sym2->usl.spillLoc == sym1))
847     return TRUE;
848
849   return FALSE;
850 }
851
852 /*-----------------------------------------------------------------*/
853 /* sameByte - two asmops have the same address at given offsets    */
854 /*-----------------------------------------------------------------*/
855 static bool
856 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
857 {
858   if (aop1 == aop2 && off1 == off2)
859     return TRUE;
860
861   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
862     return FALSE;
863
864   if (aop1->type != aop2->type)
865     return FALSE;
866
867   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
868     return FALSE;
869
870   return TRUE;
871 }
872
873 /*-----------------------------------------------------------------*/
874 /* sameRegs - two asmops have the same registers                   */
875 /*-----------------------------------------------------------------*/
876 static bool
877 sameRegs (asmop * aop1, asmop * aop2)
878 {
879   int i;
880
881   if (aop1 == aop2)
882     return TRUE;
883
884   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
885     return FALSE;
886
887   if (aop1->type != aop2->type)
888     return FALSE;
889
890   if (aop1->size != aop2->size)
891     return FALSE;
892
893   for (i = 0; i < aop1->size; i++)
894     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
895       return FALSE;
896
897   return TRUE;
898 }
899
900 /*-----------------------------------------------------------------*/
901 /* aopOp - allocates an asmop for an operand  :                    */
902 /*-----------------------------------------------------------------*/
903 static void
904 aopOp (operand * op, iCode * ic, bool result)
905 {
906   asmop *aop;
907   symbol *sym;
908   int i;
909
910   if (!op)
911     return;
912
913   /* if this a literal */
914   if (IS_OP_LITERAL (op))
915     {
916       op->aop = aop = newAsmop (AOP_LIT);
917       aop->aopu.aop_lit = op->operand.valOperand;
918       aop->size = getSize (operandType (op));
919       return;
920     }
921
922   /* if already has a asmop then continue */
923   if (op->aop)
924     {
925       op->aop->allocated++;
926       return;
927     }
928
929   /* if the underlying symbol has a aop */
930   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
931     {
932       op->aop = OP_SYMBOL (op)->aop;
933       op->aop->allocated++;
934       return;
935     }
936
937   /* if this is a true symbol */
938   if (IS_TRUE_SYMOP (op))
939     {
940       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
941       return;
942     }
943
944   /* this is a temporary : this has
945      only five choices :
946      a) register
947      b) spillocation
948      c) rematerialize
949      d) conditional
950      e) can be a return use only */
951
952   sym = OP_SYMBOL (op);
953
954   /* if the type is a conditional */
955   if (sym->regType == REG_CND)
956     {
957       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
958       aop->size = sym->ruonly ? 1 : 0;
959       return;
960     }
961
962   /* if it is spilt then two situations
963      a) is rematerialize
964      b) has a spill location */
965   if (sym->isspilt || sym->nRegs == 0)
966     {
967
968       /* rematerialize it NOW */
969       if (sym->remat)
970         {
971           sym->aop = op->aop = aop = aopForRemat (sym);
972           aop->size = operandSize (op);
973           return;
974         }
975
976       if (sym->accuse)
977         {
978           int i;
979           sym->aop = op->aop = aop = newAsmop (AOP_ACC);
980           aop->size = getSize (sym->type);
981           for (i = 0; i < 2; i++)
982             aop->aopu.aop_str[i] = accUse[i];
983           return;
984         }
985
986       if (sym->ruonly)
987         {
988           unsigned i;
989
990           sym->aop = op->aop = aop = newAsmop (AOP_STR);
991           aop->size = getSize (sym->type);
992           for (i = 0; i < fReturnSizeMCS51; i++)
993             aop->aopu.aop_str[i] = fReturn[i];
994           return;
995         }
996
997       if (sym->usl.spillLoc)
998         {
999           asmop *oldAsmOp = NULL;
1000
1001           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1002             {
1003               /* force a new aop if sizes differ */
1004               oldAsmOp = sym->usl.spillLoc->aop;
1005               sym->usl.spillLoc->aop = NULL;
1006             }
1007           sym->aop = op->aop = aop =
1008                      aopForSym (ic, sym->usl.spillLoc, result);
1009           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1010             {
1011               /* Don't reuse the new aop, go with the last one */
1012               sym->usl.spillLoc->aop = oldAsmOp;
1013             }
1014           aop->size = getSize (sym->type);
1015           return;
1016         }
1017
1018       /* else must be a dummy iTemp */
1019       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1020       aop->size = getSize (sym->type);
1021       return;
1022     }
1023
1024   /* if the type is a bit register */
1025   if (sym->regType == REG_BIT)
1026     {
1027       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1028       aop->size = sym->nRegs;//1???
1029       aop->aopu.aop_reg[0] = sym->regs[0];
1030       aop->aopu.aop_dir = sym->regs[0]->name;
1031       return;
1032     }
1033
1034   /* must be in a register */
1035   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1036   aop->size = sym->nRegs;
1037   for (i = 0; i < sym->nRegs; i++)
1038     aop->aopu.aop_reg[i] = sym->regs[i];
1039 }
1040
1041 /*-----------------------------------------------------------------*/
1042 /* freeAsmop - free up the asmop given to an operand               */
1043 /*----------------------------------------------------------------*/
1044 static void
1045 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1046 {
1047   asmop *aop;
1048
1049   if (!op)
1050     aop = aaop;
1051   else
1052     aop = op->aop;
1053
1054   if (!aop)
1055     return;
1056
1057   aop->allocated--;
1058
1059   if (aop->allocated)
1060     goto dealloc;
1061
1062   /* depending on the asmop type only three cases need work
1063      AOP_R0, AOP_R1 & AOP_STK */
1064   switch (aop->type)
1065     {
1066     case AOP_R0:
1067       if (R0INB)
1068         {
1069           emitcode ("mov", "r0,b");
1070           R0INB--;
1071         }
1072       else if (_G.r0Pushed)
1073         {
1074           if (pop)
1075             {
1076               emitcode ("pop", "ar0");
1077               _G.r0Pushed--;
1078             }
1079         }
1080       bitVectUnSetBit (ic->rUsed, R0_IDX);
1081       break;
1082
1083     case AOP_R1:
1084       if (R1INB)
1085         {
1086           emitcode ("mov", "r1,b");
1087           R1INB--;
1088         }
1089       else if (_G.r1Pushed)
1090         {
1091           if (pop)
1092             {
1093               emitcode ("pop", "ar1");
1094               _G.r1Pushed--;
1095             }
1096         }
1097       bitVectUnSetBit (ic->rUsed, R1_IDX);
1098       break;
1099
1100     case AOP_STK:
1101       {
1102         int sz = aop->size;
1103         int stk = aop->aopu.aop_stk + aop->size - 1;
1104         bitVectUnSetBit (ic->rUsed, R0_IDX);
1105         bitVectUnSetBit (ic->rUsed, R1_IDX);
1106
1107         getFreePtr (ic, &aop, FALSE);
1108
1109         if (stk)
1110           {
1111             emitcode ("mov", "a,_bp");
1112             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1113             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1114           }
1115         else
1116           {
1117             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1118           }
1119
1120         while (sz--)
1121           {
1122             emitcode ("pop", "acc");
1123             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1124             if (!sz)
1125               break;
1126             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1127           }
1128         op->aop = aop;
1129         freeAsmop (op, NULL, ic, TRUE);
1130         if (_G.r1Pushed)
1131           {
1132             emitcode ("pop", "ar1");
1133             _G.r1Pushed--;
1134           }
1135         if (_G.r0Pushed)
1136           {
1137             emitcode ("pop", "ar0");
1138             _G.r0Pushed--;
1139           }
1140       }
1141       break;
1142     }
1143
1144 dealloc:
1145   /* all other cases just dealloc */
1146   if (op)
1147     {
1148       op->aop = NULL;
1149       if (IS_SYMOP (op))
1150         {
1151           OP_SYMBOL (op)->aop = NULL;
1152           /* if the symbol has a spill */
1153           if (SPIL_LOC (op))
1154             SPIL_LOC (op)->aop = NULL;
1155         }
1156     }
1157 }
1158
1159 /*------------------------------------------------------------------*/
1160 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1161 /*                      pop r0 or r1 off stack if pushed            */
1162 /*------------------------------------------------------------------*/
1163 static void
1164 freeForBranchAsmop (operand * op)
1165 {
1166   asmop *aop;
1167
1168   if (!op)
1169     return;
1170
1171   aop = op->aop;
1172
1173   if (!aop)
1174     return;
1175
1176   if (!aop->allocated)
1177     return;
1178
1179   switch (aop->type)
1180     {
1181     case AOP_R0:
1182       if (R0INB)
1183         {
1184           emitcode ("mov", "r0,b");
1185         }
1186       else if (_G.r0Pushed)
1187         {
1188           emitcode ("pop", "ar0");
1189         }
1190       break;
1191
1192     case AOP_R1:
1193       if (R1INB)
1194         {
1195           emitcode ("mov", "r1,b");
1196         }
1197       else if (_G.r1Pushed)
1198         {
1199           emitcode ("pop", "ar1");
1200         }
1201       break;
1202
1203     case AOP_STK:
1204       {
1205         int sz = aop->size;
1206         int stk = aop->aopu.aop_stk + aop->size - 1;
1207
1208         emitcode ("mov", "b,r0");
1209         if (stk)
1210           {
1211             emitcode ("mov", "a,_bp");
1212             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1213             emitcode ("mov", "r0,a");
1214           }
1215         else
1216           {
1217             emitcode ("mov", "r0,_bp");
1218           }
1219
1220         while (sz--)
1221           {
1222             emitcode ("pop", "acc");
1223             emitcode ("mov", "@r0,a");
1224             if (!sz)
1225               break;
1226             emitcode ("dec", "r0");
1227           }
1228         emitcode ("mov", "r0,b");
1229       }
1230     }
1231
1232 }
1233
1234 /*-----------------------------------------------------------------*/
1235 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1236 /*                 clobber the accumulator                         */
1237 /*-----------------------------------------------------------------*/
1238 static bool
1239 aopGetUsesAcc (operand * oper, int offset)
1240 {
1241   asmop * aop = AOP (oper);
1242
1243   if (offset > (aop->size - 1))
1244     return FALSE;
1245
1246   switch (aop->type)
1247     {
1248
1249     case AOP_R0:
1250     case AOP_R1:
1251       if (aop->paged)
1252         return TRUE;
1253       return FALSE;
1254     case AOP_DPTR:
1255       return TRUE;
1256     case AOP_IMMD:
1257       return FALSE;
1258     case AOP_DIR:
1259       return FALSE;
1260     case AOP_REG:
1261       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1262       return FALSE;
1263     case AOP_CRY:
1264       return TRUE;
1265     case AOP_ACC:
1266       if (offset)
1267         return FALSE;
1268       return TRUE;
1269     case AOP_LIT:
1270       return FALSE;
1271     case AOP_STR:
1272       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1273         return TRUE;
1274       return FALSE;
1275     case AOP_DUMMY:
1276       return FALSE;
1277     default:
1278       /* Error case --- will have been caught already */
1279       wassert(0);
1280       return FALSE;
1281     }
1282 }
1283
1284 /*-------------------------------------------------------------------*/
1285 /* aopGet - for fetching value of the aop                            */
1286 /*-------------------------------------------------------------------*/
1287 static char *
1288 aopGet (operand * oper, int offset, bool bit16, bool dname)
1289 {
1290   asmop * aop = AOP (oper);
1291
1292   /* offset is greater than
1293      size then zero */
1294   if (offset > (aop->size - 1) &&
1295       aop->type != AOP_LIT)
1296     return zero;
1297
1298   /* depending on type */
1299   switch (aop->type)
1300     {
1301     case AOP_DUMMY:
1302       return zero;
1303
1304     case AOP_R0:
1305     case AOP_R1:
1306       /* if we need to increment it */
1307       while (offset > aop->coff)
1308         {
1309           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1310           aop->coff++;
1311         }
1312
1313       while (offset < aop->coff)
1314         {
1315           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1316           aop->coff--;
1317         }
1318
1319       aop->coff = offset;
1320       if (aop->paged)
1321         {
1322           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1323           return (dname ? "acc" : "a");
1324         }
1325       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1326       return Safe_strdup(buffer);
1327
1328     case AOP_DPTR:
1329       if (aop->code && aop->coff==0 && offset>=1) {
1330         emitcode ("mov", "a,#0x%02x", offset);
1331         emitcode ("movc", "a,@a+dptr");
1332         return (dname ? "acc" : "a");
1333       }
1334
1335       while (offset > aop->coff)
1336         {
1337           emitcode ("inc", "dptr");
1338           aop->coff++;
1339         }
1340
1341       while (offset < aop->coff)
1342         {
1343           emitcode ("lcall", "__decdptr");
1344           aop->coff--;
1345         }
1346
1347       aop->coff = offset;
1348       if (aop->code)
1349         {
1350           emitcode ("clr", "a");
1351           emitcode ("movc", "a,@a+dptr");
1352         }
1353       else
1354         {
1355           emitcode ("movx", "a,@dptr");
1356         }
1357       return (dname ? "acc" : "a");
1358
1359     case AOP_IMMD:
1360       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1361         {
1362           SNPRINTF(buffer, sizeof(buffer),
1363                    "%s",aop->aopu.aop_immd.aop_immd2);
1364         }
1365       else if (bit16)
1366         {
1367           SNPRINTF(buffer, sizeof(buffer),
1368                    "#%s", aop->aopu.aop_immd.aop_immd1);
1369         }
1370       else if (offset)
1371         {
1372           SNPRINTF (buffer, sizeof(buffer),
1373                     "#(%s >> %d)",
1374                     aop->aopu.aop_immd.aop_immd1,
1375                     offset * 8);
1376         }
1377       else
1378         {
1379           SNPRINTF (buffer, sizeof(buffer),
1380                     "#%s",
1381                     aop->aopu.aop_immd.aop_immd1);
1382         }
1383       return Safe_strdup(buffer);
1384
1385     case AOP_DIR:
1386       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1387         {
1388           SNPRINTF (buffer, sizeof(buffer),
1389                     "(%s >> %d)",
1390                     aop->aopu.aop_dir, offset * 8);
1391         }
1392       else if (offset)
1393         {
1394           SNPRINTF (buffer, sizeof(buffer),
1395                     "(%s + %d)",
1396                     aop->aopu.aop_dir,
1397                     offset);
1398         }
1399       else
1400         {
1401           SNPRINTF (buffer, sizeof(buffer),
1402                     "%s",
1403                     aop->aopu.aop_dir);
1404         }
1405
1406       return Safe_strdup(buffer);
1407
1408     case AOP_REG:
1409       if (dname)
1410         return aop->aopu.aop_reg[offset]->dname;
1411       else
1412         return aop->aopu.aop_reg[offset]->name;
1413
1414     case AOP_CRY:
1415       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1416       emitcode ("clr", "a");
1417       emitcode ("rlc", "a");
1418       return (dname ? "acc" : "a");
1419
1420     case AOP_ACC:
1421       if (!offset && dname)
1422         return "acc";
1423       return aop->aopu.aop_str[offset];
1424
1425     case AOP_LIT:
1426       return aopLiteral (aop->aopu.aop_lit, offset);
1427
1428     case AOP_STR:
1429       aop->coff = offset;
1430       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1431           dname)
1432         return "acc";
1433
1434       return aop->aopu.aop_str[offset];
1435
1436     }
1437
1438   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1439           "aopget got unsupported aop->type");
1440   exit (1);
1441 }
1442
1443 /*-----------------------------------------------------------------*/
1444 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1445 /*                 clobber the accumulator                         */
1446 /*-----------------------------------------------------------------*/
1447 static bool
1448 aopPutUsesAcc (operand * oper, const char *s, int offset)
1449 {
1450   asmop * aop = AOP (oper);
1451
1452   if (offset > (aop->size - 1))
1453     return FALSE;
1454
1455   switch (aop->type)
1456     {
1457     case AOP_DUMMY:
1458       return TRUE;
1459     case AOP_DIR:
1460       return FALSE;
1461     case AOP_REG:
1462       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1463       return FALSE;
1464     case AOP_DPTR:
1465       return TRUE;
1466     case AOP_R0:
1467     case AOP_R1:
1468       return ((aop->paged) || (*s == '@'));
1469     case AOP_STK:
1470       return (*s == '@');
1471     case AOP_CRY:
1472       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1473     case AOP_STR:
1474       return FALSE;
1475     case AOP_IMMD:
1476       return FALSE;
1477     case AOP_ACC:
1478       return FALSE;
1479     default:
1480       /* Error case --- will have been caught already */
1481       wassert(0);
1482       return FALSE;
1483     }
1484 }
1485
1486 /*-----------------------------------------------------------------*/
1487 /* aopPut - puts a string for a aop and indicates if acc is in use */
1488 /*-----------------------------------------------------------------*/
1489 static bool
1490 aopPut (operand * result, const char *s, int offset)
1491 {
1492   bool bvolatile = isOperandVolatile (result, FALSE);
1493   bool accuse = FALSE;
1494   asmop * aop = AOP (result);
1495   const char *d = NULL;
1496
1497   if (aop->size && offset > (aop->size - 1))
1498     {
1499       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1500               "aopPut got offset > aop->size");
1501       exit (1);
1502     }
1503
1504   /* will assign value to value */
1505   /* depending on where it is ofcourse */
1506   switch (aop->type)
1507     {
1508     case AOP_DUMMY:
1509       MOVA (s);         /* read s in case it was volatile */
1510       accuse = TRUE;
1511       break;
1512
1513     case AOP_DIR:
1514       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1515         {
1516           SNPRINTF (buffer, sizeof(buffer),
1517                     "(%s >> %d)",
1518                     aop->aopu.aop_dir, offset * 8);
1519         }
1520       else if (offset)
1521         {
1522           SNPRINTF (buffer, sizeof(buffer),
1523                     "(%s + %d)",
1524                     aop->aopu.aop_dir, offset);
1525         }
1526       else
1527         {
1528           SNPRINTF (buffer, sizeof(buffer),
1529                     "%s",
1530                     aop->aopu.aop_dir);
1531         }
1532
1533       if (strcmp (buffer, s) || bvolatile)
1534         {
1535           emitcode ("mov", "%s,%s", buffer, s);
1536         }
1537       if (!strcmp (buffer, "acc"))
1538         {
1539           accuse = TRUE;
1540         }
1541       break;
1542
1543     case AOP_REG:
1544       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1545           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1546         {
1547           if (*s == '@' ||
1548               strcmp (s, "r0") == 0 ||
1549               strcmp (s, "r1") == 0 ||
1550               strcmp (s, "r2") == 0 ||
1551               strcmp (s, "r3") == 0 ||
1552               strcmp (s, "r4") == 0 ||
1553               strcmp (s, "r5") == 0 ||
1554               strcmp (s, "r6") == 0 ||
1555               strcmp (s, "r7") == 0)
1556             {
1557               emitcode ("mov", "%s,%s",
1558                         aop->aopu.aop_reg[offset]->dname, s);
1559             }
1560           else
1561             {
1562               emitcode ("mov", "%s,%s",
1563                         aop->aopu.aop_reg[offset]->name, s);
1564             }
1565         }
1566       break;
1567
1568     case AOP_DPTR:
1569       if (aop->code)
1570         {
1571           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1572                   "aopPut writing to code space");
1573           exit (1);
1574         }
1575
1576       while (offset > aop->coff)
1577         {
1578           aop->coff++;
1579           emitcode ("inc", "dptr");
1580         }
1581
1582       while (offset < aop->coff)
1583         {
1584           aop->coff--;
1585           emitcode ("lcall", "__decdptr");
1586         }
1587
1588       aop->coff = offset;
1589
1590       /* if not in accumulator */
1591       MOVA (s);
1592
1593       emitcode ("movx", "@dptr,a");
1594       break;
1595
1596     case AOP_R0:
1597     case AOP_R1:
1598       while (offset > aop->coff)
1599         {
1600           aop->coff++;
1601           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1602         }
1603       while (offset < aop->coff)
1604         {
1605           aop->coff--;
1606           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1607         }
1608       aop->coff = offset;
1609
1610       if (aop->paged)
1611         {
1612           MOVA (s);
1613           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1614         }
1615       else if (*s == '@')
1616         {
1617           MOVA (s);
1618           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1619         }
1620       else if (strcmp (s, "r0") == 0 ||
1621                strcmp (s, "r1") == 0 ||
1622                strcmp (s, "r2") == 0 ||
1623                strcmp (s, "r3") == 0 ||
1624                strcmp (s, "r4") == 0 ||
1625                strcmp (s, "r5") == 0 ||
1626                strcmp (s, "r6") == 0 ||
1627                strcmp (s, "r7") == 0)
1628         {
1629           char buffer[10];
1630           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1631           emitcode ("mov", "@%s,%s",
1632                     aop->aopu.aop_ptr->name, buffer);
1633         }
1634       else
1635         {
1636           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1637         }
1638       break;
1639
1640     case AOP_STK:
1641       if (strcmp (s, "a") == 0)
1642         {
1643           emitcode ("push", "acc");
1644         }
1645       else if (*s=='@')
1646         {
1647           MOVA(s);
1648           emitcode ("push", "acc");
1649         }
1650       else if (strcmp (s, "r0") == 0 ||
1651                strcmp (s, "r1") == 0 ||
1652                strcmp (s, "r2") == 0 ||
1653                strcmp (s, "r3") == 0 ||
1654                strcmp (s, "r4") == 0 ||
1655                strcmp (s, "r5") == 0 ||
1656                strcmp (s, "r6") == 0 ||
1657                strcmp (s, "r7") == 0)
1658         {
1659           char buffer[10];
1660           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1661           emitcode ("push", buffer);
1662         }
1663       else
1664         {
1665           emitcode ("push", s);
1666         }
1667
1668       break;
1669
1670     case AOP_CRY:
1671       // destination is carry for return-use-only
1672       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1673       // source is no literal and not in carry
1674       if ((s != zero) && (s != one) && strcmp (s, "c"))
1675         {
1676           MOVA (s);
1677           /* set C, if a >= 1 */
1678           emitcode ("add", "a,#0xff");
1679           s = "c";
1680         }
1681       // now source is zero, one or carry
1682
1683       /* if result no bit variable */
1684       if (!d)
1685         {
1686           if (!strcmp (s, "c"))
1687             {
1688               /* inefficient: move carry into A and use jz/jnz */
1689               emitcode ("clr", "a");
1690               emitcode ("rlc", "a");
1691               accuse = TRUE;
1692             }
1693           else
1694             {
1695               MOVA (s);
1696               accuse = TRUE;
1697             }
1698         }
1699       else if (s == zero)
1700           emitcode ("clr", "%s", d);
1701       else if (s == one)
1702           emitcode ("setb", "%s", d);
1703       else if (strcmp (s, d))
1704           emitcode ("mov", "%s,c", d);
1705       break;
1706
1707     case AOP_STR:
1708       aop->coff = offset;
1709       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1710         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1711       break;
1712
1713     case AOP_ACC:
1714       accuse = TRUE;
1715       aop->coff = offset;
1716       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1717         break;
1718
1719       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1720         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1721       break;
1722
1723     default:
1724       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1725               "aopPut got unsupported aop->type");
1726       exit (1);
1727     }
1728
1729     return accuse;
1730 }
1731
1732
1733 #if 0
1734 /*-----------------------------------------------------------------*/
1735 /* pointToEnd :- points to the last byte of the operand            */
1736 /*-----------------------------------------------------------------*/
1737 static void
1738 pointToEnd (asmop * aop)
1739 {
1740   int count;
1741   if (!aop)
1742     return;
1743
1744   aop->coff = count = (aop->size - 1);
1745   switch (aop->type)
1746     {
1747     case AOP_R0:
1748     case AOP_R1:
1749       while (count--)
1750         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1751       break;
1752     case AOP_DPTR:
1753       while (count--)
1754         emitcode ("inc", "dptr");
1755       break;
1756     }
1757
1758 }
1759 #endif
1760
1761 /*-----------------------------------------------------------------*/
1762 /* reAdjustPreg - points a register back to where it should        */
1763 /*-----------------------------------------------------------------*/
1764 static void
1765 reAdjustPreg (asmop * aop)
1766 {
1767   if ((aop->coff==0) || (aop->size <= 1))
1768     return;
1769
1770   switch (aop->type)
1771     {
1772     case AOP_R0:
1773     case AOP_R1:
1774       while (aop->coff--)
1775         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1776       break;
1777     case AOP_DPTR:
1778       while (aop->coff--)
1779         {
1780           emitcode ("lcall", "__decdptr");
1781         }
1782       break;
1783     }
1784   aop->coff = 0;
1785 }
1786
1787 /*-----------------------------------------------------------------*/
1788 /* opIsGptr: returns non-zero if the passed operand is       */
1789 /* a generic pointer type.             */
1790 /*-----------------------------------------------------------------*/
1791 static int
1792 opIsGptr (operand * op)
1793 {
1794   sym_link *type = operandType (op);
1795
1796   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1797     {
1798       return 1;
1799     }
1800   return 0;
1801 }
1802
1803 /*-----------------------------------------------------------------*/
1804 /* getDataSize - get the operand data size                         */
1805 /*-----------------------------------------------------------------*/
1806 static int
1807 getDataSize (operand * op)
1808 {
1809   int size;
1810   size = AOP_SIZE (op);
1811   if (size == GPTRSIZE)
1812     {
1813       sym_link *type = operandType (op);
1814       if (IS_GENPTR (type))
1815         {
1816           /* generic pointer; arithmetic operations
1817            * should ignore the high byte (pointer type).
1818            */
1819           size--;
1820         }
1821     }
1822   return size;
1823 }
1824
1825 /*-----------------------------------------------------------------*/
1826 /* outAcc - output Acc                                             */
1827 /*-----------------------------------------------------------------*/
1828 static void
1829 outAcc (operand * result)
1830 {
1831   int size, offset;
1832   size = getDataSize (result);
1833   if (size)
1834     {
1835       aopPut (result, "a", 0);
1836       size--;
1837       offset = 1;
1838       /* unsigned or positive */
1839       while (size--)
1840         {
1841           aopPut (result, zero, offset++);
1842         }
1843     }
1844 }
1845
1846 /*-----------------------------------------------------------------*/
1847 /* outBitC - output a bit C                                        */
1848 /*-----------------------------------------------------------------*/
1849 static void
1850 outBitC (operand * result)
1851 {
1852   /* if the result is bit */
1853   if (AOP_TYPE (result) == AOP_CRY)
1854     {
1855       if (!IS_OP_RUONLY (result))
1856         aopPut (result, "c", 0);
1857     }
1858   else
1859     {
1860       emitcode ("clr", "a");
1861       emitcode ("rlc", "a");
1862       outAcc (result);
1863     }
1864 }
1865
1866 /*-----------------------------------------------------------------*/
1867 /* toBoolean - emit code for orl a,operator(sizeop)                */
1868 /*-----------------------------------------------------------------*/
1869 static void
1870 toBoolean (operand * oper)
1871 {
1872   int size = AOP_SIZE (oper) - 1;
1873   int offset = 1;
1874   bool AccUsed = FALSE;
1875   bool pushedB;
1876
1877   while (!AccUsed && size--)
1878     {
1879       AccUsed |= aopGetUsesAcc(oper, offset++);
1880     }
1881
1882   size = AOP_SIZE (oper) - 1;
1883   offset = 1;
1884   MOVA (aopGet (oper, 0, FALSE, FALSE));
1885   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1886     {
1887       pushedB = pushB ();
1888       emitcode("mov", "b,a");
1889       while (--size)
1890         {
1891           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1892           emitcode ("orl", "b,a");
1893         }
1894       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1895       emitcode ("orl", "a,b");
1896       popB (pushedB);
1897     }
1898   else
1899     {
1900       while (size--)
1901         {
1902           emitcode ("orl", "a,%s",
1903                     aopGet (oper, offset++, FALSE, FALSE));
1904         }
1905     }
1906 }
1907
1908 /*-----------------------------------------------------------------*/
1909 /* toCarry - make boolean and move into carry                      */
1910 /*-----------------------------------------------------------------*/
1911 static void
1912 toCarry (operand * oper)
1913 {
1914   /* if the operand is a literal then
1915      we know what the value is */
1916   if (AOP_TYPE (oper) == AOP_LIT)
1917     {
1918       if ((int) operandLitValue (oper))
1919         SETC;
1920       else
1921         CLRC;
1922     }
1923   else if (AOP_TYPE (oper) == AOP_CRY)
1924     {
1925       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1926     }
1927   else
1928     {
1929       /* or the operand into a */
1930       toBoolean (oper);
1931       /* set C, if a >= 1 */
1932       emitcode ("add", "a,#0xff");
1933     }
1934 }
1935
1936 /*-----------------------------------------------------------------*/
1937 /* assignBit - assign operand to bit operand                       */
1938 /*-----------------------------------------------------------------*/
1939 static void
1940 assignBit (operand * result, operand * right)
1941 {
1942   /* if the right side is a literal then
1943      we know what the value is */
1944   if (AOP_TYPE (right) == AOP_LIT)
1945     {
1946       if ((int) operandLitValue (right))
1947         aopPut (result, one, 0);
1948       else
1949         aopPut (result, zero, 0);
1950     }
1951   else
1952     {
1953       toCarry (right);
1954       aopPut (result, "c", 0);
1955     }
1956 }
1957
1958
1959 /*-------------------------------------------------------------------*/
1960 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1961 /*-------------------------------------------------------------------*/
1962 static char *
1963 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1964 {
1965   char * l;
1966
1967   if (aopGetUsesAcc (oper, offset))
1968     {
1969       emitcode("mov", "b,a");
1970       MOVA (aopGet (oper, offset, bit16, dname));
1971       emitcode("xch", "a,b");
1972       aopPut (oper, "a", offset);
1973       emitcode("xch", "a,b");
1974       l = "b";
1975     }
1976   else
1977     {
1978       l = aopGet (oper, offset, bit16, dname);
1979       emitcode("xch", "a,%s", l);
1980     }
1981   return l;
1982 }
1983
1984
1985 /*-----------------------------------------------------------------*/
1986 /* genNot - generate code for ! operation                          */
1987 /*-----------------------------------------------------------------*/
1988 static void
1989 genNot (iCode * ic)
1990 {
1991   symbol *tlbl;
1992
1993   D (emitcode (";", "genNot"));
1994
1995   /* assign asmOps to operand & result */
1996   aopOp (IC_LEFT (ic), ic, FALSE);
1997   aopOp (IC_RESULT (ic), ic, TRUE);
1998
1999   /* if in bit space then a special case */
2000   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2001     {
2002       /* if left==result then cpl bit */
2003       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2004         {
2005           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2006         }
2007       else
2008         {
2009           toCarry (IC_LEFT (ic));
2010           emitcode ("cpl", "c");
2011           outBitC (IC_RESULT (ic));
2012         }
2013       goto release;
2014     }
2015
2016   toBoolean (IC_LEFT (ic));
2017
2018   /* set C, if a == 0 */
2019   tlbl = newiTempLabel (NULL);
2020   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2021   emitLabel (tlbl);
2022   outBitC (IC_RESULT (ic));
2023
2024 release:
2025   /* release the aops */
2026   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2027   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2028 }
2029
2030
2031 /*-----------------------------------------------------------------*/
2032 /* genCpl - generate code for complement                           */
2033 /*-----------------------------------------------------------------*/
2034 static void
2035 genCpl (iCode * ic)
2036 {
2037   int offset = 0;
2038   int size;
2039   symbol *tlbl;
2040   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2041
2042   D(emitcode (";", "genCpl"));
2043
2044   /* assign asmOps to operand & result */
2045   aopOp (IC_LEFT (ic), ic, FALSE);
2046   aopOp (IC_RESULT (ic), ic, TRUE);
2047
2048   /* special case if in bit space */
2049   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2050     {
2051       char *l;
2052
2053       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2054           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2055         {
2056           /* promotion rules are responsible for this strange result:
2057              bit -> int -> ~int -> bit
2058              uchar -> int -> ~int -> bit
2059           */
2060           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2061           goto release;
2062         }
2063
2064       tlbl=newiTempLabel(NULL);
2065       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2066       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2067           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2068           IS_AOP_PREG (IC_LEFT (ic)))
2069         {
2070           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2071         }
2072       else
2073         {
2074           MOVA (l);
2075           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2076         }
2077       emitLabel (tlbl);
2078       outBitC (IC_RESULT(ic));
2079       goto release;
2080     }
2081
2082   size = AOP_SIZE (IC_RESULT (ic));
2083   while (size--)
2084     {
2085       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2086       MOVA (l);
2087       emitcode ("cpl", "a");
2088       aopPut (IC_RESULT (ic), "a", offset++);
2089     }
2090
2091
2092 release:
2093   /* release the aops */
2094   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2095   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2096 }
2097
2098 /*-----------------------------------------------------------------*/
2099 /* genUminusFloat - unary minus for floating points                */
2100 /*-----------------------------------------------------------------*/
2101 static void
2102 genUminusFloat (operand * op, operand * result)
2103 {
2104   int size, offset = 0;
2105   char *l;
2106
2107   D (emitcode (";", "genUminusFloat"));
2108
2109   /* for this we just copy and then flip the bit */
2110
2111   size = AOP_SIZE (op) - 1;
2112
2113   while (size--)
2114     {
2115       aopPut (result,
2116               aopGet (op, offset, FALSE, FALSE),
2117               offset);
2118       offset++;
2119     }
2120
2121   l = aopGet (op, offset, FALSE, FALSE);
2122   MOVA (l);
2123
2124   emitcode ("cpl", "acc.7");
2125   aopPut (result, "a", offset);
2126 }
2127
2128 /*-----------------------------------------------------------------*/
2129 /* genUminus - unary minus code generation                         */
2130 /*-----------------------------------------------------------------*/
2131 static void
2132 genUminus (iCode * ic)
2133 {
2134   int offset, size;
2135   sym_link *optype;
2136
2137   D (emitcode (";", "genUminus"));
2138
2139   /* assign asmops */
2140   aopOp (IC_LEFT (ic), ic, FALSE);
2141   aopOp (IC_RESULT (ic), ic, TRUE);
2142
2143   /* if both in bit space then special
2144      case */
2145   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2146       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2147     {
2148
2149       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2150       emitcode ("cpl", "c");
2151       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2152       goto release;
2153     }
2154
2155   optype = operandType (IC_LEFT (ic));
2156
2157   /* if float then do float stuff */
2158   if (IS_FLOAT (optype))
2159     {
2160       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2161       goto release;
2162     }
2163
2164   /* otherwise subtract from zero */
2165   size = AOP_SIZE (IC_LEFT (ic));
2166   offset = 0;
2167   while (size--)
2168     {
2169       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2170       if (!strcmp (l, "a"))
2171         {
2172           if (offset == 0)
2173             SETC;
2174           emitcode ("cpl", "a");
2175           emitcode ("addc", "a,#0");
2176         }
2177       else
2178         {
2179           if (offset == 0)
2180             CLRC;
2181           emitcode ("clr", "a");
2182           emitcode ("subb", "a,%s", l);
2183         }
2184       aopPut (IC_RESULT (ic), "a", offset++);
2185     }
2186
2187   /* if any remaining bytes in the result */
2188   /* we just need to propagate the sign   */
2189   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2190     {
2191       emitcode ("rlc", "a");
2192       emitcode ("subb", "a,acc");
2193       while (size--)
2194         aopPut (IC_RESULT (ic), "a", offset++);
2195     }
2196
2197 release:
2198   /* release the aops */
2199   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2200   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2201 }
2202
2203 /*-----------------------------------------------------------------*/
2204 /* saveRegisters - will look for a call and save the registers     */
2205 /*-----------------------------------------------------------------*/
2206 static void
2207 saveRegisters (iCode * lic)
2208 {
2209   int i;
2210   iCode *ic;
2211   bitVect *rsave;
2212
2213   /* look for call */
2214   for (ic = lic; ic; ic = ic->next)
2215     if (ic->op == CALL || ic->op == PCALL)
2216       break;
2217
2218   if (!ic)
2219     {
2220       fprintf (stderr, "found parameter push with no function call\n");
2221       return;
2222     }
2223
2224   /* if the registers have been saved already or don't need to be then
2225      do nothing */
2226   if (ic->regsSaved)
2227     return;
2228   if (IS_SYMOP(IC_LEFT(ic)) &&
2229       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2230        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2231     return;
2232
2233   /* save the registers in use at this time but skip the
2234      ones for the result */
2235   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2236                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2237
2238   ic->regsSaved = 1;
2239   if (options.useXstack)
2240     {
2241       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2242       int nBits = bitVectnBitsOn (rsavebits);
2243       int count = bitVectnBitsOn (rsave);
2244
2245       if (nBits != 0)
2246         {
2247           count = count - nBits + 1;
2248           /* remove all but the first bits as they are pushed all at once */
2249           rsave = bitVectCplAnd (rsave, rsavebits);
2250           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2251         }
2252       freeBitVect (rsavebits);
2253
2254       if (count == 1)
2255         {
2256           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2257           if (reg->type == REG_BIT)
2258             {
2259               emitcode ("mov", "a,%s", reg->base);
2260             }
2261           else
2262             {
2263               emitcode ("mov", "a,%s", reg->name);
2264             }
2265           emitcode ("mov", "r0,%s", spname);
2266           emitcode ("inc", "%s", spname);// allocate before use
2267           emitcode ("movx", "@r0,a");
2268           if (bitVectBitValue (rsave, R0_IDX))
2269             emitcode ("mov", "r0,a");
2270         }
2271       else if (count != 0)
2272         {
2273           if (bitVectBitValue (rsave, R0_IDX))
2274             {
2275               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2276             }
2277           emitcode ("mov", "r0,%s", spname);
2278           MOVA ("r0");
2279           emitcode ("add", "a,#%d", count);
2280           emitcode ("mov", "%s,a", spname);
2281           for (i = 0; i < mcs51_nRegs; i++)
2282             {
2283               if (bitVectBitValue (rsave, i))
2284                 {
2285                   regs * reg = REG_WITH_INDEX (i);
2286                   if (i == R0_IDX)
2287                     {
2288                       emitcode ("pop", "acc");
2289                       emitcode ("push", "acc");
2290                     }
2291                   else if (reg->type == REG_BIT)
2292                     {
2293                       emitcode ("mov", "a,%s", reg->base);
2294                     }
2295                   else
2296                     {
2297                       emitcode ("mov", "a,%s", reg->name);
2298                     }
2299                   emitcode ("movx", "@r0,a");
2300                   if (--count)
2301                     {
2302                       emitcode ("inc", "r0");
2303                     }
2304                 }
2305             }
2306           if (bitVectBitValue (rsave, R0_IDX))
2307             {
2308               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2309             }
2310         }
2311     }
2312   else
2313     {
2314       bool bits_pushed = FALSE;
2315       for (i = 0; i < mcs51_nRegs; i++)
2316         {
2317           if (bitVectBitValue (rsave, i))
2318             {
2319               bits_pushed = pushReg (i, bits_pushed);
2320             }
2321         }
2322     }
2323   freeBitVect (rsave);
2324 }
2325
2326 /*-----------------------------------------------------------------*/
2327 /* unsaveRegisters - pop the pushed registers                      */
2328 /*-----------------------------------------------------------------*/
2329 static void
2330 unsaveRegisters (iCode * ic)
2331 {
2332   int i;
2333   bitVect *rsave;
2334
2335   /* restore the registers in use at this time but skip the
2336      ones for the result */
2337   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2338                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2339
2340   if (options.useXstack)
2341     {
2342       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2343       int nBits = bitVectnBitsOn (rsavebits);
2344       int count = bitVectnBitsOn (rsave);
2345
2346       if (nBits != 0)
2347         {
2348           count = count - nBits + 1;
2349           /* remove all but the first bits as they are popped all at once */
2350           rsave = bitVectCplAnd (rsave, rsavebits);
2351           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2352         }
2353       freeBitVect (rsavebits);
2354
2355       if (count == 1)
2356         {
2357           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2358           emitcode ("mov", "r0,%s", spname);
2359           emitcode ("dec", "r0");
2360           emitcode ("movx", "a,@r0");
2361           if (reg->type == REG_BIT)
2362             {
2363               emitcode ("mov", "%s,a", reg->base);
2364             }
2365           else
2366             {
2367               emitcode ("mov", "%s,a", reg->name);
2368             }
2369           emitcode ("dec", "%s", spname);
2370         }
2371       else if (count != 0)
2372         {
2373           emitcode ("mov", "r0,%s", spname);
2374           for (i = mcs51_nRegs; i >= 0; i--)
2375             {
2376               if (bitVectBitValue (rsave, i))
2377                 {
2378                   regs * reg = REG_WITH_INDEX (i);
2379                   emitcode ("dec", "r0");
2380                   emitcode ("movx", "a,@r0");
2381                   if (i == R0_IDX)
2382                     {
2383                       emitcode ("push", "acc");
2384                     }
2385                   else if (reg->type == REG_BIT)
2386                     {
2387                       emitcode ("mov", "%s,a", reg->base);
2388                     }
2389                   else
2390                     {
2391                       emitcode ("mov", "%s,a", reg->name);
2392                     }
2393                 }
2394             }
2395           emitcode ("mov", "%s,r0", spname);
2396           if (bitVectBitValue (rsave, R0_IDX))
2397             {
2398               emitcode ("pop", "ar0");
2399             }
2400         }
2401     }
2402   else
2403     {
2404       bool bits_popped = FALSE;
2405       for (i = mcs51_nRegs; i >= 0; i--)
2406         {
2407           if (bitVectBitValue (rsave, i))
2408             {
2409               bits_popped = popReg (i, bits_popped);
2410             }
2411         }
2412     }
2413   freeBitVect (rsave);
2414 }
2415
2416
2417 /*-----------------------------------------------------------------*/
2418 /* pushSide -                                                      */
2419 /*-----------------------------------------------------------------*/
2420 static void
2421 pushSide (operand * oper, int size)
2422 {
2423   int offset = 0;
2424   while (size--)
2425     {
2426       char *l = aopGet (oper, offset++, FALSE, TRUE);
2427       if (AOP_TYPE (oper) != AOP_REG &&
2428           AOP_TYPE (oper) != AOP_DIR &&
2429           strcmp (l, "a"))
2430         {
2431           MOVA (l);
2432           emitcode ("push", "acc");
2433         }
2434       else
2435         {
2436           emitcode ("push", "%s", l);
2437         }
2438     }
2439 }
2440
2441 /*-----------------------------------------------------------------*/
2442 /* assignResultValue - also indicates if acc is in use afterwards  */
2443 /*-----------------------------------------------------------------*/
2444 static bool
2445 assignResultValue (operand * oper, operand * func)
2446 {
2447   int offset = 0;
2448   int size = AOP_SIZE (oper);
2449   bool accuse = FALSE;
2450   bool pushedA = FALSE;
2451
2452   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2453     {
2454       outBitC (oper);
2455       return FALSE;
2456     }
2457
2458   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2459     {
2460       emitcode ("push", "acc");
2461       pushedA = TRUE;
2462     }
2463   while (size--)
2464     {
2465       if ((offset == 3) && pushedA)
2466         emitcode ("pop", "acc");
2467       accuse |= aopPut (oper, fReturn[offset], offset);
2468       offset++;
2469     }
2470   return accuse;
2471 }
2472
2473
2474 /*-----------------------------------------------------------------*/
2475 /* genXpush - pushes onto the external stack                       */
2476 /*-----------------------------------------------------------------*/
2477 static void
2478 genXpush (iCode * ic)
2479 {
2480   asmop *aop = newAsmop (0);
2481   regs *r;
2482   int size, offset = 0;
2483
2484   D (emitcode (";", "genXpush"));
2485
2486   aopOp (IC_LEFT (ic), ic, FALSE);
2487   r = getFreePtr (ic, &aop, FALSE);
2488
2489   size = AOP_SIZE (IC_LEFT (ic));
2490
2491   if (size == 1)
2492     {
2493       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2494       emitcode ("mov", "%s,%s", r->name, spname);
2495       emitcode ("inc", "%s", spname); // allocate space first
2496       emitcode ("movx", "@%s,a", r->name);
2497     }
2498   else
2499     {
2500       // allocate space first
2501       emitcode ("mov", "%s,%s", r->name, spname);
2502       MOVA (r->name);
2503       emitcode ("add", "a,#%d", size);
2504       emitcode ("mov", "%s,a", spname);
2505
2506       while (size--)
2507         {
2508           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2509           emitcode ("movx", "@%s,a", r->name);
2510           emitcode ("inc", "%s", r->name);
2511         }
2512     }
2513
2514   freeAsmop (NULL, aop, ic, TRUE);
2515   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2516 }
2517
2518 /*-----------------------------------------------------------------*/
2519 /* genIpush - generate code for pushing this gets a little complex */
2520 /*-----------------------------------------------------------------*/
2521 static void
2522 genIpush (iCode * ic)
2523 {
2524   int size, offset = 0;
2525   char *l;
2526   char *prev = "";
2527
2528   D (emitcode (";", "genIpush"));
2529
2530   /* if this is not a parm push : ie. it is spill push
2531      and spill push is always done on the local stack */
2532   if (!ic->parmPush)
2533     {
2534
2535       /* and the item is spilt then do nothing */
2536       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2537         return;
2538
2539       aopOp (IC_LEFT (ic), ic, FALSE);
2540       size = AOP_SIZE (IC_LEFT (ic));
2541       /* push it on the stack */
2542       while (size--)
2543         {
2544           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2545           if (*l == '#')
2546             {
2547               MOVA (l);
2548               l = "acc";
2549             }
2550           emitcode ("push", "%s", l);
2551         }
2552       return;
2553     }
2554
2555   /* this is a parameter push: in this case we call
2556      the routine to find the call and save those
2557      registers that need to be saved */
2558   saveRegisters (ic);
2559
2560   /* if use external stack then call the external
2561      stack pushing routine */
2562   if (options.useXstack)
2563     {
2564       genXpush (ic);
2565       return;
2566     }
2567
2568   /* then do the push */
2569   aopOp (IC_LEFT (ic), ic, FALSE);
2570
2571   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2572   size = AOP_SIZE (IC_LEFT (ic));
2573
2574   while (size--)
2575     {
2576       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2577       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2578           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2579         {
2580           if (strcmp (l, prev) || *l == '@')
2581             MOVA (l);
2582           emitcode ("push", "acc");
2583         }
2584       else
2585         {
2586           emitcode ("push", "%s", l);
2587         }
2588       prev = l;
2589     }
2590
2591   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2592 }
2593
2594 /*-----------------------------------------------------------------*/
2595 /* genIpop - recover the registers: can happen only for spilling   */
2596 /*-----------------------------------------------------------------*/
2597 static void
2598 genIpop (iCode * ic)
2599 {
2600   int size, offset;
2601
2602   D (emitcode (";", "genIpop"));
2603
2604   /* if the temp was not pushed then */
2605   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2606     return;
2607
2608   aopOp (IC_LEFT (ic), ic, FALSE);
2609   size = AOP_SIZE (IC_LEFT (ic));
2610   offset = (size - 1);
2611   while (size--)
2612     {
2613       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2614                                      FALSE, TRUE));
2615     }
2616
2617   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2618 }
2619
2620 /*-----------------------------------------------------------------*/
2621 /* saveRBank - saves an entire register bank on the stack          */
2622 /*-----------------------------------------------------------------*/
2623 static void
2624 saveRBank (int bank, iCode * ic, bool pushPsw)
2625 {
2626   int i;
2627   int count = 8 + (pushPsw ? 1 : 0);
2628   asmop *aop = NULL;
2629   regs *r = NULL;
2630
2631   if (options.useXstack)
2632     {
2633       if (!ic)
2634         {
2635           /* Assume r0 is available for use. */
2636           r = REG_WITH_INDEX (R0_IDX);
2637         }
2638       else
2639         {
2640           aop = newAsmop (0);
2641           r = getFreePtr (ic, &aop, FALSE);
2642         }
2643       // allocate space first
2644       emitcode ("mov", "%s,%s", r->name, spname);
2645       MOVA (r->name);
2646       emitcode ("add", "a,#%d", count);
2647       emitcode ("mov", "%s,a", spname);
2648     }
2649
2650   for (i = 0; i < 8; i++)
2651     {
2652       if (options.useXstack)
2653         {
2654           emitcode ("mov", "a,(%s+%d)",
2655                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2656           emitcode ("movx", "@%s,a", r->name);
2657           if (--count)
2658             emitcode ("inc", "%s", r->name);
2659         }
2660       else
2661         emitcode ("push", "(%s+%d)",
2662                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2663     }
2664
2665   if (pushPsw)
2666     {
2667       if (options.useXstack)
2668         {
2669           emitcode ("mov", "a,psw");
2670           emitcode ("movx", "@%s,a", r->name);
2671         }
2672       else
2673         {
2674           emitcode ("push", "psw");
2675         }
2676
2677       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2678     }
2679
2680   if (aop)
2681     {
2682       freeAsmop (NULL, aop, ic, TRUE);
2683     }
2684
2685   if (ic)
2686     {
2687       ic->bankSaved = 1;
2688     }
2689 }
2690
2691 /*-----------------------------------------------------------------*/
2692 /* unsaveRBank - restores the register bank from stack             */
2693 /*-----------------------------------------------------------------*/
2694 static void
2695 unsaveRBank (int bank, iCode * ic, bool popPsw)
2696 {
2697   int i;
2698   asmop *aop = NULL;
2699   regs *r = NULL;
2700
2701   if (options.useXstack)
2702     {
2703       if (!ic)
2704         {
2705           /* Assume r0 is available for use. */
2706           r = REG_WITH_INDEX (R0_IDX);;
2707         }
2708       else
2709         {
2710           aop = newAsmop (0);
2711           r = getFreePtr (ic, &aop, FALSE);
2712         }
2713       emitcode ("mov", "%s,%s", r->name, spname);
2714     }
2715
2716   if (popPsw)
2717     {
2718       if (options.useXstack)
2719         {
2720           emitcode ("dec", "%s", r->name);
2721           emitcode ("movx", "a,@%s", r->name);
2722           emitcode ("mov", "psw,a");
2723         }
2724       else
2725         {
2726           emitcode ("pop", "psw");
2727         }
2728     }
2729
2730   for (i = 7; i >= 0; i--)
2731     {
2732       if (options.useXstack)
2733         {
2734           emitcode ("dec", "%s", r->name);
2735           emitcode ("movx", "a,@%s", r->name);
2736           emitcode ("mov", "(%s+%d),a",
2737                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2738         }
2739       else
2740         {
2741           emitcode ("pop", "(%s+%d)",
2742                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2743         }
2744     }
2745
2746   if (options.useXstack)
2747     {
2748       emitcode ("mov", "%s,%s", spname, r->name);
2749     }
2750
2751   if (aop)
2752     {
2753       freeAsmop (NULL, aop, ic, TRUE);
2754     }
2755 }
2756
2757 /*-----------------------------------------------------------------*/
2758 /* genSend - gen code for SEND                                     */
2759 /*-----------------------------------------------------------------*/
2760 static void genSend(set *sendSet)
2761 {
2762   iCode *sic;
2763   int bit_count = 0;
2764
2765   /* first we do all bit parameters */
2766   for (sic = setFirstItem (sendSet); sic;
2767        sic = setNextItem (sendSet))
2768     {
2769       if (sic->argreg > 12)
2770         {
2771           int bit = sic->argreg-13;
2772
2773           aopOp (IC_LEFT (sic), sic, FALSE);
2774
2775           /* if left is a literal then
2776              we know what the value is */
2777           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2778             {
2779               if (((int) operandLitValue (IC_LEFT (sic))))
2780                   emitcode ("setb", "b[%d]", bit);
2781               else
2782                   emitcode ("clr", "b[%d]", bit);
2783             }
2784           else
2785             {
2786               /* we need to or */
2787               toCarry (IC_LEFT (sic));
2788               emitcode ("mov", "b[%d],c", bit);
2789             }
2790           bit_count++;
2791           BitBankUsed = 1;
2792
2793           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2794         }
2795     }
2796
2797   if (bit_count)
2798     {
2799       saveRegisters (setFirstItem (sendSet));
2800       emitcode ("mov", "bits,b");
2801     }
2802
2803   /* then we do all other parameters */
2804   for (sic = setFirstItem (sendSet); sic;
2805        sic = setNextItem (sendSet))
2806     {
2807       if (sic->argreg <= 12)
2808         {
2809           int size, offset = 0;
2810           aopOp (IC_LEFT (sic), sic, FALSE);
2811           size = AOP_SIZE (IC_LEFT (sic));
2812
2813           if (sic->argreg == 1)
2814             {
2815               while (size--)
2816                 {
2817                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2818                   if (strcmp (l, fReturn[offset]))
2819                     {
2820                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2821                     }
2822                   offset++;
2823                 }
2824             }
2825           else
2826             {
2827               while (size--)
2828                 {
2829                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2830                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2831                   offset++;
2832                 }
2833             }
2834           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2835         }
2836     }
2837 }
2838
2839 /*-----------------------------------------------------------------*/
2840 /* selectRegBank - emit code to select the register bank           */
2841 /*-----------------------------------------------------------------*/
2842 static void
2843 selectRegBank (short bank, bool keepFlags)
2844 {
2845   /* if f.e. result is in carry */
2846   if (keepFlags)
2847     {
2848       emitcode ("anl", "psw,#0xE7");
2849       if (bank)
2850         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2851     }
2852   else
2853     {
2854       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2855     }
2856 }
2857
2858 /*-----------------------------------------------------------------*/
2859 /* genCall - generates a call statement                            */
2860 /*-----------------------------------------------------------------*/
2861 static void
2862 genCall (iCode * ic)
2863 {
2864   sym_link *dtype;
2865   sym_link *etype;
2866 //  bool restoreBank = FALSE;
2867   bool swapBanks = FALSE;
2868   bool accuse = FALSE;
2869   bool accPushed = FALSE;
2870   bool resultInF0 = FALSE;
2871   bool assignResultGenerated = FALSE;
2872
2873   D (emitcode (";", "genCall"));
2874
2875   dtype = operandType (IC_LEFT (ic));
2876   etype = getSpec(dtype);
2877   /* if send set is not empty then assign */
2878   if (_G.sendSet)
2879     {
2880         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2881             genSend(reverseSet(_G.sendSet));
2882         } else {
2883             genSend(_G.sendSet);
2884         }
2885       _G.sendSet = NULL;
2886     }
2887
2888   /* if we are calling a not _naked function that is not using
2889      the same register bank then we need to save the
2890      destination registers on the stack */
2891   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2892       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2893        !IFFUNC_ISISR (dtype))
2894     {
2895       swapBanks = TRUE;
2896     }
2897
2898   /* if caller saves & we have not saved then */
2899   if (!ic->regsSaved)
2900       saveRegisters (ic);
2901
2902   if (swapBanks)
2903     {
2904         emitcode ("mov", "psw,#0x%02x",
2905            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2906     }
2907
2908   /* make the call */
2909   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2910     {
2911       if (IFFUNC_CALLEESAVES(dtype))
2912         {
2913           werror (E_BANKED_WITH_CALLEESAVES);
2914         }
2915       else
2916         {
2917           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2918                      OP_SYMBOL (IC_LEFT (ic))->rname :
2919                      OP_SYMBOL (IC_LEFT (ic))->name);
2920
2921           emitcode ("mov", "r0,#%s", l);
2922           emitcode ("mov", "r1,#(%s >> 8)", l);
2923           emitcode ("mov", "r2,#(%s >> 16)", l);
2924           emitcode ("lcall", "__sdcc_banked_call");
2925         }
2926     }
2927   else
2928     {
2929       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2930                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2931                                 OP_SYMBOL (IC_LEFT (ic))->name));
2932     }
2933
2934   if (swapBanks)
2935     {
2936       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2937     }
2938
2939   /* if we need assign a result value */
2940   if ((IS_ITEMP (IC_RESULT (ic)) &&
2941        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2942        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2943         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2944         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2945       IS_TRUE_SYMOP (IC_RESULT (ic)))
2946     {
2947
2948       _G.accInUse++;
2949       aopOp (IC_RESULT (ic), ic, FALSE);
2950       _G.accInUse--;
2951
2952       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2953       assignResultGenerated = TRUE;
2954
2955       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2956     }
2957
2958   /* adjust the stack for parameters if required */
2959   if (ic->parmBytes)
2960     {
2961       int i;
2962       if (ic->parmBytes > 3)
2963         {
2964           if (accuse)
2965             {
2966               emitcode ("push", "acc");
2967               accPushed = TRUE;
2968             }
2969           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2970               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2971               !assignResultGenerated)
2972             {
2973               emitcode ("mov", "F0,c");
2974               resultInF0 = TRUE;
2975             }
2976
2977           emitcode ("mov", "a,%s", spname);
2978           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2979           emitcode ("mov", "%s,a", spname);
2980
2981           /* unsaveRegisters from xstack needs acc, but */
2982           /* unsaveRegisters from stack needs this popped */
2983           if (accPushed && !options.useXstack)
2984             {
2985               emitcode ("pop", "acc");
2986               accPushed = FALSE;
2987             }
2988         }
2989       else
2990         for (i = 0; i < ic->parmBytes; i++)
2991           emitcode ("dec", "%s", spname);
2992     }
2993
2994   /* if we had saved some registers then unsave them */
2995   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2996     {
2997       if (accuse && !accPushed && options.useXstack)
2998         {
2999           /* xstack needs acc, but doesn't touch normal stack */
3000           emitcode ("push", "acc");
3001           accPushed = TRUE;
3002         }
3003       unsaveRegisters (ic);
3004     }
3005
3006 //  /* if register bank was saved then pop them */
3007 //  if (restoreBank)
3008 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3009
3010   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3011     {
3012       if (resultInF0)
3013           emitcode ("mov", "c,F0");
3014
3015       aopOp (IC_RESULT (ic), ic, FALSE);
3016       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3017       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3018     }
3019
3020   if (accPushed)
3021     emitcode ("pop", "acc");
3022 }
3023
3024 /*-----------------------------------------------------------------*/
3025 /* genPcall - generates a call by pointer statement                */
3026 /*-----------------------------------------------------------------*/
3027 static void
3028 genPcall (iCode * ic)
3029 {
3030   sym_link *dtype;
3031   sym_link *etype;
3032   symbol *rlbl = newiTempLabel (NULL);
3033 //  bool restoreBank=FALSE;
3034   bool swapBanks = FALSE;
3035   bool resultInF0 = FALSE;
3036
3037   D (emitcode (";", "genPcall"));
3038
3039   dtype = operandType (IC_LEFT (ic))->next;
3040   etype = getSpec(dtype);
3041   /* if caller saves & we have not saved then */
3042   if (!ic->regsSaved)
3043     saveRegisters (ic);
3044
3045   /* if we are calling a not _naked function that is not using
3046      the same register bank then we need to save the
3047      destination registers on the stack */
3048   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3049       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3050       !IFFUNC_ISISR (dtype))
3051     {
3052 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3053 //    restoreBank=TRUE;
3054       swapBanks = TRUE;
3055       // need caution message to user here
3056     }
3057
3058   if (IS_LITERAL (etype))
3059     {
3060       /* if send set is not empty then assign */
3061       if (_G.sendSet)
3062         {
3063           genSend(reverseSet(_G.sendSet));
3064           _G.sendSet = NULL;
3065         }
3066
3067       if (swapBanks)
3068         {
3069           emitcode ("mov", "psw,#0x%02x",
3070            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3071         }
3072
3073       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3074         {
3075           if (IFFUNC_CALLEESAVES (dtype))
3076             {
3077               werror (E_BANKED_WITH_CALLEESAVES);
3078             }
3079           else
3080             {
3081               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3082
3083               emitcode ("mov", "r0,#%s", l);
3084               emitcode ("mov", "r1,#(%s >> 8)", l);
3085               emitcode ("mov", "r2,#(%s >> 16)", l);
3086               emitcode ("lcall", "__sdcc_banked_call");
3087             }
3088         }
3089       else
3090         {
3091           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3092         }
3093     }
3094   else
3095     {
3096       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3097         {
3098           if (IFFUNC_CALLEESAVES (dtype))
3099             {
3100               werror (E_BANKED_WITH_CALLEESAVES);
3101             }
3102           else
3103             {
3104               aopOp (IC_LEFT (ic), ic, FALSE);
3105
3106               if (!swapBanks)
3107                 {
3108                   /* what if aopGet needs r0 or r1 ??? */
3109                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3110                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3111                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3112                 }
3113               else
3114                 {
3115                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3116                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3117                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3118                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3119                 }
3120
3121               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3122
3123               /* if send set is not empty then assign */
3124               if (_G.sendSet)
3125                 {
3126                   genSend(reverseSet(_G.sendSet));
3127                   _G.sendSet = NULL;
3128                 }
3129
3130               if (swapBanks)
3131                 {
3132                   emitcode ("mov", "psw,#0x%02x",
3133                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3134                 }
3135
3136               /* make the call */
3137               emitcode ("lcall", "__sdcc_banked_call");
3138             }
3139         }
3140       else if (_G.sendSet)
3141         {
3142           /* push the return address on to the stack */
3143           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3144           emitcode ("push", "acc");
3145           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3146           emitcode ("push", "acc");
3147
3148           /* now push the calling address */
3149           aopOp (IC_LEFT (ic), ic, FALSE);
3150
3151           pushSide (IC_LEFT (ic), FPTRSIZE);
3152
3153           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3154
3155           /* if send set is not empty the assign */
3156           if (_G.sendSet)
3157             {
3158               genSend(reverseSet(_G.sendSet));
3159               _G.sendSet = NULL;
3160             }
3161
3162           if (swapBanks)
3163             {
3164               emitcode ("mov", "psw,#0x%02x",
3165                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3166             }
3167
3168           /* make the call */
3169           emitcode ("ret", "");
3170           emitLabel (rlbl);
3171         }
3172       else /* the send set is empty */
3173         {
3174           char *l;
3175           /* now get the calling address into dptr */
3176           aopOp (IC_LEFT (ic), ic, FALSE);
3177
3178           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3179           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3180             {
3181               emitcode ("mov", "r0,%s", l);
3182               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3183               emitcode ("mov", "dph,%s", l);
3184               emitcode ("mov", "dpl,r0");
3185             }
3186           else
3187             {
3188               emitcode ("mov", "dpl,%s", l);
3189               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3190               emitcode ("mov", "dph,%s", l);
3191             }
3192
3193           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3194
3195           if (swapBanks)
3196             {
3197               emitcode ("mov", "psw,#0x%02x",
3198                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3199             }
3200
3201           /* make the call */
3202           emitcode ("lcall", "__sdcc_call_dptr");
3203         }
3204     }
3205   if (swapBanks)
3206     {
3207       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3208     }
3209
3210   /* if we need assign a result value */
3211   if ((IS_ITEMP (IC_RESULT (ic)) &&
3212        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3213        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3214         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3215       IS_TRUE_SYMOP (IC_RESULT (ic)))
3216     {
3217
3218       _G.accInUse++;
3219       aopOp (IC_RESULT (ic), ic, FALSE);
3220       _G.accInUse--;
3221
3222       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3223
3224       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3225     }
3226
3227   /* adjust the stack for parameters if required */
3228   if (ic->parmBytes)
3229     {
3230       int i;
3231       if (ic->parmBytes > 3)
3232         {
3233           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3234               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3235             {
3236               emitcode ("mov", "F0,c");
3237               resultInF0 = TRUE;
3238             }
3239
3240           emitcode ("mov", "a,%s", spname);
3241           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3242           emitcode ("mov", "%s,a", spname);
3243         }
3244       else
3245         for (i = 0; i < ic->parmBytes; i++)
3246           emitcode ("dec", "%s", spname);
3247     }
3248
3249 //  /* if register bank was saved then unsave them */
3250 //  if (restoreBank)
3251 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3252
3253   /* if we had saved some registers then unsave them */
3254   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3255     unsaveRegisters (ic);
3256
3257   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3258     {
3259       if (resultInF0)
3260           emitcode ("mov", "c,F0");
3261
3262       aopOp (IC_RESULT (ic), ic, FALSE);
3263       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3264       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3265     }
3266 }
3267
3268 /*-----------------------------------------------------------------*/
3269 /* resultRemat - result  is rematerializable                       */
3270 /*-----------------------------------------------------------------*/
3271 static int
3272 resultRemat (iCode * ic)
3273 {
3274   if (SKIP_IC (ic) || ic->op == IFX)
3275     return 0;
3276
3277   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3278     {
3279       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3280       if (sym->remat && !POINTER_SET (ic))
3281         return 1;
3282     }
3283
3284   return 0;
3285 }
3286
3287 /*-----------------------------------------------------------------*/
3288 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3289 /*-----------------------------------------------------------------*/
3290 static int
3291 regsCmp(void *p1, void *p2)
3292 {
3293   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3294 }
3295
3296 static bool
3297 inExcludeList (char *s)
3298 {
3299   const char *p = setFirstItem(options.excludeRegsSet);
3300
3301   if (p == NULL || STRCASECMP(p, "none") == 0)
3302     return FALSE;
3303
3304
3305   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3306 }
3307
3308 /*-----------------------------------------------------------------*/
3309 /* genFunction - generated code for function entry                 */
3310 /*-----------------------------------------------------------------*/
3311 static void
3312 genFunction (iCode * ic)
3313 {
3314   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3315   sym_link *ftype;
3316   bool     switchedPSW = FALSE;
3317   int      calleesaves_saved_register = -1;
3318   int      stackAdjust = sym->stack;
3319   int      accIsFree = sym->recvSize < 4;
3320   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3321   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3322
3323   _G.nRegsSaved = 0;
3324   /* create the function header */
3325   emitcode (";", "-----------------------------------------");
3326   emitcode (";", " function %s", sym->name);
3327   emitcode (";", "-----------------------------------------");
3328
3329   emitcode ("", "%s:", sym->rname);
3330   lineCurr->isLabel = 1;
3331   ftype = operandType (IC_LEFT (ic));
3332   _G.currentFunc = sym;
3333
3334   if (IFFUNC_ISNAKED(ftype))
3335   {
3336       emitcode(";", "naked function: no prologue.");
3337       return;
3338   }
3339
3340   /* here we need to generate the equates for the
3341      register bank if required */
3342   if (FUNC_REGBANK (ftype) != rbank)
3343     {
3344       int i;
3345
3346       rbank = FUNC_REGBANK (ftype);
3347       for (i = 0; i < mcs51_nRegs; i++)
3348         {
3349           if (regs8051[i].type != REG_BIT)
3350             {
3351               if (strcmp (regs8051[i].base, "0") == 0)
3352                 emitcode ("", "%s = 0x%02x",
3353                           regs8051[i].dname,
3354                           8 * rbank + regs8051[i].offset);
3355               else
3356                 emitcode ("", "%s = %s + 0x%02x",
3357                           regs8051[i].dname,
3358                           regs8051[i].base,
3359                           8 * rbank + regs8051[i].offset);
3360             }
3361         }
3362     }
3363
3364   /* if this is an interrupt service routine then
3365      save acc, b, dpl, dph  */
3366   if (IFFUNC_ISISR (sym->type))
3367     {
3368       bitVect *rsavebits;
3369
3370       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3371       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3372         {
3373           emitcode ("push", "bits");
3374           BitBankUsed = 1;
3375         }
3376       freeBitVect (rsavebits);
3377
3378       if (!inExcludeList ("acc"))
3379         emitcode ("push", "acc");
3380       if (!inExcludeList ("b"))
3381         emitcode ("push", "b");
3382       if (!inExcludeList ("dpl"))
3383         emitcode ("push", "dpl");
3384       if (!inExcludeList ("dph"))
3385         emitcode ("push", "dph");
3386       /* if this isr has no bank i.e. is going to
3387          run with bank 0 , then we need to save more
3388          registers :-) */
3389       if (!FUNC_REGBANK (sym->type))
3390         {
3391           int i;
3392
3393           /* if this function does not call any other
3394              function then we can be economical and
3395              save only those registers that are used */
3396           if (!IFFUNC_HASFCALL(sym->type))
3397             {
3398               /* if any registers used */
3399               if (sym->regsUsed)
3400                 {
3401                   /* save the registers used */
3402                   for (i = 0; i < sym->regsUsed->size; i++)
3403                     {
3404                       if (bitVectBitValue (sym->regsUsed, i))
3405                         pushReg (i, TRUE);
3406                     }
3407                 }
3408             }
3409           else
3410             {
3411               /* this function has a function call. We cannot
3412                  determine register usage so we will have to push the
3413                  entire bank */
3414                 saveRBank (0, ic, FALSE);
3415                 if (options.parms_in_bank1) {
3416                     for (i=0; i < 8 ; i++ ) {
3417                         emitcode ("push","%s",rb1regs[i]);
3418                     }
3419                 }
3420             }
3421         }
3422       else
3423         {
3424             /* This ISR uses a non-zero bank.
3425              *
3426              * We assume that the bank is available for our
3427              * exclusive use.
3428              *
3429              * However, if this ISR calls a function which uses some
3430              * other bank, we must save that bank entirely.
3431              */
3432             unsigned long banksToSave = 0;
3433
3434             if (IFFUNC_HASFCALL(sym->type))
3435             {
3436
3437 #define MAX_REGISTER_BANKS 4
3438
3439                 iCode *i;
3440                 int ix;
3441
3442                 for (i = ic; i; i = i->next)
3443                 {
3444                     if (i->op == ENDFUNCTION)
3445                     {
3446                         /* we got to the end OK. */
3447                         break;
3448                     }
3449
3450                     if (i->op == CALL)
3451                     {
3452                         sym_link *dtype;
3453
3454                         dtype = operandType (IC_LEFT(i));
3455                         if (dtype
3456                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3457                         {
3458                              /* Mark this bank for saving. */
3459                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3460                              {
3461                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3462                              }
3463                              else
3464                              {
3465                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3466                              }
3467
3468                              /* And note that we don't need to do it in
3469                               * genCall.
3470                               */
3471                              i->bankSaved = 1;
3472                         }
3473                     }
3474                     if (i->op == PCALL)
3475                     {
3476                         /* This is a mess; we have no idea what
3477                          * register bank the called function might
3478                          * use.
3479                          *
3480                          * The only thing I can think of to do is
3481                          * throw a warning and hope.
3482                          */
3483                         werror(W_FUNCPTR_IN_USING_ISR);
3484                     }
3485                 }
3486
3487                 if (banksToSave && options.useXstack)
3488                 {
3489                     /* Since we aren't passing it an ic,
3490                      * saveRBank will assume r0 is available to abuse.
3491                      *
3492                      * So switch to our (trashable) bank now, so
3493                      * the caller's R0 isn't trashed.
3494                      */
3495                     emitcode ("push", "psw");
3496                     emitcode ("mov", "psw,#0x%02x",
3497                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3498                     switchedPSW = TRUE;
3499                 }
3500
3501                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3502                 {
3503                      if (banksToSave & (1 << ix))
3504                      {
3505                          saveRBank(ix, NULL, FALSE);
3506                      }
3507                 }
3508             }
3509             // TODO: this needs a closer look
3510             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3511         }
3512
3513       /* Set the register bank to the desired value if nothing else */
3514       /* has done so yet. */
3515       if (!switchedPSW)
3516         {
3517           emitcode ("push", "psw");
3518           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3519         }
3520     }
3521   else
3522     {
3523       /* This is a non-ISR function. The caller has already switched register */
3524       /* banks, if necessary, so just handle the callee-saves option. */
3525
3526       /* if callee-save to be used for this function
3527          then save the registers being used in this function */
3528       if (IFFUNC_CALLEESAVES(sym->type))
3529         {
3530           int i;
3531
3532           /* if any registers used */
3533           if (sym->regsUsed)
3534             {
3535               bool bits_pushed = FALSE;
3536               /* save the registers used */
3537               for (i = 0; i < sym->regsUsed->size; i++)
3538                 {
3539                   if (bitVectBitValue (sym->regsUsed, i))
3540                     {
3541                       /* remember one saved register for later usage */
3542                       if (calleesaves_saved_register < 0)
3543                         calleesaves_saved_register = i;
3544                       bits_pushed = pushReg (i, bits_pushed);
3545                       _G.nRegsSaved++;
3546                     }
3547                 }
3548             }
3549         }
3550     }
3551
3552   if (fReentrant)
3553     {
3554       if (options.useXstack)
3555         {
3556           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3557             {
3558               emitcode ("mov", "r0,%s", spname);
3559               emitcode ("inc", "%s", spname);
3560               emitcode ("xch", "a,_bpx");
3561               emitcode ("movx", "@r0,a");
3562               emitcode ("inc", "r0");
3563               emitcode ("mov", "a,r0");
3564               emitcode ("xch", "a,_bpx");
3565             }
3566           if (sym->stack)
3567             {
3568               emitcode ("push", "_bp");     /* save the callers stack  */
3569               emitcode ("mov", "_bp,sp");
3570             }
3571         }
3572       else
3573         {
3574           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3575             {
3576               /* set up the stack */
3577               emitcode ("push", "_bp");     /* save the callers stack  */
3578               emitcode ("mov", "_bp,sp");
3579             }
3580         }
3581     }
3582
3583   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3584   /* before setting up the stack frame completely. */
3585   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3586     {
3587       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3588
3589       if (rsym->isitmp)
3590         {
3591           if (rsym && rsym->regType == REG_CND)
3592             rsym = NULL;
3593           if (rsym && (rsym->accuse || rsym->ruonly))
3594             rsym = NULL;
3595           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3596             rsym = rsym->usl.spillLoc;
3597         }
3598
3599       /* If the RECEIVE operand immediately spills to the first entry on the */
3600       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3601       /* rather than the usual @r0/r1 machinations. */
3602       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3603         {
3604           int ofs;
3605
3606           _G.current_iCode = ric;
3607           D(emitcode (";", "genReceive"));
3608           for (ofs=0; ofs < sym->recvSize; ofs++)
3609             {
3610               if (!strcmp (fReturn[ofs], "a"))
3611                 emitcode ("push", "acc");
3612               else
3613                 emitcode ("push", fReturn[ofs]);
3614             }
3615           stackAdjust -= sym->recvSize;
3616           if (stackAdjust<0)
3617             {
3618               assert (stackAdjust>=0);
3619               stackAdjust = 0;
3620             }
3621           _G.current_iCode = ic;
3622           ric->generated = 1;
3623           accIsFree = 1;
3624         }
3625       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3626       /* to free up the accumulator. */
3627       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3628         {
3629           int ofs;
3630
3631           _G.current_iCode = ric;
3632           D(emitcode (";", "genReceive"));
3633           for (ofs=0; ofs < sym->recvSize; ofs++)
3634             {
3635               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3636             }
3637           _G.current_iCode = ic;
3638           ric->generated = 1;
3639           accIsFree = 1;
3640         }
3641     }
3642
3643   /* adjust the stack for the function */
3644   if (stackAdjust)
3645     {
3646       int i = stackAdjust;
3647       if (i > 256)
3648         werror (W_STACK_OVERFLOW, sym->name);
3649
3650       if (i > 3 && accIsFree)
3651         {
3652           emitcode ("mov", "a,sp");
3653           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3654           emitcode ("mov", "sp,a");
3655         }
3656       else if (i > 5)
3657         {
3658           /* The accumulator is not free, so we will need another register */
3659           /* to clobber. No need to worry about a possible conflict with */
3660           /* the above early RECEIVE optimizations since they would have */
3661           /* freed the accumulator if they were generated. */
3662
3663           if (IFFUNC_CALLEESAVES(sym->type))
3664             {
3665               /* if it's a callee-saves function we need a saved register */
3666               if (calleesaves_saved_register >= 0)
3667                 {
3668                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3669                   emitcode ("mov", "a,sp");
3670                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3671                   emitcode ("mov", "sp,a");
3672                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3673                 }
3674               else
3675                 /* do it the hard way */
3676                 while (i--)
3677                   emitcode ("inc", "sp");
3678             }
3679           else
3680             {
3681               /* not callee-saves, we can clobber r0 */
3682               emitcode ("mov", "r0,a");
3683               emitcode ("mov", "a,sp");
3684               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3685               emitcode ("mov", "sp,a");
3686               emitcode ("mov", "a,r0");
3687             }
3688         }
3689       else
3690         while (i--)
3691           emitcode ("inc", "sp");
3692     }
3693
3694   if (sym->xstack)
3695     {
3696       char i = ((char) sym->xstack & 0xff);
3697
3698       if (i > 3 && accIsFree)
3699         {
3700           emitcode ("mov", "a,_spx");
3701           emitcode ("add", "a,#0x%02x", i & 0xff);
3702           emitcode ("mov", "_spx,a");
3703         }
3704       else if (i > 5)
3705         {
3706           emitcode ("push", "acc");
3707           emitcode ("mov", "a,_spx");
3708           emitcode ("add", "a,#0x%02x", i & 0xff);
3709           emitcode ("mov", "_spx,a");
3710           emitcode ("pop", "acc");
3711         }
3712       else
3713         {
3714           while (i--)
3715             emitcode ("inc", "_spx");
3716         }
3717     }
3718
3719   /* if critical function then turn interrupts off */
3720   if (IFFUNC_ISCRITICAL (ftype))
3721     {
3722       symbol *tlbl = newiTempLabel (NULL);
3723       emitcode ("setb", "c");
3724       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3725       emitcode ("clr", "c");
3726       emitLabel (tlbl);
3727       emitcode ("push", "psw"); /* save old ea via c in psw */
3728     }
3729 }
3730
3731 /*-----------------------------------------------------------------*/
3732 /* genEndFunction - generates epilogue for functions               */
3733 /*-----------------------------------------------------------------*/
3734 static void
3735 genEndFunction (iCode * ic)
3736 {
3737   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3738   lineNode *lnp = lineCurr;
3739   bitVect  *regsUsed;
3740   bitVect  *regsUsedPrologue;
3741   bitVect  *regsUnneeded;
3742   int      idx;
3743
3744   _G.currentFunc = NULL;
3745   if (IFFUNC_ISNAKED(sym->type))
3746   {
3747       emitcode(";", "naked function: no epilogue.");
3748       if (options.debug && currFunc)
3749         debugFile->writeEndFunction (currFunc, ic, 0);
3750       return;
3751   }
3752
3753   if (IFFUNC_ISCRITICAL (sym->type))
3754     {
3755       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3756         {
3757           emitcode ("rlc", "a");   /* save c in a */
3758           emitcode ("pop", "psw"); /* restore ea via c in psw */
3759           emitcode ("mov", "ea,c");
3760           emitcode ("rrc", "a");   /* restore c from a */
3761         }
3762       else
3763         {
3764           emitcode ("pop", "psw"); /* restore ea via c in psw */
3765           emitcode ("mov", "ea,c");
3766         }
3767     }
3768
3769   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3770     {
3771       if (options.useXstack)
3772         {
3773           if (sym->stack)
3774             {
3775               emitcode ("mov", "sp,_bp");
3776               emitcode ("pop", "_bp");
3777             }
3778           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3779             {
3780               emitcode ("xch", "a,_bpx");
3781               emitcode ("mov", "r0,a");
3782               emitcode ("dec", "r0");
3783               emitcode ("movx", "a,@r0");
3784               emitcode ("xch", "a,_bpx");
3785               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3786             }
3787         }
3788       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3789         {
3790           if (sym->stack)
3791             emitcode ("mov", "sp,_bp");
3792           emitcode ("pop", "_bp");
3793         }
3794     }
3795
3796   /* restore the register bank  */
3797   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3798   {
3799     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3800      || !options.useXstack)
3801     {
3802         /* Special case of ISR using non-zero bank with useXstack
3803          * is handled below.
3804          */
3805         emitcode ("pop", "psw");
3806     }
3807   }
3808
3809   if (IFFUNC_ISISR (sym->type))
3810     {
3811       bitVect *rsavebits;
3812
3813       /* now we need to restore the registers */
3814       /* if this isr has no bank i.e. is going to
3815          run with bank 0 , then we need to save more
3816          registers :-) */
3817       if (!FUNC_REGBANK (sym->type))
3818         {
3819           int i;
3820           /* if this function does not call any other
3821              function then we can be economical and
3822              save only those registers that are used */
3823           if (!IFFUNC_HASFCALL(sym->type))
3824             {
3825               /* if any registers used */
3826               if (sym->regsUsed)
3827                 {
3828                   /* save the registers used */
3829                   for (i = sym->regsUsed->size; i >= 0; i--)
3830                     {
3831                       if (bitVectBitValue (sym->regsUsed, i))
3832                         popReg (i, TRUE);
3833                     }
3834                 }
3835             }
3836           else
3837             {
3838               if (options.parms_in_bank1) {
3839                   for (i = 7 ; i >= 0 ; i-- ) {
3840                       emitcode ("pop","%s",rb1regs[i]);
3841                   }
3842               }
3843               /* this function has a function call. We cannot
3844                  determine register usage so we will have to pop the
3845                  entire bank */
3846               unsaveRBank (0, ic, FALSE);
3847             }
3848         }
3849         else
3850         {
3851             /* This ISR uses a non-zero bank.
3852              *
3853              * Restore any register banks saved by genFunction
3854              * in reverse order.
3855              */
3856             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3857             int ix;
3858
3859             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3860             {
3861                 if (savedBanks & (1 << ix))
3862                 {
3863                     unsaveRBank(ix, NULL, FALSE);
3864                 }
3865             }
3866
3867             if (options.useXstack)
3868             {
3869                 /* Restore bank AFTER calling unsaveRBank,
3870                  * since it can trash r0.
3871                  */
3872                 emitcode ("pop", "psw");
3873             }
3874         }
3875
3876       if (!inExcludeList ("dph"))
3877         emitcode ("pop", "dph");
3878       if (!inExcludeList ("dpl"))
3879         emitcode ("pop", "dpl");
3880       if (!inExcludeList ("b"))
3881         emitcode ("pop", "b");
3882       if (!inExcludeList ("acc"))
3883         emitcode ("pop", "acc");
3884
3885       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3886       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3887         emitcode ("pop", "bits");
3888       freeBitVect (rsavebits);
3889
3890       /* if debug then send end of function */
3891       if (options.debug && currFunc)
3892         {
3893           debugFile->writeEndFunction (currFunc, ic, 1);
3894         }
3895
3896       emitcode ("reti", "");
3897     }
3898   else
3899     {
3900       if (IFFUNC_CALLEESAVES(sym->type))
3901         {
3902           int i;
3903
3904           /* if any registers used */
3905           if (sym->regsUsed)
3906             {
3907               /* save the registers used */
3908               for (i = sym->regsUsed->size; i >= 0; i--)
3909                 {
3910                   if (bitVectBitValue (sym->regsUsed, i) ||
3911                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3912                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3913                 }
3914             }
3915           else if (mcs51_ptrRegReq)
3916             {
3917               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3918               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3919             }
3920
3921         }
3922
3923       /* if debug then send end of function */
3924       if (options.debug && currFunc)
3925         {
3926           debugFile->writeEndFunction (currFunc, ic, 1);
3927         }
3928
3929       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3930         {
3931           emitcode ("ljmp", "__sdcc_banked_ret");
3932         }
3933       else
3934         {
3935           emitcode ("ret", "");
3936         }
3937     }
3938
3939   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3940     return;
3941
3942   /* If this was an interrupt handler using bank 0 that called another */
3943   /* function, then all registers must be saved; nothing to optimized. */
3944   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3945       && !FUNC_REGBANK(sym->type))
3946     return;
3947
3948   /* There are no push/pops to optimize if not callee-saves or ISR */
3949   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3950     return;
3951
3952   /* If there were stack parameters, we cannot optimize without also    */
3953   /* fixing all of the stack offsets; this is too dificult to consider. */
3954   if (FUNC_HASSTACKPARM(sym->type))
3955     return;
3956
3957   /* Compute the registers actually used */
3958   regsUsed = newBitVect (mcs51_nRegs);
3959   regsUsedPrologue = newBitVect (mcs51_nRegs);
3960   while (lnp)
3961     {
3962       if (lnp->ic && lnp->ic->op == FUNCTION)
3963         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3964       else
3965         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3966
3967       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3968           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3969         break;
3970       if (!lnp->prev)
3971         break;
3972       lnp = lnp->prev;
3973     }
3974
3975   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3976       && !bitVectBitValue (regsUsed, CND_IDX))
3977     {
3978       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3979       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3980           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3981         bitVectUnSetBit (regsUsed, CND_IDX);
3982     }
3983   else
3984     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3985
3986   /* If this was an interrupt handler that called another function */
3987   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3988   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3989     {
3990       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3991       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3992       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3993       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3995     }
3996
3997   /* Remove the unneeded push/pops */
3998   regsUnneeded = newBitVect (mcs51_nRegs);
3999   while (lnp)
4000     {
4001       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4002         {
4003           if (!strncmp(lnp->line, "push", 4))
4004             {
4005               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4006               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4007                 {
4008                   connectLine (lnp->prev, lnp->next);
4009                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4010                 }
4011             }
4012           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4013             {
4014               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4015               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4016                 {
4017                   connectLine (lnp->prev, lnp->next);
4018                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4019                 }
4020             }
4021         }
4022       lnp = lnp->next;
4023     }
4024
4025   for (idx = 0; idx < regsUnneeded->size; idx++)
4026     if (bitVectBitValue (regsUnneeded, idx))
4027       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4028
4029   freeBitVect (regsUnneeded);
4030   freeBitVect (regsUsed);
4031   freeBitVect (regsUsedPrologue);
4032 }
4033
4034 /*-----------------------------------------------------------------*/
4035 /* genRet - generate code for return statement                     */
4036 /*-----------------------------------------------------------------*/
4037 static void
4038 genRet (iCode * ic)
4039 {
4040   int size, offset = 0, pushed = 0;
4041
4042   D (emitcode (";", "genRet"));
4043
4044   /* if we have no return value then
4045      just generate the "ret" */
4046   if (!IC_LEFT (ic))
4047     goto jumpret;
4048
4049   /* we have something to return then
4050      move the return value into place */
4051   aopOp (IC_LEFT (ic), ic, FALSE);
4052   size = AOP_SIZE (IC_LEFT (ic));
4053
4054   if (IS_BIT(_G.currentFunc->etype))
4055     {
4056       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4057         toCarry (IC_LEFT (ic));
4058     }
4059   else
4060     {
4061       while (size--)
4062         {
4063           char *l;
4064           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4065             {
4066               /* #NOCHANGE */
4067               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4068               emitcode ("push", "%s", l);
4069               pushed++;
4070             }
4071           else
4072             {
4073               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4074               if (strcmp (fReturn[offset], l))
4075                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4076             }
4077         }
4078
4079       while (pushed)
4080         {
4081           pushed--;
4082           if (strcmp (fReturn[pushed], "a"))
4083             emitcode ("pop", fReturn[pushed]);
4084           else
4085             emitcode ("pop", "acc");
4086         }
4087     }
4088   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4089
4090 jumpret:
4091   /* generate a jump to the return label
4092      if the next is not the return statement */
4093   if (!(ic->next && ic->next->op == LABEL &&
4094         IC_LABEL (ic->next) == returnLabel))
4095
4096     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4097
4098 }
4099
4100 /*-----------------------------------------------------------------*/
4101 /* genLabel - generates a label                                    */
4102 /*-----------------------------------------------------------------*/
4103 static void
4104 genLabel (iCode * ic)
4105 {
4106   /* special case never generate */
4107   if (IC_LABEL (ic) == entryLabel)
4108     return;
4109
4110   emitLabel (IC_LABEL (ic));
4111 }
4112
4113 /*-----------------------------------------------------------------*/
4114 /* genGoto - generates a ljmp                                      */
4115 /*-----------------------------------------------------------------*/
4116 static void
4117 genGoto (iCode * ic)
4118 {
4119   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4120 }
4121
4122 /*-----------------------------------------------------------------*/
4123 /* findLabelBackwards: walks back through the iCode chain looking  */
4124 /* for the given label. Returns number of iCode instructions     */
4125 /* between that label and given ic.          */
4126 /* Returns zero if label not found.          */
4127 /*-----------------------------------------------------------------*/
4128 static int
4129 findLabelBackwards (iCode * ic, int key)
4130 {
4131   int count = 0;
4132
4133   while (ic->prev)
4134     {
4135       ic = ic->prev;
4136       count++;
4137
4138       /* If we have any pushes or pops, we cannot predict the distance.
4139          I don't like this at all, this should be dealt with in the
4140          back-end */
4141       if (ic->op == IPUSH || ic->op == IPOP) {
4142         return 0;
4143       }
4144
4145       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4146         {
4147           return count;
4148         }
4149     }
4150
4151   return 0;
4152 }
4153
4154 /*-----------------------------------------------------------------*/
4155 /* genPlusIncr :- does addition with increment if possible         */
4156 /*-----------------------------------------------------------------*/
4157 static bool
4158 genPlusIncr (iCode * ic)
4159 {
4160   unsigned int icount;
4161   unsigned int size = getDataSize (IC_RESULT (ic));
4162
4163   /* will try to generate an increment */
4164   /* if the right side is not a literal
4165      we cannot */
4166   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4167     return FALSE;
4168
4169   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4170
4171   D(emitcode (";","genPlusIncr"));
4172
4173   /* if increment >=16 bits in register or direct space */
4174   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4175         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4176         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4177       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4178       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4179       (size > 1) &&
4180       (icount == 1))
4181     {
4182       symbol *tlbl;
4183       int emitTlbl;
4184       int labelRange;
4185
4186       /* If the next instruction is a goto and the goto target
4187        * is < 10 instructions previous to this, we can generate
4188        * jumps straight to that target.
4189        */
4190       if (ic->next && ic->next->op == GOTO
4191           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4192           && labelRange <= 10)
4193         {
4194           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4195           tlbl = IC_LABEL (ic->next);
4196           emitTlbl = 0;
4197         }
4198       else
4199         {
4200           tlbl = newiTempLabel (NULL);
4201           emitTlbl = 1;
4202         }
4203       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4204       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4205           IS_AOP_PREG (IC_RESULT (ic)))
4206         emitcode ("cjne", "%s,#0x00,%05d$",
4207                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4208                   tlbl->key + 100);
4209       else
4210         {
4211           emitcode ("clr", "a");
4212           emitcode ("cjne", "a,%s,%05d$",
4213                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4214                     tlbl->key + 100);
4215         }
4216
4217       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4218       if (size > 2)
4219         {
4220           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4221               IS_AOP_PREG (IC_RESULT (ic)))
4222             emitcode ("cjne", "%s,#0x00,%05d$",
4223                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4224                       tlbl->key + 100);
4225           else
4226             emitcode ("cjne", "a,%s,%05d$",
4227                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4228                       tlbl->key + 100);
4229
4230           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4231         }
4232       if (size > 3)
4233         {
4234           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4235               IS_AOP_PREG (IC_RESULT (ic)))
4236             emitcode ("cjne", "%s,#0x00,%05d$",
4237                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4238                       tlbl->key + 100);
4239           else
4240             {
4241               emitcode ("cjne", "a,%s,%05d$",
4242                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4243                         tlbl->key + 100);
4244             }
4245           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4246         }
4247
4248       if (emitTlbl)
4249         {
4250           emitLabel (tlbl);
4251         }
4252       return TRUE;
4253     }
4254
4255   /* if result is dptr */
4256   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4257       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4258       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4259       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4260     {
4261       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4262         return FALSE;
4263
4264       if (icount > 9)
4265         return FALSE;
4266
4267       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4268         return FALSE;
4269
4270       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4271       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4272       while (icount--)
4273         emitcode ("inc", "dptr");
4274
4275       return TRUE;
4276     }
4277
4278   /* if the literal value of the right hand side
4279      is greater than 4 then it is not worth it */
4280   if (icount > 4)
4281     return FALSE;
4282
4283   /* if the sizes are greater than 1 then we cannot */
4284   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4285       AOP_SIZE (IC_LEFT (ic)) > 1)
4286     return FALSE;
4287
4288   /* we can if the aops of the left & result match or
4289      if they are in registers and the registers are the
4290      same */
4291   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4292     {
4293       if (icount > 3)
4294         {
4295           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4296           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4297           aopPut (IC_RESULT (ic), "a", 0);
4298         }
4299       else
4300         {
4301           while (icount--)
4302             {
4303               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4304             }
4305         }
4306
4307       return TRUE;
4308     }
4309
4310   if (icount == 1)
4311     {
4312       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4313       emitcode ("inc", "a");
4314       aopPut (IC_RESULT (ic), "a", 0);
4315       return TRUE;
4316     }
4317
4318   return FALSE;
4319 }
4320
4321 /*-----------------------------------------------------------------*/
4322 /* outBitAcc - output a bit in acc                                 */
4323 /*-----------------------------------------------------------------*/
4324 static void
4325 outBitAcc (operand * result)
4326 {
4327   symbol *tlbl = newiTempLabel (NULL);
4328   /* if the result is a bit */
4329   if (AOP_TYPE (result) == AOP_CRY)
4330     {
4331       aopPut (result, "a", 0);
4332     }
4333   else
4334     {
4335       emitcode ("jz", "%05d$", tlbl->key + 100);
4336       emitcode ("mov", "a,%s", one);
4337       emitLabel (tlbl);
4338       outAcc (result);
4339     }
4340 }
4341
4342 /*-----------------------------------------------------------------*/
4343 /* genPlusBits - generates code for addition of two bits           */
4344 /*-----------------------------------------------------------------*/
4345 static void
4346 genPlusBits (iCode * ic)
4347 {
4348   D (emitcode (";", "genPlusBits"));
4349
4350   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4351   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4352     {
4353       symbol *lbl = newiTempLabel (NULL);
4354       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4355       emitcode ("cpl", "c");
4356       emitLabel (lbl);
4357       outBitC (IC_RESULT (ic));
4358     }
4359   else
4360     {
4361       emitcode ("clr", "a");
4362       emitcode ("rlc", "a");
4363       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4364       emitcode ("addc", "a,%s", zero);
4365       outAcc (IC_RESULT (ic));
4366     }
4367 }
4368
4369 #if 0
4370 /* This is the original version of this code.
4371
4372  * This is being kept around for reference,
4373  * because I am not entirely sure I got it right...
4374  */
4375 static void
4376 adjustArithmeticResult (iCode * ic)
4377 {
4378   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4379       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4380       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4381     aopPut (IC_RESULT (ic),
4382             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4383             2);
4384
4385   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4386       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4387       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4388     aopPut (IC_RESULT (ic),
4389             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4390             2);
4391
4392   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4393       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4394       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4395       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4396       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4397     {
4398       char buffer[5];
4399       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4400       aopPut (IC_RESULT (ic), buffer, 2);
4401     }
4402 }
4403 #else
4404 /* This is the pure and virtuous version of this code.
4405  * I'm pretty certain it's right, but not enough to toss the old
4406  * code just yet...
4407  */
4408 static void
4409 adjustArithmeticResult (iCode * ic)
4410 {
4411   if (opIsGptr (IC_RESULT (ic)) &&
4412       opIsGptr (IC_LEFT (ic)) &&
4413       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4414     {
4415       aopPut (IC_RESULT (ic),
4416               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4417               GPTRSIZE - 1);
4418     }
4419
4420   if (opIsGptr (IC_RESULT (ic)) &&
4421       opIsGptr (IC_RIGHT (ic)) &&
4422       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4423     {
4424       aopPut (IC_RESULT (ic),
4425               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4426               GPTRSIZE - 1);
4427     }
4428
4429   if (opIsGptr (IC_RESULT (ic)) &&
4430       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4431       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4432       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4433       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4434     {
4435       char buffer[5];
4436       SNPRINTF (buffer, sizeof(buffer),
4437                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4438       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4439     }
4440 }
4441 #endif
4442
4443 /*-----------------------------------------------------------------*/
4444 /* genPlus - generates code for addition                           */
4445 /*-----------------------------------------------------------------*/
4446 static void
4447 genPlus (iCode * ic)
4448 {
4449   int size, offset = 0;
4450   int skip_bytes = 0;
4451   char *add = "add";
4452   bool swappedLR = FALSE;
4453   operand *leftOp, *rightOp;
4454   operand * op;
4455
4456   D (emitcode (";", "genPlus"));
4457
4458   /* special cases :- */
4459
4460   aopOp (IC_LEFT (ic), ic, FALSE);
4461   aopOp (IC_RIGHT (ic), ic, FALSE);
4462   aopOp (IC_RESULT (ic), ic, TRUE);
4463
4464   /* if literal, literal on the right or
4465      if left requires ACC or right is already
4466      in ACC */
4467   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4468       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4469       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4470     {
4471       operand *t = IC_RIGHT (ic);
4472       IC_RIGHT (ic) = IC_LEFT (ic);
4473       IC_LEFT (ic) = t;
4474       swappedLR = TRUE;
4475     }
4476
4477   /* if both left & right are in bit
4478      space */
4479   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4480       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4481     {
4482       genPlusBits (ic);
4483       goto release;
4484     }
4485
4486   /* if left in bit space & right literal */
4487   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4488       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4489     {
4490       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4491       /* if result in bit space */
4492       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4493         {
4494           if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4495             emitcode ("cpl", "c");
4496           outBitC (IC_RESULT (ic));
4497         }
4498       else
4499         {
4500           size = getDataSize (IC_RESULT (ic));
4501           while (size--)
4502             {
4503               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4504               emitcode ("addc", "a,%s", zero);
4505               aopPut (IC_RESULT (ic), "a", offset++);
4506             }
4507         }
4508       goto release;
4509     }
4510
4511   /* if I can do an increment instead
4512      of add then GOOD for ME */
4513   if (genPlusIncr (ic) == TRUE)
4514     goto release;
4515
4516   size = getDataSize (IC_RESULT (ic));
4517   leftOp = IC_LEFT(ic);
4518   rightOp = IC_RIGHT(ic);
4519   op = IC_LEFT(ic);
4520
4521   /* if this is an add for an array access
4522      at a 256 byte boundary */
4523   if ( 2 == size
4524        && AOP_TYPE (op) == AOP_IMMD
4525        && IS_SYMOP (op)
4526        && IS_SPEC (OP_SYM_ETYPE (op))
4527        && SPEC_ABSA (OP_SYM_ETYPE (op))
4528        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4529      )
4530     {
4531       D(emitcode (";", "genPlus aligned array"));
4532       aopPut (IC_RESULT (ic),
4533               aopGet (rightOp, 0, FALSE, FALSE),
4534               0);
4535
4536       if( 1 == getDataSize (IC_RIGHT (ic)) )
4537         {
4538           aopPut (IC_RESULT (ic),
4539                   aopGet (leftOp, 1, FALSE, FALSE),
4540                   1);
4541         }
4542       else
4543         {
4544           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4545           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4546           aopPut (IC_RESULT (ic), "a", 1);
4547         }
4548       goto release;
4549     }
4550
4551   /* if the lower bytes of a literal are zero skip the addition */
4552   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4553     {
4554        while ((0 == ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4555               (skip_bytes+1 < size))
4556          {
4557            skip_bytes++;
4558          }
4559        if (skip_bytes)
4560          D(emitcode (";", "genPlus shortcut"));
4561     }
4562
4563   while (size--)
4564     {
4565       if( offset >= skip_bytes )
4566         {
4567           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4568             {
4569               bool pushedB;
4570               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4571               pushedB = pushB ();
4572               emitcode("xch", "a,b");
4573               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4574               emitcode (add, "a,b");
4575               popB (pushedB);
4576             }
4577           else if (aopGetUsesAcc (leftOp, offset))
4578             {
4579               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4580               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4581             }
4582           else
4583             {
4584               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4585               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4586             }
4587           aopPut (IC_RESULT (ic), "a", offset);
4588           add = "addc";  /* further adds must propagate carry */
4589         }
4590       else
4591         {
4592           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4593               isOperandVolatile (IC_RESULT (ic), FALSE))
4594             {
4595               /* just move */
4596               aopPut (IC_RESULT (ic),
4597                       aopGet (leftOp, offset, FALSE, FALSE),
4598                       offset);
4599             }
4600         }
4601       offset++;
4602     }
4603
4604   adjustArithmeticResult (ic);
4605
4606 release:
4607   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4608   if (!swappedLR)
4609     {
4610       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4611       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4612     }
4613   else
4614     {
4615       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4616       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4617     }
4618 }
4619
4620 /*-----------------------------------------------------------------*/
4621 /* genMinusDec :- does subtraction with decrement if possible      */
4622 /*-----------------------------------------------------------------*/
4623 static bool
4624 genMinusDec (iCode * ic)
4625 {
4626   unsigned int icount;
4627   unsigned int size = getDataSize (IC_RESULT (ic));
4628
4629   /* will try to generate an increment */
4630   /* if the right side is not a literal
4631      we cannot */
4632   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4633     return FALSE;
4634
4635   /* if the literal value of the right hand side
4636      is greater than 4 then it is not worth it */
4637   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4638     return FALSE;
4639
4640   D (emitcode (";", "genMinusDec"));
4641
4642   /* if decrement >=16 bits in register or direct space */
4643   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG || 
4644         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4645         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4646       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4647       (size > 1) &&
4648       (icount == 1))
4649     {
4650       symbol *tlbl;
4651       int emitTlbl;
4652       int labelRange;
4653
4654       /* If the next instruction is a goto and the goto target
4655        * is <= 10 instructions previous to this, we can generate
4656        * jumps straight to that target.
4657        */
4658       if (ic->next && ic->next->op == GOTO
4659           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4660           && labelRange <= 10)
4661         {
4662           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4663           tlbl = IC_LABEL (ic->next);
4664           emitTlbl = 0;
4665         }
4666       else
4667         {
4668           tlbl = newiTempLabel (NULL);
4669           emitTlbl = 1;
4670         }
4671
4672       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4673       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4674           IS_AOP_PREG (IC_RESULT (ic)))
4675         emitcode ("cjne", "%s,#0xff,%05d$"
4676                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4677                   ,tlbl->key + 100);
4678       else
4679         {
4680           emitcode ("mov", "a,#0xff");
4681           emitcode ("cjne", "a,%s,%05d$"
4682                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4683                     ,tlbl->key + 100);
4684         }
4685       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4686       if (size > 2)
4687         {
4688           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4689               IS_AOP_PREG (IC_RESULT (ic)))
4690             emitcode ("cjne", "%s,#0xff,%05d$"
4691                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4692                       ,tlbl->key + 100);
4693           else
4694             {
4695               emitcode ("cjne", "a,%s,%05d$"
4696                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4697                         ,tlbl->key + 100);
4698             }
4699           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4700         }
4701       if (size > 3)
4702         {
4703           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4704               IS_AOP_PREG (IC_RESULT (ic)))
4705             emitcode ("cjne", "%s,#0xff,%05d$"
4706                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4707                       ,tlbl->key + 100);
4708           else
4709             {
4710               emitcode ("cjne", "a,%s,%05d$"
4711                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4712                         ,tlbl->key + 100);
4713             }
4714           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4715         }
4716       if (emitTlbl)
4717         {
4718           emitLabel (tlbl);
4719         }
4720       return TRUE;
4721     }
4722
4723   /* if the sizes are greater than 1 then we cannot */
4724   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4725       AOP_SIZE (IC_LEFT (ic)) > 1)
4726     return FALSE;
4727
4728   /* we can if the aops of the left & result match or
4729      if they are in registers and the registers are the
4730      same */
4731   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4732     {
4733       char *l;
4734
4735       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4736         {
4737           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4738           l = "a";
4739         }
4740       else
4741         {
4742           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4743         }
4744
4745       while (icount--)
4746         {
4747           emitcode ("dec", "%s", l);
4748         }
4749
4750       if (AOP_NEEDSACC (IC_RESULT (ic)))
4751         aopPut (IC_RESULT (ic), "a", 0);
4752
4753       return TRUE;
4754     }
4755
4756   if (icount == 1)
4757     {
4758       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4759       emitcode ("dec", "a");
4760       aopPut (IC_RESULT (ic), "a", 0);
4761       return TRUE;
4762     }
4763
4764   return FALSE;
4765 }
4766
4767 /*-----------------------------------------------------------------*/
4768 /* addSign - complete with sign                                    */
4769 /*-----------------------------------------------------------------*/
4770 static void
4771 addSign (operand * result, int offset, int sign)
4772 {
4773   int size = (getDataSize (result) - offset);
4774   if (size > 0)
4775     {
4776       if (sign)
4777         {
4778           emitcode ("rlc", "a");
4779           emitcode ("subb", "a,acc");
4780           while (size--)
4781             {
4782               aopPut (result, "a", offset++);
4783             }
4784         }
4785       else
4786         {
4787           while (size--)
4788             {
4789               aopPut (result, zero, offset++);
4790             }
4791         }
4792     }
4793 }
4794
4795 /*-----------------------------------------------------------------*/
4796 /* genMinusBits - generates code for subtraction  of two bits      */
4797 /*-----------------------------------------------------------------*/
4798 static void
4799 genMinusBits (iCode * ic)
4800 {
4801   symbol *lbl = newiTempLabel (NULL);
4802
4803   D (emitcode (";", "genMinusBits"));
4804
4805   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4806     {
4807       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4808       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4809       emitcode ("cpl", "c");
4810       emitLabel (lbl);
4811       outBitC (IC_RESULT (ic));
4812     }
4813   else
4814     {
4815       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4816       emitcode ("subb", "a,acc");
4817       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4818       emitcode ("inc", "a");
4819       emitLabel (lbl);
4820       aopPut (IC_RESULT (ic), "a", 0);
4821       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4822     }
4823 }
4824
4825 /*-----------------------------------------------------------------*/
4826 /* genMinus - generates code for subtraction                       */
4827 /*-----------------------------------------------------------------*/
4828 static void
4829 genMinus (iCode * ic)
4830 {
4831   int size, offset = 0;
4832
4833   D (emitcode (";", "genMinus"));
4834
4835   aopOp (IC_LEFT (ic), ic, FALSE);
4836   aopOp (IC_RIGHT (ic), ic, FALSE);
4837   aopOp (IC_RESULT (ic), ic, TRUE);
4838
4839   /* special cases :- */
4840   /* if both left & right are in bit space */
4841   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4842       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4843     {
4844       genMinusBits (ic);
4845       goto release;
4846     }
4847
4848   /* if I can do an decrement instead
4849      of subtract then GOOD for ME */
4850   if (genMinusDec (ic) == TRUE)
4851     goto release;
4852
4853   size = getDataSize (IC_RESULT (ic));
4854
4855   /* if literal, add a,#-lit, else normal subb */
4856   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4857     {
4858       unsigned long lit = 0L;
4859       bool useCarry = FALSE;
4860
4861       lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4862       lit = -(long) lit;
4863
4864       while (size--)
4865         {
4866           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4867             {
4868               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4869               if (!offset && !size && lit== (unsigned long) -1)
4870                 {
4871                   emitcode ("dec", "a");
4872                 }
4873               else if (!useCarry)
4874                 {
4875                   /* first add without previous c */
4876                   emitcode ("add", "a,#0x%02x",
4877                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4878                   useCarry = TRUE;
4879                 }
4880               else
4881                 {
4882                   emitcode ("addc", "a,#0x%02x",
4883                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4884                 }
4885               aopPut (IC_RESULT (ic), "a", offset++);
4886             }
4887           else
4888             {
4889               /* no need to add zeroes */
4890               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4891                 {
4892                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4893                           offset);
4894                 }
4895               offset++;
4896             }
4897         }
4898     }
4899   else
4900     {
4901       operand *leftOp, *rightOp;
4902
4903       leftOp = IC_LEFT(ic);
4904       rightOp = IC_RIGHT(ic);
4905
4906       while (size--)
4907         {
4908           if (aopGetUsesAcc(rightOp, offset)) {
4909             if (aopGetUsesAcc(leftOp, offset)) {
4910               bool pushedB;
4911
4912               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4913               pushedB = pushB ();
4914               emitcode ("mov", "b,a");
4915               if (offset == 0)
4916                 CLRC;
4917               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4918               emitcode ("subb", "a,b");
4919               popB (pushedB);
4920             } else {
4921               /* reverse subtraction with 2's complement */
4922               if (offset == 0)
4923                 emitcode( "setb", "c");
4924               else
4925                 emitcode( "cpl", "c");
4926               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4927               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4928               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4929               emitcode("cpl", "a");
4930               if (size) /* skip if last byte */
4931                 emitcode( "cpl", "c");
4932             }
4933           } else {
4934             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4935             if (offset == 0)
4936               CLRC;
4937             emitcode ("subb", "a,%s",
4938                       aopGet(rightOp, offset, FALSE, TRUE));
4939           }
4940
4941           aopPut (IC_RESULT (ic), "a", offset++);
4942         }
4943     }
4944
4945   adjustArithmeticResult (ic);
4946
4947 release:
4948   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4949   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4950   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4951 }
4952
4953
4954 /*-----------------------------------------------------------------*/
4955 /* genMultbits :- multiplication of bits                           */
4956 /*-----------------------------------------------------------------*/
4957 static void
4958 genMultbits (operand * left,
4959              operand * right,
4960              operand * result)
4961 {
4962   D (emitcode (";", "genMultbits"));
4963
4964   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4965   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4966   outBitC (result);
4967 }
4968
4969 /*-----------------------------------------------------------------*/
4970 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4971 /*-----------------------------------------------------------------*/
4972 static void
4973 genMultOneByte (operand * left,
4974                 operand * right,
4975                 operand * result)
4976 {
4977   symbol *lbl;
4978   int size = AOP_SIZE (result);
4979   bool runtimeSign, compiletimeSign;
4980   bool lUnsigned, rUnsigned, pushedB;
4981
4982   D (emitcode (";", "genMultOneByte"));
4983
4984   if (size < 1 || size > 2)
4985     {
4986       /* this should never happen */
4987       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4988                AOP_SIZE(result), __FILE__, lineno);
4989       exit (1);
4990     }
4991
4992   /* (if two literals: the value is computed before) */
4993   /* if one literal, literal on the right */
4994   if (AOP_TYPE (left) == AOP_LIT)
4995     {
4996       operand *t = right;
4997       right = left;
4998       left = t;
4999       /* emitcode (";", "swapped left and right"); */
5000     }
5001   /* if no literal, unsigned on the right: shorter code */
5002   if (   AOP_TYPE (right) != AOP_LIT
5003       && SPEC_USIGN (getSpec (operandType (left))))
5004     {
5005       operand *t = right;
5006       right = left;
5007       left = t;
5008     }
5009
5010   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5011   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5012
5013   pushedB = pushB ();
5014
5015   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5016                    no need to take care about the signedness! */
5017       || (lUnsigned && rUnsigned))
5018     {
5019       /* just an unsigned 8 * 8 = 8 multiply
5020          or 8u * 8u = 16u */
5021       /* emitcode (";","unsigned"); */
5022       /* TODO: check for accumulator clash between left & right aops? */
5023
5024       if (AOP_TYPE (right) == AOP_LIT)
5025         {
5026           /* moving to accumulator first helps peepholes */
5027           MOVA (aopGet (left, 0, FALSE, FALSE));
5028           MOVB (aopGet (right, 0, FALSE, FALSE));
5029         }
5030       else
5031         {
5032           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5033           MOVA (aopGet (left, 0, FALSE, FALSE));
5034         }
5035
5036       emitcode ("mul", "ab");
5037       aopPut (result, "a", 0);
5038       if (size == 2)
5039         aopPut (result, "b", 1);
5040
5041       popB (pushedB);
5042       return;
5043     }
5044
5045   /* we have to do a signed multiply */
5046   /* emitcode (";", "signed"); */
5047
5048   /* now sign adjust for both left & right */
5049
5050   /* let's see what's needed: */
5051   /* apply negative sign during runtime */
5052   runtimeSign = FALSE;
5053   /* negative sign from literals */
5054   compiletimeSign = FALSE;
5055
5056   if (!lUnsigned)
5057     {
5058       if (AOP_TYPE(left) == AOP_LIT)
5059         {
5060           /* signed literal */
5061           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5062           if (val < 0)
5063             compiletimeSign = TRUE;
5064         }
5065       else
5066         /* signed but not literal */
5067         runtimeSign = TRUE;
5068     }
5069
5070   if (!rUnsigned)
5071     {
5072       if (AOP_TYPE(right) == AOP_LIT)
5073         {
5074           /* signed literal */
5075           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5076           if (val < 0)
5077             compiletimeSign ^= TRUE;
5078         }
5079       else
5080         /* signed but not literal */
5081         runtimeSign = TRUE;
5082     }
5083
5084   /* initialize F0, which stores the runtime sign */
5085   if (runtimeSign)
5086     {
5087       if (compiletimeSign)
5088         emitcode ("setb", "F0"); /* set sign flag */
5089       else
5090         emitcode ("clr", "F0"); /* reset sign flag */
5091     }
5092
5093   /* save the signs of the operands */
5094   if (AOP_TYPE(right) == AOP_LIT)
5095     {
5096       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5097
5098       if (!rUnsigned && val < 0)
5099         emitcode ("mov", "b,#0x%02x", -val);
5100       else
5101         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5102     }
5103   else /* ! literal */
5104     {
5105       if (rUnsigned)  /* emitcode (";", "signed"); */
5106         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5107       else
5108         {
5109           MOVA (aopGet (right, 0, FALSE, FALSE));
5110           lbl = newiTempLabel (NULL);
5111           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5112           emitcode ("cpl", "F0"); /* complement sign flag */
5113           emitcode ("cpl", "a");  /* 2's complement */
5114           emitcode ("inc", "a");
5115           emitLabel (lbl);
5116           emitcode ("mov", "b,a");
5117         }
5118     }
5119
5120   if (AOP_TYPE(left) == AOP_LIT)
5121     {
5122       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5123
5124       if (!lUnsigned && val < 0)
5125         emitcode ("mov", "a,#0x%02x", -val);
5126       else
5127         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5128     }
5129   else /* ! literal */
5130     {
5131       MOVA (aopGet (left, 0, FALSE, FALSE));
5132
5133       if (!lUnsigned)
5134         {
5135           lbl = newiTempLabel (NULL);
5136           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5137           emitcode ("cpl", "F0"); /* complement sign flag */
5138           emitcode ("cpl", "a"); /* 2's complement */
5139           emitcode ("inc", "a");
5140           emitLabel (lbl);
5141         }
5142     }
5143
5144   /* now the multiplication */
5145   emitcode ("mul", "ab");
5146   if (runtimeSign || compiletimeSign)
5147     {
5148       lbl = newiTempLabel (NULL);
5149       if (runtimeSign)
5150         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5151       emitcode ("cpl", "a"); /* lsb 2's complement */
5152       if (size != 2)
5153         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5154       else
5155         {
5156           emitcode ("add", "a,#1"); /* this sets carry flag */
5157           emitcode ("xch", "a,b");
5158           emitcode ("cpl", "a"); /* msb 2's complement */
5159           emitcode ("addc", "a,#0");
5160           emitcode ("xch", "a,b");
5161         }
5162       emitLabel (lbl);
5163     }
5164   aopPut (result, "a", 0);
5165   if (size == 2)
5166     aopPut (result, "b", 1);
5167
5168   popB (pushedB);
5169 }
5170
5171 /*-----------------------------------------------------------------*/
5172 /* genMult - generates code for multiplication                     */
5173 /*-----------------------------------------------------------------*/
5174 static void
5175 genMult (iCode * ic)
5176 {
5177   operand *left = IC_LEFT (ic);
5178   operand *right = IC_RIGHT (ic);
5179   operand *result = IC_RESULT (ic);
5180
5181   D (emitcode (";", "genMult"));
5182
5183   /* assign the asmops */
5184   aopOp (left, ic, FALSE);
5185   aopOp (right, ic, FALSE);
5186   aopOp (result, ic, TRUE);
5187
5188   /* special cases first */
5189   /* both are bits */
5190   if (AOP_TYPE (left) == AOP_CRY &&
5191       AOP_TYPE (right) == AOP_CRY)
5192     {
5193       genMultbits (left, right, result);
5194       goto release;
5195     }
5196
5197   /* if both are of size == 1 */
5198 #if 0 // one of them can be a sloc shared with the result
5199     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5200 #else
5201   if (getSize(operandType(left)) == 1 &&
5202       getSize(operandType(right)) == 1)
5203 #endif
5204     {
5205       genMultOneByte (left, right, result);
5206       goto release;
5207     }
5208
5209   /* should have been converted to function call */
5210     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5211              getSize(OP_SYMBOL(right)->type));
5212   assert (0);
5213
5214 release:
5215   freeAsmop (result, NULL, ic, TRUE);
5216   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5217   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5218 }
5219
5220 /*-----------------------------------------------------------------*/
5221 /* genDivbits :- division of bits                                  */
5222 /*-----------------------------------------------------------------*/
5223 static void
5224 genDivbits (operand * left,
5225             operand * right,
5226             operand * result)
5227 {
5228   char *l;
5229   bool pushedB;
5230
5231   D(emitcode (";", "genDivbits"));
5232
5233   pushedB = pushB ();
5234
5235   /* the result must be bit */
5236   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5237   l = aopGet (left, 0, FALSE, FALSE);
5238
5239   MOVA (l);
5240
5241   emitcode ("div", "ab");
5242   emitcode ("rrc", "a");
5243
5244   popB (pushedB);
5245
5246   aopPut (result, "c", 0);
5247 }
5248
5249 /*-----------------------------------------------------------------*/
5250 /* genDivOneByte : 8 bit division                                  */
5251 /*-----------------------------------------------------------------*/
5252 static void
5253 genDivOneByte (operand * left,
5254                operand * right,
5255                operand * result)
5256 {
5257   bool lUnsigned, rUnsigned, pushedB;
5258   bool runtimeSign, compiletimeSign;
5259   bool accuse = FALSE;
5260   bool pushedA = FALSE;
5261   symbol *lbl;
5262   int size, offset;
5263
5264   D(emitcode (";", "genDivOneByte"));
5265
5266   /* Why is it necessary that genDivOneByte() can return an int result?
5267      Have a look at:
5268
5269         volatile unsigned char uc;
5270         volatile signed char sc1, sc2;
5271         volatile int i;
5272
5273         uc  = 255;
5274         sc1 = -1;
5275         i = uc / sc1;
5276
5277      Or:
5278
5279         sc1 = -128;
5280         sc2 = -1;
5281         i = sc1 / sc2;
5282
5283      In all cases a one byte result would overflow, the following cast to int
5284      would return the wrong result.
5285
5286      Two possible solution:
5287         a) cast operands to int, if ((unsigned) / (signed)) or
5288            ((signed) / (signed))
5289         b) return an 16 bit signed int; this is what we're doing here!
5290   */
5291
5292   size = AOP_SIZE (result) - 1;
5293   offset = 1;
5294   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5295   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5296
5297   pushedB = pushB ();
5298
5299   /* signed or unsigned */
5300   if (lUnsigned && rUnsigned)
5301     {
5302       /* unsigned is easy */
5303       MOVB (aopGet (right, 0, FALSE, FALSE));
5304       MOVA (aopGet (left, 0, FALSE, FALSE));
5305       emitcode ("div", "ab");
5306       aopPut (result, "a", 0);
5307       while (size--)
5308         aopPut (result, zero, offset++);
5309
5310       popB (pushedB);
5311       return;
5312     }
5313
5314   /* signed is a little bit more difficult */
5315
5316   /* now sign adjust for both left & right */
5317
5318   /* let's see what's needed: */
5319   /* apply negative sign during runtime */
5320   runtimeSign = FALSE;
5321   /* negative sign from literals */
5322   compiletimeSign = FALSE;
5323
5324   if (!lUnsigned)
5325     {
5326       if (AOP_TYPE(left) == AOP_LIT)
5327         {
5328           /* signed literal */
5329           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5330           if (val < 0)
5331             compiletimeSign = TRUE;
5332         }
5333       else
5334         /* signed but not literal */
5335         runtimeSign = TRUE;
5336     }
5337
5338   if (!rUnsigned)
5339     {
5340       if (AOP_TYPE(right) == AOP_LIT)
5341         {
5342           /* signed literal */
5343           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5344           if (val < 0)
5345             compiletimeSign ^= TRUE;
5346         }
5347       else
5348         /* signed but not literal */
5349         runtimeSign = TRUE;
5350     }
5351
5352   /* initialize F0, which stores the runtime sign */
5353   if (runtimeSign)
5354     {
5355       if (compiletimeSign)
5356         emitcode ("setb", "F0"); /* set sign flag */
5357       else
5358         emitcode ("clr", "F0"); /* reset sign flag */
5359     }
5360
5361   /* save the signs of the operands */
5362   if (AOP_TYPE(right) == AOP_LIT)
5363     {
5364       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5365
5366       if (!rUnsigned && val < 0)
5367         emitcode ("mov", "b,#0x%02x", -val);
5368       else
5369         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5370     }
5371   else /* ! literal */
5372     {
5373       if (rUnsigned)
5374         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5375       else
5376         {
5377           MOVA (aopGet (right, 0, FALSE, FALSE));
5378           lbl = newiTempLabel (NULL);
5379           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5380           emitcode ("cpl", "F0"); /* complement sign flag */
5381           emitcode ("cpl", "a");  /* 2's complement */
5382           emitcode ("inc", "a");
5383           emitLabel (lbl);
5384           emitcode ("mov", "b,a");
5385         }
5386     }
5387
5388   if (AOP_TYPE(left) == AOP_LIT)
5389     {
5390       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5391
5392       if (!lUnsigned && val < 0)
5393         emitcode ("mov", "a,#0x%02x", -val);
5394       else
5395         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5396     }
5397   else /* ! literal */
5398     {
5399       MOVA (aopGet (left, 0, FALSE, FALSE));
5400
5401       if (!lUnsigned)
5402         {
5403           lbl = newiTempLabel (NULL);
5404           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5405           emitcode ("cpl", "F0"); /* complement sign flag */
5406           emitcode ("cpl", "a");  /* 2's complement */
5407           emitcode ("inc", "a");
5408           emitLabel (lbl);
5409         }
5410     }
5411
5412   /* now the division */
5413   emitcode ("div", "ab");
5414
5415   if (runtimeSign || compiletimeSign)
5416     {
5417       lbl = newiTempLabel (NULL);
5418       if (runtimeSign)
5419         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5420       emitcode ("cpl", "a"); /* lsb 2's complement */
5421       emitcode ("inc", "a");
5422       emitLabel (lbl);
5423
5424       accuse = aopPut (result, "a", 0);
5425       if (size > 0)
5426         {
5427           /* msb is 0x00 or 0xff depending on the sign */
5428           if (runtimeSign)
5429             {
5430               if (accuse)
5431                 {
5432                   emitcode ("push", "acc");
5433                   pushedA = TRUE;
5434                 }
5435               emitcode ("mov", "c,F0");
5436               emitcode ("subb", "a,acc");
5437               while (size--)
5438                 aopPut (result, "a", offset++);
5439             }
5440           else /* compiletimeSign */
5441             {
5442               if (aopPutUsesAcc (result, "#0xFF", offset))
5443                 {
5444                   emitcode ("push", "acc");
5445                   pushedA = TRUE;
5446                 }
5447               while (size--)
5448                 aopPut (result, "#0xff", offset++);
5449             }
5450         }
5451     }
5452   else
5453     {
5454       aopPut (result, "a", 0);
5455       while (size--)
5456         aopPut (result, zero, offset++);
5457     }
5458
5459   if (pushedA)
5460     emitcode ("pop", "acc");
5461   popB (pushedB);
5462 }
5463
5464 /*-----------------------------------------------------------------*/
5465 /* genDiv - generates code for division                            */
5466 /*-----------------------------------------------------------------*/
5467 static void
5468 genDiv (iCode * ic)
5469 {
5470   operand *left = IC_LEFT (ic);
5471   operand *right = IC_RIGHT (ic);
5472   operand *result = IC_RESULT (ic);
5473
5474   D (emitcode (";", "genDiv"));
5475
5476   /* assign the asmops */
5477   aopOp (left, ic, FALSE);
5478   aopOp (right, ic, FALSE);
5479   aopOp (result, ic, TRUE);
5480
5481   /* special cases first */
5482   /* both are bits */
5483   if (AOP_TYPE (left) == AOP_CRY &&
5484       AOP_TYPE (right) == AOP_CRY)
5485     {
5486       genDivbits (left, right, result);
5487       goto release;
5488     }
5489
5490   /* if both are of size == 1 */
5491   if (AOP_SIZE (left) == 1 &&
5492       AOP_SIZE (right) == 1)
5493     {
5494       genDivOneByte (left, right, result);
5495       goto release;
5496     }
5497
5498   /* should have been converted to function call */
5499   assert (0);
5500 release:
5501   freeAsmop (result, NULL, ic, TRUE);
5502   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5503   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5504 }
5505
5506 /*-----------------------------------------------------------------*/
5507 /* genModbits :- modulus of bits                                   */
5508 /*-----------------------------------------------------------------*/
5509 static void
5510 genModbits (operand * left,
5511             operand * right,
5512             operand * result)
5513 {
5514   char *l;
5515   bool pushedB;
5516
5517   D (emitcode (";", "genModbits"));
5518
5519   pushedB = pushB ();
5520
5521   /* the result must be bit */
5522   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5523   l = aopGet (left, 0, FALSE, FALSE);
5524
5525   MOVA (l);
5526
5527   emitcode ("div", "ab");
5528   emitcode ("mov", "a,b");
5529   emitcode ("rrc", "a");
5530
5531   popB (pushedB);
5532
5533   aopPut (result, "c", 0);
5534 }
5535
5536 /*-----------------------------------------------------------------*/
5537 /* genModOneByte : 8 bit modulus                                   */
5538 /*-----------------------------------------------------------------*/
5539 static void
5540 genModOneByte (operand * left,
5541                operand * right,
5542                operand * result)
5543 {
5544   bool lUnsigned, rUnsigned, pushedB;
5545   bool runtimeSign, compiletimeSign;
5546   symbol *lbl;
5547   int size, offset;
5548
5549   D (emitcode (";", "genModOneByte"));
5550
5551   size = AOP_SIZE (result) - 1;
5552   offset = 1;
5553   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5554   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5555
5556   /* if right is a literal, check it for 2^n */
5557   if (AOP_TYPE(right) == AOP_LIT)
5558     {
5559       unsigned char val = abs((int) operandLitValue(right));
5560       symbol *lbl2 = NULL;
5561
5562       switch (val)
5563         {
5564           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5565           case 2:
5566           case 4:
5567           case 8:
5568           case 16:
5569           case 32:
5570           case 64:
5571           case 128:
5572             if (lUnsigned)
5573               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5574                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5575               /* because iCode should have been changed to genAnd  */
5576               /* see file "SDCCopt.c", function "convertToFcall()" */
5577
5578             MOVA (aopGet (left, 0, FALSE, FALSE));
5579             emitcode ("mov", "c,acc.7");
5580             emitcode ("anl", "a,#0x%02x", val - 1);
5581             lbl = newiTempLabel (NULL);
5582             emitcode ("jz", "%05d$", (lbl->key + 100));
5583             emitcode ("jnc", "%05d$", (lbl->key + 100));
5584             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5585             if (size)
5586               {
5587                 int size2 = size;
5588                 int offs2 = offset;
5589
5590                 aopPut (result, "a", 0);
5591                 while (size2--)
5592                   aopPut (result, "#0xff", offs2++);
5593                 lbl2 = newiTempLabel (NULL);
5594                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5595               }
5596             emitLabel (lbl);
5597             aopPut (result, "a", 0);
5598             while (size--)
5599               aopPut (result, zero, offset++);
5600             if (lbl2)
5601               {
5602                 emitLabel (lbl2);
5603               }
5604             return;
5605
5606           default:
5607             break;
5608         }
5609     }
5610
5611   pushedB = pushB ();
5612
5613   /* signed or unsigned */
5614   if (lUnsigned && rUnsigned)
5615     {
5616       /* unsigned is easy */
5617       MOVB (aopGet (right, 0, FALSE, FALSE));
5618       MOVA (aopGet (left, 0, FALSE, FALSE));
5619       emitcode ("div", "ab");
5620       aopPut (result, "b", 0);
5621       while (size--)
5622         aopPut (result, zero, offset++);
5623
5624       popB (pushedB);
5625       return;
5626     }
5627
5628   /* signed is a little bit more difficult */
5629
5630   /* now sign adjust for both left & right */
5631
5632   /* modulus: sign of the right operand has no influence on the result! */
5633   if (AOP_TYPE(right) == AOP_LIT)
5634     {
5635       signed char val = (char) operandLitValue(right);
5636
5637       if (!rUnsigned && val < 0)
5638         emitcode ("mov", "b,#0x%02x", -val);
5639       else
5640         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5641     }
5642   else /* not literal */
5643     {
5644       if (rUnsigned)
5645         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5646       else
5647         {
5648           MOVA (aopGet (right, 0, FALSE, FALSE));
5649           lbl = newiTempLabel (NULL);
5650           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5651           emitcode ("cpl", "a"); /* 2's complement */
5652           emitcode ("inc", "a");
5653           emitLabel (lbl);
5654           emitcode ("mov", "b,a");
5655         }
5656     }
5657
5658   /* let's see what's needed: */
5659   /* apply negative sign during runtime */
5660   runtimeSign = FALSE;
5661   /* negative sign from literals */
5662   compiletimeSign = FALSE;
5663
5664   /* sign adjust left side */
5665   if (AOP_TYPE(left) == AOP_LIT)
5666     {
5667       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5668
5669       if (!lUnsigned && val < 0)
5670         {
5671           compiletimeSign = TRUE; /* set sign flag */
5672           emitcode ("mov", "a,#0x%02x", -val);
5673         }
5674       else
5675         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5676     }
5677   else /* ! literal */
5678     {
5679       MOVA (aopGet (left, 0, FALSE, FALSE));
5680
5681       if (!lUnsigned)
5682         {
5683           runtimeSign = TRUE;
5684           emitcode ("clr", "F0"); /* clear sign flag */
5685
5686           lbl = newiTempLabel (NULL);
5687           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5688           emitcode ("setb", "F0"); /* set sign flag */
5689           emitcode ("cpl", "a");   /* 2's complement */
5690           emitcode ("inc", "a");
5691           emitLabel (lbl);
5692         }
5693     }
5694
5695   /* now the modulus */
5696   emitcode ("div", "ab");
5697
5698   if (runtimeSign || compiletimeSign)
5699     {
5700       emitcode ("mov", "a,b");
5701       lbl = newiTempLabel (NULL);
5702       if (runtimeSign)
5703         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5704       emitcode ("cpl", "a"); /* 2's complement */
5705       emitcode ("inc", "a");
5706       emitLabel (lbl);
5707
5708       aopPut (result, "a", 0);
5709       if (size > 0)
5710         {
5711           /* msb is 0x00 or 0xff depending on the sign */
5712           if (runtimeSign)
5713             {
5714               emitcode ("mov", "c,F0");
5715               emitcode ("subb", "a,acc");
5716               while (size--)
5717                 aopPut (result, "a", offset++);
5718             }
5719           else /* compiletimeSign */
5720             while (size--)
5721               aopPut (result, "#0xff", offset++);
5722         }
5723     }
5724   else
5725     {
5726       aopPut (result, "b", 0);
5727       while (size--)
5728         aopPut (result, zero, offset++);
5729     }
5730
5731   popB (pushedB);
5732 }
5733
5734 /*-----------------------------------------------------------------*/
5735 /* genMod - generates code for division                            */
5736 /*-----------------------------------------------------------------*/
5737 static void
5738 genMod (iCode * ic)
5739 {
5740   operand *left = IC_LEFT (ic);
5741   operand *right = IC_RIGHT (ic);
5742   operand *result = IC_RESULT (ic);
5743
5744   D (emitcode (";", "genMod"));
5745
5746   /* assign the asmops */
5747   aopOp (left, ic, FALSE);
5748   aopOp (right, ic, FALSE);
5749   aopOp (result, ic, TRUE);
5750
5751   /* special cases first */
5752   /* both are bits */
5753   if (AOP_TYPE (left) == AOP_CRY &&
5754       AOP_TYPE (right) == AOP_CRY)
5755     {
5756       genModbits (left, right, result);
5757       goto release;
5758     }
5759
5760   /* if both are of size == 1 */
5761   if (AOP_SIZE (left) == 1 &&
5762       AOP_SIZE (right) == 1)
5763     {
5764       genModOneByte (left, right, result);
5765       goto release;
5766     }
5767
5768   /* should have been converted to function call */
5769   assert (0);
5770
5771 release:
5772   freeAsmop (result, NULL, ic, TRUE);
5773   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5774   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5775 }
5776
5777 /*-----------------------------------------------------------------*/
5778 /* genIfxJump :- will create a jump depending on the ifx           */
5779 /*-----------------------------------------------------------------*/
5780 static void
5781 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5782 {
5783   symbol *jlbl;
5784   symbol *tlbl = newiTempLabel (NULL);
5785   char *inst;
5786
5787   D (emitcode (";", "genIfxJump"));
5788
5789   /* if true label then we jump if condition
5790      supplied is true */
5791   if (IC_TRUE (ic))
5792     {
5793       jlbl = IC_TRUE (ic);
5794       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5795                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5796     }
5797   else
5798     {
5799       /* false label is present */
5800       jlbl = IC_FALSE (ic);
5801       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5802                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5803     }
5804   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5805     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5806   else
5807     emitcode (inst, "%05d$", tlbl->key + 100);
5808   freeForBranchAsmop (result);
5809   freeForBranchAsmop (right);
5810   freeForBranchAsmop (left);
5811   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5812   emitLabel (tlbl);
5813
5814   /* mark the icode as generated */
5815   ic->generated = 1;
5816 }
5817
5818 /*-----------------------------------------------------------------*/
5819 /* genCmp :- greater or less than comparison                       */
5820 /*-----------------------------------------------------------------*/
5821 static void
5822 genCmp (operand * left, operand * right,
5823         operand * result, iCode * ifx, int sign, iCode *ic)
5824 {
5825   int size, offset = 0;
5826   unsigned long lit = 0L;
5827   bool rightInB;
5828
5829   D (emitcode (";", "genCmp"));
5830
5831   /* if left & right are bit variables */
5832   if (AOP_TYPE (left) == AOP_CRY &&
5833       AOP_TYPE (right) == AOP_CRY)
5834     {
5835       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5836       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5837     }
5838   else
5839     {
5840       /* subtract right from left if at the
5841          end the carry flag is set then we know that
5842          left is greater than right */
5843       size = max (AOP_SIZE (left), AOP_SIZE (right));
5844
5845       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5846       if ((size == 1) && !sign &&
5847           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5848         {
5849           symbol *lbl = newiTempLabel (NULL);
5850           emitcode ("cjne", "%s,%s,%05d$",
5851                     aopGet (left, offset, FALSE, FALSE),
5852                     aopGet (right, offset, FALSE, FALSE),
5853                     lbl->key + 100);
5854           emitLabel (lbl);
5855         }
5856       else
5857         {
5858           if (AOP_TYPE (right) == AOP_LIT)
5859             {
5860               lit = ulFromVal (AOP (right)->aopu.aop_lit);
5861               /* optimize if(x < 0) or if(x >= 0) */
5862               if (lit == 0L)
5863                 {
5864                   if (!sign)
5865                     {
5866                       CLRC;
5867                     }
5868                   else
5869                     {
5870                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5871                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5872                         {
5873                           genIfxJump (ifx, "acc.7", left, right, result);
5874                           freeAsmop (right, NULL, ic, TRUE);
5875                           freeAsmop (left, NULL, ic, TRUE);
5876
5877                           return;
5878                         }
5879                       else
5880                         {
5881                           emitcode ("rlc", "a");
5882                         }
5883                     }
5884                   goto release;
5885                 }
5886               else
5887                 {//nonzero literal
5888                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5889                   while (size && (bytelit == 0))
5890                     {
5891                       offset++;
5892                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5893                       size--;
5894                     }
5895                   CLRC;
5896                   while (size--)
5897                     {
5898                       MOVA (aopGet (left, offset, FALSE, FALSE));
5899                       if (sign && size == 0)
5900                         {
5901                           emitcode ("xrl", "a,#0x80");
5902                           emitcode ("subb", "a,#0x%02x",
5903                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5904                         }
5905                       else
5906                         {
5907                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5908                         }
5909                       offset++;
5910                     }
5911                   goto release;
5912                 }
5913             }
5914           CLRC;
5915           while (size--)
5916             {
5917               bool pushedB = FALSE;
5918               rightInB = aopGetUsesAcc(right, offset);
5919               if (rightInB)
5920                 {
5921                   pushedB = pushB ();
5922                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5923                 }
5924               MOVA (aopGet (left, offset, FALSE, FALSE));
5925               if (sign && size == 0)
5926                 {
5927                   emitcode ("xrl", "a,#0x80");
5928                   if (!rightInB)
5929                     {
5930                       pushedB = pushB ();
5931                       rightInB++;
5932                       MOVB (aopGet (right, offset, FALSE, FALSE));
5933                     }
5934                   emitcode ("xrl", "b,#0x80");
5935                   emitcode ("subb", "a,b");
5936                 }
5937               else
5938                 {
5939                   if (rightInB)
5940                     emitcode ("subb", "a,b");
5941                   else
5942                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5943                 }
5944               if (rightInB)
5945                 popB (pushedB);
5946               offset++;
5947             }
5948         }
5949     }
5950
5951 release:
5952   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5953   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5954   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5955     {
5956       outBitC (result);
5957     }
5958   else
5959     {
5960       /* if the result is used in the next
5961          ifx conditional branch then generate
5962          code a little differently */
5963       if (ifx)
5964         {
5965           genIfxJump (ifx, "c", NULL, NULL, result);
5966         }
5967       else
5968         {
5969           outBitC (result);
5970         }
5971       /* leave the result in acc */
5972     }
5973 }
5974
5975 /*-----------------------------------------------------------------*/
5976 /* genCmpGt :- greater than comparison                             */
5977 /*-----------------------------------------------------------------*/
5978 static void
5979 genCmpGt (iCode * ic, iCode * ifx)
5980 {
5981   operand *left, *right, *result;
5982   sym_link *letype, *retype;
5983   int sign;
5984
5985   D (emitcode (";", "genCmpGt"));
5986
5987   left = IC_LEFT (ic);
5988   right = IC_RIGHT (ic);
5989   result = IC_RESULT (ic);
5990
5991   letype = getSpec (operandType (left));
5992   retype = getSpec (operandType (right));
5993   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5994            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5995   /* assign the asmops */
5996   aopOp (result, ic, TRUE);
5997   aopOp (left, ic, FALSE);
5998   aopOp (right, ic, FALSE);
5999
6000   genCmp (right, left, result, ifx, sign, ic);
6001
6002   freeAsmop (result, NULL, ic, TRUE);
6003 }
6004
6005 /*-----------------------------------------------------------------*/
6006 /* genCmpLt - less than comparisons                                */
6007 /*-----------------------------------------------------------------*/
6008 static void
6009 genCmpLt (iCode * ic, iCode * ifx)
6010 {
6011   operand *left, *right, *result;
6012   sym_link *letype, *retype;
6013   int sign;
6014
6015   D (emitcode (";", "genCmpLt"));
6016
6017   left = IC_LEFT (ic);
6018   right = IC_RIGHT (ic);
6019   result = IC_RESULT (ic);
6020
6021   letype = getSpec (operandType (left));
6022   retype = getSpec (operandType (right));
6023   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6024            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6025   /* assign the asmops */
6026   aopOp (result, ic, TRUE);
6027   aopOp (left, ic, FALSE);
6028   aopOp (right, ic, FALSE);
6029
6030   genCmp (left, right, result, ifx, sign, ic);
6031
6032   freeAsmop (result, NULL, ic, TRUE);
6033 }
6034
6035 /*-----------------------------------------------------------------*/
6036 /* gencjneshort - compare and jump if not equal                    */
6037 /*-----------------------------------------------------------------*/
6038 static void
6039 gencjneshort (operand * left, operand * right, symbol * lbl)
6040 {
6041   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6042   int offset = 0;
6043   unsigned long lit = 0L;
6044
6045   D (emitcode (";", "gencjneshort"));
6046
6047   /* if the left side is a literal or
6048      if the right is in a pointer register and left
6049      is not */
6050   if ((AOP_TYPE (left) == AOP_LIT)  ||
6051       (AOP_TYPE (left) == AOP_IMMD) ||
6052       (AOP_TYPE (left) == AOP_DIR)  ||
6053       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6054     {
6055       operand *t = right;
6056       right = left;
6057       left = t;
6058     }
6059
6060   if (AOP_TYPE (right) == AOP_LIT)
6061     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6062
6063   /* if the right side is a literal then anything goes */
6064   if (AOP_TYPE (right) == AOP_LIT &&
6065       AOP_TYPE (left) != AOP_DIR  &&
6066       AOP_TYPE (left) != AOP_IMMD)
6067     {
6068       while (size--)
6069         {
6070           emitcode ("cjne", "%s,%s,%05d$",
6071                     aopGet (left, offset, FALSE, FALSE),
6072                     aopGet (right, offset, FALSE, FALSE),
6073                     lbl->key + 100);
6074           offset++;
6075         }
6076     }
6077
6078   /* if the right side is in a register or in direct space or
6079      if the left is a pointer register & right is not */
6080   else if (AOP_TYPE (right) == AOP_REG ||
6081            AOP_TYPE (right) == AOP_DIR ||
6082            AOP_TYPE (right) == AOP_LIT ||
6083            AOP_TYPE (right) == AOP_IMMD ||
6084            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6085            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6086     {
6087       while (size--)
6088         {
6089           MOVA (aopGet (left, offset, FALSE, FALSE));
6090           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6091               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6092             emitcode ("jnz", "%05d$", lbl->key + 100);
6093           else
6094             emitcode ("cjne", "a,%s,%05d$",
6095                       aopGet (right, offset, FALSE, TRUE),
6096                       lbl->key + 100);
6097           offset++;
6098         }
6099     }
6100   else
6101     {
6102       /* right is a pointer reg need both a & b */
6103       while (size--)
6104         {
6105           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6106           wassertl(!BINUSE, "B was in use");
6107           MOVB (aopGet (left, offset, FALSE, FALSE));
6108           MOVA (aopGet (right, offset, FALSE, FALSE));
6109           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6110           offset++;
6111         }
6112     }
6113 }
6114
6115 /*-----------------------------------------------------------------*/
6116 /* gencjne - compare and jump if not equal                         */
6117 /*-----------------------------------------------------------------*/
6118 static void
6119 gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
6120 {
6121   symbol *tlbl = newiTempLabel (NULL);
6122
6123   D (emitcode (";", "gencjne"));
6124
6125   gencjneshort (left, right, lbl);
6126
6127   if (useCarry)
6128       SETC;
6129   else
6130       MOVA (one);
6131   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6132   emitLabel (lbl);
6133   if (useCarry)
6134       CLRC;
6135   else
6136       MOVA (zero);
6137   emitLabel (tlbl);
6138 }
6139
6140 /*-----------------------------------------------------------------*/
6141 /* genCmpEq - generates code for equal to                          */
6142 /*-----------------------------------------------------------------*/
6143 static void
6144 genCmpEq (iCode * ic, iCode * ifx)
6145 {
6146   bool swappedLR = FALSE;
6147   operand *left, *right, *result;
6148
6149   D (emitcode (";", "genCmpEq"));
6150
6151   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6152   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6153   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6154
6155   /* if literal, literal on the right or
6156      if the right is in a pointer register and left
6157      is not */
6158   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6159       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6160     {
6161       operand *t = IC_RIGHT (ic);
6162       IC_RIGHT (ic) = IC_LEFT (ic);
6163       IC_LEFT (ic) = t;
6164       swappedLR = TRUE;
6165     }
6166
6167   if (ifx && !AOP_SIZE (result))
6168     {
6169       symbol *tlbl;
6170       /* if they are both bit variables */
6171       if (AOP_TYPE (left) == AOP_CRY &&
6172           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6173         {
6174           if (AOP_TYPE (right) == AOP_LIT)
6175             {
6176               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6177               if (lit == 0L)
6178                 {
6179                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6180                   emitcode ("cpl", "c");
6181                 }
6182               else if (lit == 1L)
6183                 {
6184                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6185                 }
6186               else
6187                 {
6188                   emitcode ("clr", "c");
6189                 }
6190               /* AOP_TYPE(right) == AOP_CRY */
6191             }
6192           else
6193             {
6194               symbol *lbl = newiTempLabel (NULL);
6195               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6196               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6197               emitcode ("cpl", "c");
6198               emitLabel (lbl);
6199             }
6200           /* if true label then we jump if condition
6201              supplied is true */
6202           tlbl = newiTempLabel (NULL);
6203           if (IC_TRUE (ifx))
6204             {
6205               emitcode ("jnc", "%05d$", tlbl->key + 100);
6206               freeForBranchAsmop (result);
6207               freeForBranchAsmop (right);
6208               freeForBranchAsmop (left);
6209               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6210             }
6211           else
6212             {
6213               emitcode ("jc", "%05d$", tlbl->key + 100);
6214               freeForBranchAsmop (result);
6215               freeForBranchAsmop (right);
6216               freeForBranchAsmop (left);
6217               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6218             }
6219           emitLabel (tlbl);
6220         }
6221       else
6222         {
6223           tlbl = newiTempLabel (NULL);
6224           gencjneshort (left, right, tlbl);
6225           if (IC_TRUE (ifx))
6226             {
6227               freeForBranchAsmop (result);
6228               freeForBranchAsmop (right);
6229               freeForBranchAsmop (left);
6230               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6231               emitLabel (tlbl);
6232             }
6233           else
6234             {
6235               symbol *lbl = newiTempLabel (NULL);
6236               emitcode ("sjmp", "%05d$", lbl->key + 100);
6237               emitLabel (tlbl);
6238               freeForBranchAsmop (result);
6239               freeForBranchAsmop (right);
6240               freeForBranchAsmop (left);
6241               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6242               emitLabel (lbl);
6243             }
6244         }
6245       /* mark the icode as generated */
6246       ifx->generated = 1;
6247       goto release;
6248     }
6249
6250   /* if they are both bit variables */
6251   if (AOP_TYPE (left) == AOP_CRY &&
6252       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6253     {
6254       if (AOP_TYPE (right) == AOP_LIT)
6255         {
6256           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6257           if (lit == 0L)
6258             {
6259               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6260               emitcode ("cpl", "c");
6261             }
6262           else if (lit == 1L)
6263             {
6264               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6265             }
6266           else
6267             {
6268               emitcode ("clr", "c");
6269             }
6270           /* AOP_TYPE(right) == AOP_CRY */
6271         }
6272       else
6273         {
6274           symbol *lbl = newiTempLabel (NULL);
6275           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6276           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6277           emitcode ("cpl", "c");
6278           emitLabel (lbl);
6279         }
6280       /* c = 1 if egal */
6281       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6282         {
6283           outBitC (result);
6284           goto release;
6285         }
6286       if (ifx)
6287         {
6288           genIfxJump (ifx, "c", left, right, result);
6289           goto release;
6290         }
6291       /* if the result is used in an arithmetic operation
6292          then put the result in place */
6293       outBitC (result);
6294     }
6295   else
6296     {
6297       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6298         {
6299           gencjne (left, right, newiTempLabel (NULL), TRUE);
6300           aopPut (result, "c", 0);
6301           goto release;
6302         }
6303       gencjne (left, right, newiTempLabel (NULL), FALSE);
6304       if (ifx)
6305         {
6306           genIfxJump (ifx, "a", left, right, result);
6307           goto release;
6308         }
6309       /* if the result is used in an arithmetic operation
6310          then put the result in place */
6311       if (AOP_TYPE (result) != AOP_CRY)
6312         outAcc (result);
6313       /* leave the result in acc */
6314     }
6315
6316 release:
6317   freeAsmop (result, NULL, ic, TRUE);
6318   if (!swappedLR)
6319     {
6320       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6321       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6322     }
6323   else
6324     {
6325       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6326       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6327     }
6328 }
6329
6330 /*-----------------------------------------------------------------*/
6331 /* ifxForOp - returns the icode containing the ifx for operand     */
6332 /*-----------------------------------------------------------------*/
6333 static iCode *
6334 ifxForOp (operand * op, iCode * ic)
6335 {
6336   /* if true symbol then needs to be assigned */
6337   if (IS_TRUE_SYMOP (op))
6338     return NULL;
6339
6340   /* if this has register type condition and
6341      the next instruction is ifx with the same operand
6342      and live to of the operand is upto the ifx only then */
6343   if (ic->next &&
6344       ic->next->op == IFX &&
6345       IC_COND (ic->next)->key == op->key &&
6346       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6347     return ic->next;
6348
6349   return NULL;
6350 }
6351
6352 /*-----------------------------------------------------------------*/
6353 /* hasInc - operand is incremented before any other use            */
6354 /*-----------------------------------------------------------------*/
6355 static iCode *
6356 hasInc (operand *op, iCode *ic, int osize)
6357 {
6358   sym_link *type = operandType(op);
6359   sym_link *retype = getSpec (type);
6360   iCode *lic = ic->next;
6361   int isize ;
6362
6363   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6364   if (!IS_SYMOP(op)) return NULL;
6365
6366   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6367   if (IS_AGGREGATE(type->next)) return NULL;
6368   if (osize != (isize = getSize(type->next))) return NULL;
6369
6370   while (lic) {
6371     /* if operand of the form op = op + <sizeof *op> */
6372     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6373         isOperandEqual(IC_RESULT(lic),op) &&
6374         isOperandLiteral(IC_RIGHT(lic)) &&
6375         operandLitValue(IC_RIGHT(lic)) == isize) {
6376       return lic;
6377     }
6378     /* if the operand used or deffed */
6379     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6380       return NULL;
6381     }
6382     /* if GOTO or IFX */
6383     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6384     lic = lic->next;
6385   }
6386   return NULL;
6387 }
6388
6389 /*-----------------------------------------------------------------*/
6390 /* genAndOp - for && operation                                     */
6391 /*-----------------------------------------------------------------*/
6392 static void
6393 genAndOp (iCode * ic)
6394 {
6395   operand *left, *right, *result;
6396   symbol *tlbl;
6397
6398   D (emitcode (";", "genAndOp"));
6399
6400   /* note here that && operations that are in an
6401      if statement are taken away by backPatchLabels
6402      only those used in arthmetic operations remain */
6403   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6404   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6405   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6406
6407   /* if both are bit variables */
6408   if (AOP_TYPE (left) == AOP_CRY &&
6409       AOP_TYPE (right) == AOP_CRY)
6410     {
6411       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6412       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6413       outBitC (result);
6414     }
6415   else
6416     {
6417       tlbl = newiTempLabel (NULL);
6418       toBoolean (left);
6419       emitcode ("jz", "%05d$", tlbl->key + 100);
6420       toBoolean (right);
6421       emitLabel (tlbl);
6422       outBitAcc (result);
6423     }
6424
6425   freeAsmop (result, NULL, ic, TRUE);
6426   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6427   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6428 }
6429
6430
6431 /*-----------------------------------------------------------------*/
6432 /* genOrOp - for || operation                                      */
6433 /*-----------------------------------------------------------------*/
6434 static void
6435 genOrOp (iCode * ic)
6436 {
6437   operand *left, *right, *result;
6438   symbol *tlbl;
6439
6440   D (emitcode (";", "genOrOp"));
6441
6442   /* note here that || operations that are in an
6443      if statement are taken away by backPatchLabels
6444      only those used in arthmetic operations remain */
6445   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6446   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6447   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6448
6449   /* if both are bit variables */
6450   if (AOP_TYPE (left) == AOP_CRY &&
6451       AOP_TYPE (right) == AOP_CRY)
6452     {
6453       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6454       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6455       outBitC (result);
6456     }
6457   else
6458     {
6459       tlbl = newiTempLabel (NULL);
6460       toBoolean (left);
6461       emitcode ("jnz", "%05d$", tlbl->key + 100);
6462       toBoolean (right);
6463       emitLabel (tlbl);
6464       outBitAcc (result);
6465     }
6466
6467   freeAsmop (result, NULL, ic, TRUE);
6468   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6469   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6470 }
6471
6472 /*-----------------------------------------------------------------*/
6473 /* isLiteralBit - test if lit == 2^n                               */
6474 /*-----------------------------------------------------------------*/
6475 static int
6476 isLiteralBit (unsigned long lit)
6477 {
6478   unsigned long pw[32] =
6479   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6480    0x100L, 0x200L, 0x400L, 0x800L,
6481    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6482    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6483    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6484    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6485    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6486   int idx;
6487
6488   for (idx = 0; idx < 32; idx++)
6489     if (lit == pw[idx])
6490       return idx + 1;
6491   return 0;
6492 }
6493
6494 /*-----------------------------------------------------------------*/
6495 /* continueIfTrue -                                                */
6496 /*-----------------------------------------------------------------*/
6497 static void
6498 continueIfTrue (iCode * ic)
6499 {
6500   if (IC_TRUE (ic))
6501     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6502   ic->generated = 1;
6503 }
6504
6505 /*-----------------------------------------------------------------*/
6506 /* jmpIfTrue -                                                     */
6507 /*-----------------------------------------------------------------*/
6508 static void
6509 jumpIfTrue (iCode * ic)
6510 {
6511   if (!IC_TRUE (ic))
6512     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6513   ic->generated = 1;
6514 }
6515
6516 /*-----------------------------------------------------------------*/
6517 /* jmpTrueOrFalse -                                                */
6518 /*-----------------------------------------------------------------*/
6519 static void
6520 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6521 {
6522   // ugly but optimized by peephole
6523   if (IC_TRUE (ic))
6524     {
6525       symbol *nlbl = newiTempLabel (NULL);
6526       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6527       emitLabel (tlbl);
6528       freeForBranchAsmop (result);
6529       freeForBranchAsmop (right);
6530       freeForBranchAsmop (left);
6531       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6532       emitLabel (nlbl);
6533     }
6534   else
6535     {
6536       freeForBranchAsmop (result);
6537       freeForBranchAsmop (right);
6538       freeForBranchAsmop (left);
6539       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6540       emitLabel (tlbl);
6541     }
6542   ic->generated = 1;
6543 }
6544
6545 /*-----------------------------------------------------------------*/
6546 /* genAnd  - code for and                                          */
6547 /*-----------------------------------------------------------------*/
6548 static void
6549 genAnd (iCode * ic, iCode * ifx)
6550 {
6551   operand *left, *right, *result;
6552   int size, offset = 0;
6553   unsigned long lit = 0L;
6554   int bytelit = 0;
6555   char buffer[10];
6556
6557   D (emitcode (";", "genAnd"));
6558
6559   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6560   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6561   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6562
6563 #ifdef DEBUG_TYPE
6564   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6565             AOP_TYPE (result),
6566             AOP_TYPE (left), AOP_TYPE (right));
6567   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6568             AOP_SIZE (result),
6569             AOP_SIZE (left), AOP_SIZE (right));
6570 #endif
6571
6572   /* if left is a literal & right is not then exchange them */
6573   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6574       AOP_NEEDSACC (left))
6575     {
6576       operand *tmp = right;
6577       right = left;
6578       left = tmp;
6579     }
6580
6581   /* if result = right then exchange left and right */
6582   if (sameRegs (AOP (result), AOP (right)))
6583     {
6584       operand *tmp = right;
6585       right = left;
6586       left = tmp;
6587     }
6588
6589   /* if right is bit then exchange them */
6590   if (AOP_TYPE (right) == AOP_CRY &&
6591       AOP_TYPE (left) != AOP_CRY)
6592     {
6593       operand *tmp = right;
6594       right = left;
6595       left = tmp;
6596     }
6597   if (AOP_TYPE (right) == AOP_LIT)
6598     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6599
6600   size = AOP_SIZE (result);
6601
6602   // if(bit & yy)
6603   // result = bit & yy;
6604   if (AOP_TYPE (left) == AOP_CRY)
6605     {
6606       // c = bit & literal;
6607       if (AOP_TYPE (right) == AOP_LIT)
6608         {
6609           if (lit & 1)
6610             {
6611               if (size && sameRegs (AOP (result), AOP (left)))
6612                 // no change
6613                 goto release;
6614               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6615             }
6616           else
6617             {
6618               // bit(result) = 0;
6619               if (size && (AOP_TYPE (result) == AOP_CRY))
6620                 {
6621                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6622                   goto release;
6623                 }
6624               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6625                 {
6626                   jumpIfTrue (ifx);
6627                   goto release;
6628                 }
6629               emitcode ("clr", "c");
6630             }
6631         }
6632       else
6633         {
6634           if (AOP_TYPE (right) == AOP_CRY)
6635             {
6636               // c = bit & bit;
6637               if (IS_OP_ACCUSE (left))
6638                 {
6639                   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6640                 }
6641                           else
6642                 {
6643                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6644                   emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6645                 }
6646             }
6647           else
6648             {
6649               // c = bit & val;
6650               MOVA (aopGet (right, 0, FALSE, FALSE));
6651               // c = lsb
6652               emitcode ("rrc", "a");
6653               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6654             }
6655         }
6656       // bit = c
6657       // val = c
6658       if (size)
6659         outBitC (result);
6660       // if(bit & ...)
6661       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6662         genIfxJump (ifx, "c", left, right, result);
6663       goto release;
6664     }
6665
6666   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6667   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6668   if ((AOP_TYPE (right) == AOP_LIT) &&
6669       (AOP_TYPE (result) == AOP_CRY) &&
6670       (AOP_TYPE (left) != AOP_CRY))
6671     {
6672       int posbit = isLiteralBit (lit);
6673       /* left &  2^n */
6674       if (posbit)
6675         {
6676           posbit--;
6677           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6678           // bit = left & 2^n
6679           if (size)
6680             {
6681               switch (posbit & 0x07)
6682                 {
6683                   case 0: emitcode ("rrc", "a");
6684                           break;
6685                   case 7: emitcode ("rlc", "a");
6686                           break;
6687                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6688                           break;
6689                 }
6690             }
6691           // if(left &  2^n)
6692           else
6693             {
6694               if (ifx)
6695                 {
6696                   SNPRINTF (buffer, sizeof(buffer),
6697                             "acc.%d", posbit & 0x07);
6698                   genIfxJump (ifx, buffer, left, right, result);
6699                 }
6700               else
6701                 {// what is this case? just found it in ds390/gen.c
6702                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6703                 }
6704               goto release;
6705             }
6706         }
6707       else
6708         {
6709           symbol *tlbl = newiTempLabel (NULL);
6710           int sizel = AOP_SIZE (left);
6711           if (size)
6712             emitcode ("setb", "c");
6713           while (sizel--)
6714             {
6715               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6716                 {
6717                   MOVA (aopGet (left, offset, FALSE, FALSE));
6718                   // byte ==  2^n ?
6719                   if ((posbit = isLiteralBit (bytelit)) != 0)
6720                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6721                   else
6722                     {
6723                       if (bytelit != 0x0FFL)
6724                         emitcode ("anl", "a,%s",
6725                                   aopGet (right, offset, FALSE, TRUE));
6726                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6727                     }
6728                 }
6729               offset++;
6730             }
6731           // bit = left & literal
6732           if (size)
6733             {
6734               emitcode ("clr", "c");
6735               emitLabel (tlbl);
6736             }
6737           // if(left & literal)
6738           else
6739             {
6740               if (ifx)
6741                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6742               else
6743                 emitLabel (tlbl);
6744               goto release;
6745             }
6746         }
6747       outBitC (result);
6748       goto release;
6749     }
6750
6751   /* if left is same as result */
6752   if (sameRegs (AOP (result), AOP (left)))
6753     {
6754       for (; size--; offset++)
6755         {
6756           if (AOP_TYPE (right) == AOP_LIT)
6757             {
6758               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6759               if (bytelit == 0x0FF)
6760                 {
6761                   /* dummy read of volatile operand */
6762                   if (isOperandVolatile (left, FALSE))
6763                     MOVA (aopGet (left, offset, FALSE, FALSE));
6764                   else
6765                     continue;
6766                 }
6767               else if (bytelit == 0)
6768                 {
6769                   aopPut (result, zero, offset);
6770                 }
6771               else if (IS_AOP_PREG (result))
6772                 {
6773                   MOVA (aopGet (left, offset, FALSE, TRUE));
6774                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6775                   aopPut (result, "a", offset);
6776                 }
6777               else
6778                 emitcode ("anl", "%s,%s",
6779                           aopGet (left, offset, FALSE, TRUE),
6780                           aopGet (right, offset, FALSE, FALSE));
6781             }
6782           else
6783             {
6784               if (AOP_TYPE (left) == AOP_ACC)
6785                 {
6786                   if (offset)
6787                     emitcode("mov", "a,b");
6788                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6789                 }
6790               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6791                 {
6792                   MOVB (aopGet (left, offset, FALSE, FALSE));
6793                   MOVA (aopGet (right, offset, FALSE, FALSE));
6794                   emitcode ("anl", "a,b");
6795                   aopPut (result, "a", offset);
6796                 }
6797               else if (aopGetUsesAcc (left, offset))
6798                 {
6799                   MOVA (aopGet (left, offset, FALSE, FALSE));
6800                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6801                   aopPut (result, "a", offset);
6802                 }
6803               else
6804                 {
6805                   MOVA (aopGet (right, offset, FALSE, FALSE));
6806                   if (IS_AOP_PREG (result))
6807                     {
6808                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6809                       aopPut (result, "a", offset);
6810                     }
6811                   else
6812                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6813                 }
6814             }
6815         }
6816     }
6817   else
6818     {
6819       // left & result in different registers
6820       if (AOP_TYPE (result) == AOP_CRY)
6821         {
6822           // result = bit
6823           // if(size), result in bit
6824           // if(!size && ifx), conditional oper: if(left & right)
6825           symbol *tlbl = newiTempLabel (NULL);
6826           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6827           if (size)
6828             emitcode ("setb", "c");
6829           while (sizer--)
6830             {
6831               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6832                   && AOP_TYPE(left)==AOP_ACC)
6833                 {
6834                   if (offset)
6835                     emitcode("mov", "a,b");
6836                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6837                 }
6838               else if (AOP_TYPE(left)==AOP_ACC)
6839                 {
6840                   if (!offset)
6841                     {
6842                       bool pushedB = pushB ();
6843                       emitcode("mov", "b,a");
6844                       MOVA (aopGet (right, offset, FALSE, FALSE));
6845                       emitcode("anl", "a,b");
6846                       popB (pushedB);
6847                     }
6848                   else
6849                     {
6850                       MOVA (aopGet (right, offset, FALSE, FALSE));
6851                       emitcode("anl", "a,b");
6852                     }
6853                 }
6854               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6855                 {
6856                   MOVB (aopGet (left, offset, FALSE, FALSE));
6857                   MOVA (aopGet (right, offset, FALSE, FALSE));
6858                   emitcode ("anl", "a,b");
6859                 }
6860               else if (aopGetUsesAcc (left, offset))
6861                 {
6862                   MOVA (aopGet (left, offset, FALSE, FALSE));
6863                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6864                     }
6865               else
6866                 {
6867                   MOVA (aopGet (right, offset, FALSE, FALSE));
6868                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6869                 }
6870
6871               emitcode ("jnz", "%05d$", tlbl->key + 100);
6872               offset++;
6873             }
6874           if (size)
6875             {
6876               CLRC;
6877               emitLabel (tlbl);
6878               outBitC (result);
6879             }
6880           else if (ifx)
6881             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6882           else
6883             emitLabel (tlbl);
6884         }
6885       else
6886         {
6887           for (; (size--); offset++)
6888             {
6889               // normal case
6890               // result = left & right
6891               if (AOP_TYPE (right) == AOP_LIT)
6892                 {
6893                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6894                   if (bytelit == 0x0FF)
6895                     {
6896                       aopPut (result,
6897                               aopGet (left, offset, FALSE, FALSE),
6898                               offset);
6899                       continue;
6900                     }
6901                   else if (bytelit == 0)
6902                     {
6903                       /* dummy read of volatile operand */
6904                       if (isOperandVolatile (left, FALSE))
6905                         MOVA (aopGet (left, offset, FALSE, FALSE));
6906                       aopPut (result, zero, offset);
6907                       continue;
6908                     }
6909                   else if (AOP_TYPE (left) == AOP_ACC)
6910                     {
6911                       if (!offset)
6912                         {
6913                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6914                           aopPut (result, "a", offset);
6915                           continue;
6916                         }
6917                       else
6918                         {
6919                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6920                           aopPut (result, "b", offset);
6921                           continue;
6922                         }
6923                     }
6924                 }
6925               // faster than result <- left, anl result,right
6926               // and better if result is SFR
6927               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6928                   && AOP_TYPE(left)==AOP_ACC)
6929                 {
6930                   if (offset)
6931                     emitcode("mov", "a,b");
6932                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6933                 }
6934               else if (AOP_TYPE(left)==AOP_ACC)
6935                 {
6936                   if (!offset)
6937                     {
6938                       bool pushedB = pushB ();
6939                       emitcode("mov", "b,a");
6940                       MOVA (aopGet (right, offset, FALSE, FALSE));
6941                       emitcode("anl", "a,b");
6942                       popB (pushedB);
6943                     }
6944                   else
6945                     {
6946                       MOVA (aopGet (right, offset, FALSE, FALSE));
6947                       emitcode("anl", "a,b");
6948                     }
6949                 }
6950               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6951                 {
6952                   MOVB (aopGet (left, offset, FALSE, FALSE));
6953                   MOVA (aopGet (right, offset, FALSE, FALSE));
6954                   emitcode ("anl", "a,b");
6955                 }
6956               else if (aopGetUsesAcc (left, offset))
6957                 {
6958                   MOVA (aopGet (left, offset, FALSE, FALSE));
6959                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6960                 }
6961               else
6962                 {
6963                   MOVA (aopGet (right, offset, FALSE, FALSE));
6964                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6965                 }
6966               aopPut (result, "a", offset);
6967             }
6968         }
6969     }
6970
6971 release:
6972   freeAsmop (result, NULL, ic, TRUE);
6973   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6974   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6975 }
6976
6977 /*-----------------------------------------------------------------*/
6978 /* genOr  - code for or                                            */
6979 /*-----------------------------------------------------------------*/
6980 static void
6981 genOr (iCode * ic, iCode * ifx)
6982 {
6983   operand *left, *right, *result;
6984   int size, offset = 0;
6985   unsigned long lit = 0L;
6986   int bytelit = 0;
6987
6988   D (emitcode (";", "genOr"));
6989
6990   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6991   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6992   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6993
6994 #ifdef DEBUG_TYPE
6995   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6996             AOP_TYPE (result),
6997             AOP_TYPE (left), AOP_TYPE (right));
6998   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6999             AOP_SIZE (result),
7000             AOP_SIZE (left), AOP_SIZE (right));
7001 #endif
7002
7003   /* if left is a literal & right is not then exchange them */
7004   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7005       AOP_NEEDSACC (left))
7006     {
7007       operand *tmp = right;
7008       right = left;
7009       left = tmp;
7010     }
7011
7012   /* if result = right then exchange them */
7013   if (sameRegs (AOP (result), AOP (right)))
7014     {
7015       operand *tmp = right;
7016       right = left;
7017       left = tmp;
7018     }
7019
7020   /* if right is bit then exchange them */
7021   if (AOP_TYPE (right) == AOP_CRY &&
7022       AOP_TYPE (left) != AOP_CRY)
7023     {
7024       operand *tmp = right;
7025       right = left;
7026       left = tmp;
7027     }
7028   if (AOP_TYPE (right) == AOP_LIT)
7029     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7030
7031   size = AOP_SIZE (result);
7032
7033   // if(bit | yy)
7034   // xx = bit | yy;
7035   if (AOP_TYPE (left) == AOP_CRY)
7036     {
7037       if (AOP_TYPE (right) == AOP_LIT)
7038         {
7039           // c = bit | literal;
7040           if (lit)
7041             {
7042               // lit != 0 => result = 1
7043               if (AOP_TYPE (result) == AOP_CRY)
7044                 {
7045                   if (size)
7046                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7047                   else if (ifx)
7048                     continueIfTrue (ifx);
7049                   goto release;
7050                 }
7051               emitcode ("setb", "c");
7052             }
7053           else
7054             {
7055               // lit == 0 => result = left
7056               if (size && sameRegs (AOP (result), AOP (left)))
7057                 goto release;
7058               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7059             }
7060         }
7061       else
7062         {
7063           if (AOP_TYPE (right) == AOP_CRY)
7064             {
7065               // c = bit | bit;
7066               if (IS_OP_ACCUSE (left))
7067                 {
7068                   emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7069                 }
7070                           else
7071                 {
7072                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7073                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7074                 }
7075             }
7076           else
7077             {
7078               // c = bit | val;
7079               symbol *tlbl = newiTempLabel (NULL);
7080               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7081                 emitcode ("setb", "c");
7082               emitcode ("jb", "%s,%05d$",
7083                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7084               toBoolean (right);
7085               emitcode ("jnz", "%05d$", tlbl->key + 100);
7086               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7087                 {
7088                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7089                   goto release;
7090                 }
7091               else
7092                 {
7093                   CLRC;
7094                   emitLabel (tlbl);
7095                 }
7096             }
7097         }
7098       // bit = c
7099       // val = c
7100       if (size)
7101         outBitC (result);
7102       // if(bit | ...)
7103       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7104         genIfxJump (ifx, "c", left, right, result);
7105       goto release;
7106     }
7107
7108   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7109   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7110   if ((AOP_TYPE (right) == AOP_LIT) &&
7111       (AOP_TYPE (result) == AOP_CRY) &&
7112       (AOP_TYPE (left) != AOP_CRY))
7113     {
7114       if (lit)
7115         {
7116           // result = 1
7117           if (size)
7118             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7119           else
7120             continueIfTrue (ifx);
7121           goto release;
7122         }
7123       else
7124         {
7125           // lit = 0, result = boolean(left)
7126           if (size)
7127             emitcode ("setb", "c");
7128           toBoolean (right);
7129           if (size)
7130             {
7131               symbol *tlbl = newiTempLabel (NULL);
7132               emitcode ("jnz", "%05d$", tlbl->key + 100);
7133               CLRC;
7134               emitLabel (tlbl);
7135             }
7136           else
7137             {
7138               genIfxJump (ifx, "a", left, right, result);
7139               goto release;
7140             }
7141         }
7142       outBitC (result);
7143       goto release;
7144     }
7145
7146   /* if left is same as result */
7147   if (sameRegs (AOP (result), AOP (left)))
7148     {
7149       for (; size--; offset++)
7150         {
7151           if (AOP_TYPE (right) == AOP_LIT)
7152             {
7153               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7154               if (bytelit == 0)
7155                 {
7156                   /* dummy read of volatile operand */
7157                   if (isOperandVolatile (left, FALSE))
7158                     MOVA (aopGet (left, offset, FALSE, FALSE));
7159                   else
7160                     continue;
7161                 }
7162               else if (bytelit == 0x0FF)
7163                 {
7164                   aopPut (result, "#0xFF", offset);
7165                 }
7166               else if (IS_AOP_PREG (left))
7167                 {
7168                   MOVA (aopGet (left, offset, FALSE, TRUE));
7169                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7170                   aopPut (result, "a", offset);
7171                 }
7172               else
7173                 {
7174                   emitcode ("orl", "%s,%s",
7175                             aopGet (left, offset, FALSE, TRUE),
7176                             aopGet (right, offset, FALSE, FALSE));
7177                 }
7178             }
7179           else
7180             {
7181               if (AOP_TYPE (left) == AOP_ACC)
7182                 {
7183                   if (offset)
7184                     emitcode("mov", "a,b");
7185                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7186                 }
7187               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7188                 {
7189                   MOVB (aopGet (left, offset, FALSE, FALSE));
7190                   MOVA (aopGet (right, offset, FALSE, FALSE));
7191                   emitcode ("orl", "a,b");
7192                   aopPut (result, "a", offset);
7193                 }
7194               else if (aopGetUsesAcc (left, offset))
7195                 {
7196                   MOVA (aopGet (left, offset, FALSE, FALSE));
7197                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7198                   aopPut (result, "a", offset);
7199                 }
7200               else
7201                 {
7202                   MOVA (aopGet (right, offset, FALSE, FALSE));
7203                   if (IS_AOP_PREG (left))
7204                     {
7205                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7206                       aopPut (result, "a", offset);
7207                     }
7208                   else
7209                     {
7210                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7211                     }
7212                 }
7213             }
7214         }
7215     }
7216   else
7217     {
7218       // left & result in different registers
7219       if (AOP_TYPE (result) == AOP_CRY)
7220         {
7221           // result = bit
7222           // if(size), result in bit
7223           // if(!size && ifx), conditional oper: if(left | right)
7224           symbol *tlbl = newiTempLabel (NULL);
7225           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7226           if (size)
7227             emitcode ("setb", "c");
7228           while (sizer--)
7229             {
7230               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7231                   && AOP_TYPE(left)==AOP_ACC)
7232                 {
7233                   if (offset)
7234                     emitcode("mov", "a,b");
7235                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7236                 }
7237               else if (AOP_TYPE(left)==AOP_ACC)
7238                 {
7239                   if (!offset)
7240                     {
7241                       bool pushedB = pushB ();
7242                       emitcode("mov", "b,a");
7243                       MOVA (aopGet (right, offset, FALSE, FALSE));
7244                       emitcode("orl", "a,b");
7245                       popB (pushedB);
7246                     }
7247                   else
7248                     {
7249                       MOVA (aopGet (right, offset, FALSE, FALSE));
7250                       emitcode("orl", "a,b");
7251                     }
7252                 }
7253               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7254                 {
7255                   MOVB (aopGet (left, offset, FALSE, FALSE));
7256                   MOVA (aopGet (right, offset, FALSE, FALSE));
7257                   emitcode ("orl", "a,b");
7258                 }
7259               else if (aopGetUsesAcc (left, offset))
7260                 {
7261                   MOVA (aopGet (left, offset, FALSE, FALSE));
7262                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7263                 }
7264               else
7265                 {
7266                   MOVA (aopGet (right, offset, FALSE, FALSE));
7267                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7268               }
7269
7270               emitcode ("jnz", "%05d$", tlbl->key + 100);
7271               offset++;
7272             }
7273           if (size)
7274             {
7275               CLRC;
7276               emitLabel (tlbl);
7277               outBitC (result);
7278             }
7279           else if (ifx)
7280             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7281           else
7282             emitLabel (tlbl);
7283         }
7284       else
7285         {
7286           for (; (size--); offset++)
7287             {
7288               // normal case
7289               // result = left | right
7290               if (AOP_TYPE (right) == AOP_LIT)
7291                 {
7292                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7293                   if (bytelit == 0)
7294                     {
7295                       aopPut (result,
7296                               aopGet (left, offset, FALSE, FALSE),
7297                               offset);
7298                       continue;
7299                     }
7300                   else if (bytelit == 0x0FF)
7301                     {
7302                       /* dummy read of volatile operand */
7303                       if (isOperandVolatile (left, FALSE))
7304                         MOVA (aopGet (left, offset, FALSE, FALSE));
7305                       aopPut (result, "#0xFF", offset);
7306                       continue;
7307                     }
7308                 }
7309               // faster than result <- left, orl result,right
7310               // and better if result is SFR
7311               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7312                   && AOP_TYPE(left)==AOP_ACC)
7313                 {
7314                   if (offset)
7315                     emitcode("mov", "a,b");
7316                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7317                 }
7318               else if (AOP_TYPE(left)==AOP_ACC)
7319                 {
7320                   if (!offset)
7321                     {
7322                       bool pushedB = pushB ();
7323                       emitcode("mov", "b,a");
7324                       MOVA (aopGet (right, offset, FALSE, FALSE));
7325                       emitcode("orl", "a,b");
7326                       popB (pushedB);
7327                     }
7328                   else
7329                     {
7330                       MOVA (aopGet (right, offset, FALSE, FALSE));
7331                       emitcode("orl", "a,b");
7332                     }
7333                 }
7334               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7335                 {
7336                   MOVB (aopGet (left, offset, FALSE, FALSE));
7337                   MOVA (aopGet (right, offset, FALSE, FALSE));
7338                   emitcode ("orl", "a,b");
7339                 }
7340               else if (aopGetUsesAcc (left, offset))
7341                 {
7342                   MOVA (aopGet (left, offset, FALSE, FALSE));
7343                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7344                 }
7345               else
7346                 {
7347                   MOVA (aopGet (right, offset, FALSE, FALSE));
7348                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7349                 }
7350               aopPut (result, "a", offset);
7351             }
7352         }
7353     }
7354
7355 release:
7356   freeAsmop (result, NULL, ic, TRUE);
7357   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7358   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7359 }
7360
7361 /*-----------------------------------------------------------------*/
7362 /* genXor - code for xclusive or                                   */
7363 /*-----------------------------------------------------------------*/
7364 static void
7365 genXor (iCode * ic, iCode * ifx)
7366 {
7367   operand *left, *right, *result;
7368   int size, offset = 0;
7369   unsigned long lit = 0L;
7370   int bytelit = 0;
7371
7372   D (emitcode (";", "genXor"));
7373
7374   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7375   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7376   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7377
7378 #ifdef DEBUG_TYPE
7379   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7380             AOP_TYPE (result),
7381             AOP_TYPE (left), AOP_TYPE (right));
7382   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7383             AOP_SIZE (result),
7384             AOP_SIZE (left), AOP_SIZE (right));
7385 #endif
7386
7387   /* if left is a literal & right is not ||
7388      if left needs acc & right does not */
7389   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7390       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7391     {
7392       operand *tmp = right;
7393       right = left;
7394       left = tmp;
7395     }
7396
7397   /* if result = right then exchange them */
7398   if (sameRegs (AOP (result), AOP (right)))
7399     {
7400       operand *tmp = right;
7401       right = left;
7402       left = tmp;
7403     }
7404
7405   /* if right is bit then exchange them */
7406   if (AOP_TYPE (right) == AOP_CRY &&
7407       AOP_TYPE (left) != AOP_CRY)
7408     {
7409       operand *tmp = right;
7410       right = left;
7411       left = tmp;
7412     }
7413
7414   if (AOP_TYPE (right) == AOP_LIT)
7415     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7416
7417   size = AOP_SIZE (result);
7418
7419   // if(bit ^ yy)
7420   // xx = bit ^ yy;
7421   if (AOP_TYPE (left) == AOP_CRY)
7422     {
7423       if (AOP_TYPE (right) == AOP_LIT)
7424         {
7425           // c = bit & literal;
7426           if (lit >> 1)
7427             {
7428               // lit>>1  != 0 => result = 1
7429               if (AOP_TYPE (result) == AOP_CRY)
7430                 {
7431                   if (size)
7432                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7433                   else if (ifx)
7434                     continueIfTrue (ifx);
7435                   goto release;
7436                 }
7437               emitcode ("setb", "c");
7438             }
7439           else
7440             {
7441               // lit == (0 or 1)
7442               if (lit == 0)
7443                 {
7444                   // lit == 0, result = left
7445                   if (size && sameRegs (AOP (result), AOP (left)))
7446                     goto release;
7447                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7448                 }
7449               else
7450                 {
7451                   // lit == 1, result = not(left)
7452                   if (size && sameRegs (AOP (result), AOP (left)))
7453                     {
7454                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7455                       goto release;
7456                     }
7457                   else
7458                     {
7459                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7460                       emitcode ("cpl", "c");
7461                     }
7462                 }
7463             }
7464         }
7465       else
7466         {
7467           // right != literal
7468           symbol *tlbl = newiTempLabel (NULL);
7469           if (AOP_TYPE (right) == AOP_CRY)
7470             {
7471               // c = bit ^ bit;
7472               if (IS_OP_ACCUSE (left))
7473                 {// left already is in the carry
7474                   operand *tmp = right;
7475                   right = left;
7476                   left = tmp;
7477                 }
7478               else
7479                 {
7480                   toCarry (right);
7481                 }
7482             }
7483           else
7484             {
7485               // c = bit ^ val
7486               toCarry (right);
7487             }
7488           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7489           emitcode ("cpl", "c");
7490           emitLabel (tlbl);
7491         }
7492       // bit = c
7493       // val = c
7494       if (size)
7495         outBitC (result);
7496       // if(bit ^ ...)
7497       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7498         genIfxJump (ifx, "c", left, right, result);
7499       goto release;
7500     }
7501
7502   /* if left is same as result */
7503   if (sameRegs (AOP (result), AOP (left)))
7504     {
7505       for (; size--; offset++)
7506         {
7507           if (AOP_TYPE (right) == AOP_LIT)
7508             {
7509               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7510               if (bytelit == 0)
7511                 {
7512                   /* dummy read of volatile operand */
7513                   if (isOperandVolatile (left, FALSE))
7514                     MOVA (aopGet (left, offset, FALSE, FALSE));
7515                   else
7516                     continue;
7517                 }
7518               else if (IS_AOP_PREG (left))
7519                 {
7520                   MOVA (aopGet (left, offset, FALSE, TRUE));
7521                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7522                   aopPut (result, "a", offset);
7523                 }
7524               else
7525                 {
7526                   emitcode ("xrl", "%s,%s",
7527                             aopGet (left, offset, FALSE, TRUE),
7528                             aopGet (right, offset, FALSE, FALSE));
7529                 }
7530             }
7531           else
7532             {
7533               if (AOP_TYPE (left) == AOP_ACC)
7534                 {
7535                   if (offset)
7536                     emitcode("mov", "a,b");
7537                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7538                 }
7539               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7540                 {
7541                   MOVB (aopGet (left, offset, FALSE, FALSE));
7542                   MOVA (aopGet (right, offset, FALSE, FALSE));
7543                   emitcode ("xrl", "a,b");
7544                   aopPut (result, "a", offset);
7545                 }
7546               else if (aopGetUsesAcc (left, offset))
7547                 {
7548                   MOVA (aopGet (left, offset, FALSE, FALSE));
7549                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7550                   aopPut (result, "a", offset);
7551                 }
7552               else
7553                 {
7554                   MOVA (aopGet (right, offset, FALSE, FALSE));
7555                   if (IS_AOP_PREG (left))
7556                     {
7557                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7558                       aopPut (result, "a", offset);
7559                     }
7560                   else
7561                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7562                 }
7563             }
7564         }
7565     }
7566   else
7567     {
7568       // left & result in different registers
7569       if (AOP_TYPE (result) == AOP_CRY)
7570         {
7571           // result = bit
7572           // if(size), result in bit
7573           // if(!size && ifx), conditional oper: if(left ^ right)
7574           symbol *tlbl = newiTempLabel (NULL);
7575           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7576
7577           if (size)
7578             emitcode ("setb", "c");
7579           while (sizer--)
7580             {
7581               if ((AOP_TYPE (right) == AOP_LIT) &&
7582                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7583                 {
7584                   MOVA (aopGet (left, offset, FALSE, FALSE));
7585                 }
7586               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7587                   && AOP_TYPE(left)==AOP_ACC)
7588                 {
7589                   if (offset)
7590                     emitcode("mov", "a,b");
7591                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7592                 }
7593               else if (AOP_TYPE(left)==AOP_ACC)
7594                 {
7595                   if (!offset)
7596                     {
7597                       bool pushedB = pushB ();
7598                       emitcode("mov", "b,a");
7599                       MOVA (aopGet (right, offset, FALSE, FALSE));
7600                       emitcode("xrl", "a,b");
7601                       popB (pushedB);
7602                     }
7603                   else
7604                     {
7605                       MOVA (aopGet (right, offset, FALSE, FALSE));
7606                       emitcode("xrl", "a,b");
7607                     }
7608                 }
7609               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7610                 {
7611                   MOVB (aopGet (left, offset, FALSE, FALSE));
7612                   MOVA (aopGet (right, offset, FALSE, FALSE));
7613                   emitcode ("xrl", "a,b");
7614                 }
7615               else if (aopGetUsesAcc (left, offset))
7616                 {
7617                   MOVA (aopGet (left, offset, FALSE, FALSE));
7618                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7619                 }
7620               else
7621                 {
7622                   MOVA (aopGet (right, offset, FALSE, FALSE));
7623                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7624                 }
7625
7626               emitcode ("jnz", "%05d$", tlbl->key + 100);
7627               offset++;
7628             }
7629           if (size)
7630             {
7631               CLRC;
7632               emitLabel (tlbl);
7633               outBitC (result);
7634             }
7635           else if (ifx)
7636             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7637         }
7638       else
7639         {
7640           for (; (size--); offset++)
7641             {
7642               // normal case
7643               // result = left ^ right
7644               if (AOP_TYPE (right) == AOP_LIT)
7645                 {
7646                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7647                   if (bytelit == 0)
7648                     {
7649                       aopPut (result,
7650                               aopGet (left, offset, FALSE, FALSE),
7651                               offset);
7652                       continue;
7653                     }
7654                 }
7655               // faster than result <- left, xrl result,right
7656               // and better if result is SFR
7657               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7658                   && AOP_TYPE(left)==AOP_ACC)
7659                 {
7660                   if (offset)
7661                     emitcode("mov", "a,b");
7662                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7663                 }
7664               else if (AOP_TYPE(left)==AOP_ACC)
7665                 {
7666                   if (!offset)
7667                     {
7668                       bool pushedB = pushB ();
7669                       emitcode("mov", "b,a");
7670                       MOVA (aopGet (right, offset, FALSE, FALSE));
7671                       emitcode("xrl", "a,b");
7672                       popB (pushedB);
7673                     }
7674                   else
7675                     {
7676                       MOVA (aopGet (right, offset, FALSE, FALSE));
7677                       emitcode("xrl", "a,b");
7678                     }
7679                 }
7680               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7681                 {
7682                   MOVB (aopGet (left, offset, FALSE, FALSE));
7683                   MOVA (aopGet (right, offset, FALSE, FALSE));
7684                   emitcode ("xrl", "a,b");
7685                 }
7686               else if (aopGetUsesAcc (left, offset))
7687                 {
7688                   MOVA (aopGet (left, offset, FALSE, FALSE));
7689                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7690                 }
7691               else
7692                 {
7693                   MOVA (aopGet (right, offset, FALSE, FALSE));
7694                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7695                 }
7696               aopPut (result, "a", offset);
7697             }
7698         }
7699     }
7700
7701 release:
7702   freeAsmop (result, NULL, ic, TRUE);
7703   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7704   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7705 }
7706
7707 /*-----------------------------------------------------------------*/
7708 /* genInline - write the inline code out                           */
7709 /*-----------------------------------------------------------------*/
7710 static void
7711 genInline (iCode * ic)
7712 {
7713   char *buffer, *bp, *bp1;
7714   bool inComment = FALSE;
7715
7716   D (emitcode (";", "genInline"));
7717
7718   _G.inLine += (!options.asmpeep);
7719
7720   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7721
7722   /* emit each line as a code */
7723   while (*bp)
7724     {
7725       switch (*bp)
7726         {
7727         case ';':
7728           inComment = TRUE;
7729           ++bp;
7730           break;
7731
7732         case '\n':
7733           inComment = FALSE;
7734           *bp++ = '\0';
7735           emitcode (bp1, "");
7736           bp1 = bp;
7737           break;
7738
7739         default:
7740           /* Add \n for labels, not dirs such as c:\mydir */
7741           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7742             {
7743               ++bp;
7744               *bp = '\0';
7745               ++bp;
7746               emitcode (bp1, "");
7747               bp1 = bp;
7748             }
7749           else
7750             ++bp;
7751           break;
7752         }
7753     }
7754   if (bp1 != bp)
7755     emitcode (bp1, "");
7756
7757   Safe_free (buffer);
7758
7759   _G.inLine -= (!options.asmpeep);
7760 }
7761
7762 /*-----------------------------------------------------------------*/
7763 /* genRRC - rotate right with carry                                */
7764 /*-----------------------------------------------------------------*/
7765 static void
7766 genRRC (iCode * ic)
7767 {
7768   operand *left, *result;
7769   int size, offset;
7770   char *l;
7771
7772   D (emitcode (";", "genRRC"));
7773
7774   /* rotate right with carry */
7775   left = IC_LEFT (ic);
7776   result = IC_RESULT (ic);
7777   aopOp (left, ic, FALSE);
7778   aopOp (result, ic, FALSE);
7779
7780   /* move it to the result */
7781   size = AOP_SIZE (result);
7782   offset = size - 1;
7783   if (size == 1) { /* special case for 1 byte */
7784       l = aopGet (left, offset, FALSE, FALSE);
7785       MOVA (l);
7786       emitcode ("rr", "a");
7787       goto release;
7788   }
7789   /* no need to clear carry, bit7 will be written later */
7790   while (size--)
7791     {
7792       l = aopGet (left, offset, FALSE, FALSE);
7793       MOVA (l);
7794       emitcode ("rrc", "a");
7795       if (AOP_SIZE (result) > 1)
7796         aopPut (result, "a", offset--);
7797     }
7798   /* now we need to put the carry into the
7799      highest order byte of the result */
7800   if (AOP_SIZE (result) > 1)
7801     {
7802       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7803       MOVA (l);
7804     }
7805   emitcode ("mov", "acc.7,c");
7806  release:
7807   aopPut (result, "a", AOP_SIZE (result) - 1);
7808   freeAsmop (result, NULL, ic, TRUE);
7809   freeAsmop (left, NULL, ic, TRUE);
7810 }
7811
7812 /*-----------------------------------------------------------------*/
7813 /* genRLC - generate code for rotate left with carry               */
7814 /*-----------------------------------------------------------------*/
7815 static void
7816 genRLC (iCode * ic)
7817 {
7818   operand *left, *result;
7819   int size, offset;
7820   char *l;
7821
7822   D (emitcode (";", "genRLC"));
7823
7824   /* rotate right with carry */
7825   left = IC_LEFT (ic);
7826   result = IC_RESULT (ic);
7827   aopOp (left, ic, FALSE);
7828   aopOp (result, ic, FALSE);
7829
7830   /* move it to the result */
7831   size = AOP_SIZE (result);
7832   offset = 0;
7833   if (size--)
7834     {
7835       l = aopGet (left, offset, FALSE, FALSE);
7836       MOVA (l);
7837       if (size == 0) { /* special case for 1 byte */
7838               emitcode("rl","a");
7839               goto release;
7840       }
7841       emitcode("rlc","a"); /* bit0 will be written later */
7842       if (AOP_SIZE (result) > 1)
7843         {
7844           aopPut (result, "a", offset++);
7845         }
7846
7847       while (size--)
7848         {
7849           l = aopGet (left, offset, FALSE, FALSE);
7850           MOVA (l);
7851           emitcode ("rlc", "a");
7852           if (AOP_SIZE (result) > 1)
7853             aopPut (result, "a", offset++);
7854         }
7855     }
7856   /* now we need to put the carry into the
7857      highest order byte of the result */
7858   if (AOP_SIZE (result) > 1)
7859     {
7860       l = aopGet (result, 0, FALSE, FALSE);
7861       MOVA (l);
7862     }
7863   emitcode ("mov", "acc.0,c");
7864  release:
7865   aopPut (result, "a", 0);
7866   freeAsmop (result, NULL, ic, TRUE);
7867   freeAsmop (left, NULL, ic, TRUE);
7868 }
7869
7870 /*-----------------------------------------------------------------*/
7871 /* genGetHbit - generates code get highest order bit               */
7872 /*-----------------------------------------------------------------*/
7873 static void
7874 genGetHbit (iCode * ic)
7875 {
7876   operand *left, *result;
7877
7878   D (emitcode (";", "genGetHbit"));
7879
7880   left = IC_LEFT (ic);
7881   result = IC_RESULT (ic);
7882   aopOp (left, ic, FALSE);
7883   aopOp (result, ic, FALSE);
7884
7885   /* get the highest order byte into a */
7886   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7887   if (AOP_TYPE (result) == AOP_CRY)
7888     {
7889       emitcode ("rlc", "a");
7890       outBitC (result);
7891     }
7892   else
7893     {
7894       emitcode ("rl", "a");
7895       emitcode ("anl", "a,#0x01");
7896       outAcc (result);
7897     }
7898
7899   freeAsmop (result, NULL, ic, TRUE);
7900   freeAsmop (left, NULL, ic, TRUE);
7901 }
7902
7903 /*-----------------------------------------------------------------*/
7904 /* genGetAbit - generates code get a single bit                    */
7905 /*-----------------------------------------------------------------*/
7906 static void
7907 genGetAbit (iCode * ic)
7908 {
7909   operand *left, *right, *result;
7910   int shCount;
7911
7912   D (emitcode (";", "genGetAbit"));
7913
7914   left = IC_LEFT (ic);
7915   right = IC_RIGHT (ic);
7916   result = IC_RESULT (ic);
7917   aopOp (left, ic, FALSE);
7918   aopOp (right, ic, FALSE);
7919   aopOp (result, ic, FALSE);
7920
7921   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7922
7923   /* get the needed byte into a */
7924   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7925   shCount %= 8;
7926   if (AOP_TYPE (result) == AOP_CRY)
7927     {
7928       if ((shCount) == 7)
7929           emitcode ("rlc", "a");
7930       else if ((shCount) == 0)
7931           emitcode ("rrc", "a");
7932       else
7933           emitcode ("mov", "c,acc[%d]", shCount);
7934       outBitC (result);
7935     }
7936   else
7937     {
7938       switch (shCount)
7939         {
7940         case 2:
7941           emitcode ("rr", "a");
7942           //fallthrough
7943         case 1:
7944           emitcode ("rr", "a");
7945           //fallthrough
7946         case 0:
7947           emitcode ("anl", "a,#0x01");
7948           break;
7949         case 3:
7950         case 5:
7951           emitcode ("mov", "c,acc[%d]", shCount);
7952           emitcode ("clr", "a");
7953           emitcode ("rlc", "a");
7954           break;
7955         case 4:
7956           emitcode ("swap", "a");
7957           emitcode ("anl", "a,#0x01");
7958           break;
7959         case 6:
7960           emitcode ("rl", "a");
7961           //fallthrough
7962         case 7:
7963           emitcode ("rl", "a");
7964           emitcode ("anl", "a,#0x01");
7965           break;
7966         }
7967       outAcc (result);
7968     }
7969
7970   freeAsmop (result, NULL, ic, TRUE);
7971   freeAsmop (right, NULL, ic, TRUE);
7972   freeAsmop (left, NULL, ic, TRUE);
7973 }
7974
7975 /*-----------------------------------------------------------------*/
7976 /* genGetByte - generates code get a single byte                   */
7977 /*-----------------------------------------------------------------*/
7978 static void
7979 genGetByte (iCode * ic)
7980 {
7981   operand *left, *right, *result;
7982   int offset;
7983
7984   D (emitcode (";", "genGetByte"));
7985
7986   left = IC_LEFT (ic);
7987   right = IC_RIGHT (ic);
7988   result = IC_RESULT (ic);
7989   aopOp (left, ic, FALSE);
7990   aopOp (right, ic, FALSE);
7991   aopOp (result, ic, FALSE);
7992
7993   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
7994   aopPut (result,
7995           aopGet (left, offset, FALSE, FALSE),
7996           0);
7997
7998   freeAsmop (result, NULL, ic, TRUE);
7999   freeAsmop (right, NULL, ic, TRUE);
8000   freeAsmop (left, NULL, ic, TRUE);
8001 }
8002
8003 /*-----------------------------------------------------------------*/
8004 /* genGetWord - generates code get two bytes                       */
8005 /*-----------------------------------------------------------------*/
8006 static void
8007 genGetWord (iCode * ic)
8008 {
8009   operand *left, *right, *result;
8010   int offset;
8011
8012   D (emitcode (";", "genGetWord"));
8013
8014   left = IC_LEFT (ic);
8015   right = IC_RIGHT (ic);
8016   result = IC_RESULT (ic);
8017   aopOp (left, ic, FALSE);
8018   aopOp (right, ic, FALSE);
8019   aopOp (result, ic, FALSE);
8020
8021   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8022   aopPut (result,
8023           aopGet (left, offset, FALSE, FALSE),
8024           0);
8025   aopPut (result,
8026           aopGet (left, offset+1, FALSE, FALSE),
8027           1);
8028
8029   freeAsmop (result, NULL, ic, TRUE);
8030   freeAsmop (right, NULL, ic, TRUE);
8031   freeAsmop (left, NULL, ic, TRUE);
8032 }
8033
8034 /*-----------------------------------------------------------------*/
8035 /* genSwap - generates code to swap nibbles or bytes               */
8036 /*-----------------------------------------------------------------*/
8037 static void
8038 genSwap (iCode * ic)
8039 {
8040   operand *left, *result;
8041
8042   D(emitcode (";", "genSwap"));
8043
8044   left = IC_LEFT (ic);
8045   result = IC_RESULT (ic);
8046   aopOp (left, ic, FALSE);
8047   aopOp (result, ic, FALSE);
8048
8049   switch (AOP_SIZE (left))
8050     {
8051     case 1: /* swap nibbles in byte */
8052       MOVA (aopGet (left, 0, FALSE, FALSE));
8053       emitcode ("swap", "a");
8054       aopPut (result, "a", 0);
8055       break;
8056     case 2: /* swap bytes in word */
8057       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8058         {
8059           MOVA (aopGet (left, 0, FALSE, FALSE));
8060           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8061           aopPut (result, "a", 1);
8062         }
8063       else if (operandsEqu (left, result))
8064         {
8065           char * reg = "a";
8066           bool pushedB = FALSE, leftInB = FALSE;
8067
8068           MOVA (aopGet (left, 0, FALSE, FALSE));
8069           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8070             {
8071               pushedB = pushB ();
8072               emitcode ("mov", "b,a");
8073               reg = "b";
8074               leftInB = TRUE;
8075             }
8076           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8077           aopPut (result, reg, 1);
8078
8079           if (leftInB)
8080             popB (pushedB);
8081         }
8082       else
8083         {
8084           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8085           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8086         }
8087       break;
8088     default:
8089       wassertl(FALSE, "unsupported SWAP operand size");
8090     }
8091
8092   freeAsmop (result, NULL, ic, TRUE);
8093   freeAsmop (left, NULL, ic, TRUE);
8094 }
8095
8096 /*-----------------------------------------------------------------*/
8097 /* AccRol - rotate left accumulator by known count                 */
8098 /*-----------------------------------------------------------------*/
8099 static void
8100 AccRol (int shCount)
8101 {
8102   shCount &= 0x0007;            // shCount : 0..7
8103
8104   switch (shCount)
8105     {
8106     case 0:
8107       break;
8108     case 1:
8109       emitcode ("rl", "a");
8110       break;
8111     case 2:
8112       emitcode ("rl", "a");
8113       emitcode ("rl", "a");
8114       break;
8115     case 3:
8116       emitcode ("swap", "a");
8117       emitcode ("rr", "a");
8118       break;
8119     case 4:
8120       emitcode ("swap", "a");
8121       break;
8122     case 5:
8123       emitcode ("swap", "a");
8124       emitcode ("rl", "a");
8125       break;
8126     case 6:
8127       emitcode ("rr", "a");
8128       emitcode ("rr", "a");
8129       break;
8130     case 7:
8131       emitcode ("rr", "a");
8132       break;
8133     }
8134 }
8135
8136 /*-----------------------------------------------------------------*/
8137 /* AccLsh - left shift accumulator by known count                  */
8138 /*-----------------------------------------------------------------*/
8139 static void
8140 AccLsh (int shCount)
8141 {
8142   if (shCount != 0)
8143     {
8144       if (shCount == 1)
8145         emitcode ("add", "a,acc");
8146       else if (shCount == 2)
8147         {
8148           emitcode ("add", "a,acc");
8149           emitcode ("add", "a,acc");
8150         }
8151       else
8152         {
8153           /* rotate left accumulator */
8154           AccRol (shCount);
8155           /* and kill the lower order bits */
8156           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8157         }
8158     }
8159 }
8160
8161 /*-----------------------------------------------------------------*/
8162 /* AccRsh - right shift accumulator by known count                 */
8163 /*-----------------------------------------------------------------*/
8164 static void
8165 AccRsh (int shCount)
8166 {
8167   if (shCount != 0)
8168     {
8169       if (shCount == 1)
8170         {
8171           CLRC;
8172           emitcode ("rrc", "a");
8173         }
8174       else
8175         {
8176           /* rotate right accumulator */
8177           AccRol (8 - shCount);
8178           /* and kill the higher order bits */
8179           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8180         }
8181     }
8182 }
8183
8184 /*-----------------------------------------------------------------*/
8185 /* AccSRsh - signed right shift accumulator by known count                 */
8186 /*-----------------------------------------------------------------*/
8187 static void
8188 AccSRsh (int shCount)
8189 {
8190   symbol *tlbl;
8191   if (shCount != 0)
8192     {
8193       if (shCount == 1)
8194         {
8195           emitcode ("mov", "c,acc.7");
8196           emitcode ("rrc", "a");
8197         }
8198       else if (shCount == 2)
8199         {
8200           emitcode ("mov", "c,acc.7");
8201           emitcode ("rrc", "a");
8202           emitcode ("mov", "c,acc.7");
8203           emitcode ("rrc", "a");
8204         }
8205       else
8206         {
8207           tlbl = newiTempLabel (NULL);
8208           /* rotate right accumulator */
8209           AccRol (8 - shCount);
8210           /* and kill the higher order bits */
8211           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8212           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8213           emitcode ("orl", "a,#0x%02x",
8214                     (unsigned char) ~SRMask[shCount]);
8215           emitLabel (tlbl);
8216         }
8217     }
8218 }
8219
8220 /*-----------------------------------------------------------------*/
8221 /* shiftR1Left2Result - shift right one byte from left to result   */
8222 /*-----------------------------------------------------------------*/
8223 static void
8224 shiftR1Left2Result (operand * left, int offl,
8225                     operand * result, int offr,
8226                     int shCount, int sign)
8227 {
8228   MOVA (aopGet (left, offl, FALSE, FALSE));
8229   /* shift right accumulator */
8230   if (sign)
8231     AccSRsh (shCount);
8232   else
8233     AccRsh (shCount);
8234   aopPut (result, "a", offr);
8235 }
8236
8237 /*-----------------------------------------------------------------*/
8238 /* shiftL1Left2Result - shift left one byte from left to result    */
8239 /*-----------------------------------------------------------------*/
8240 static void
8241 shiftL1Left2Result (operand * left, int offl,
8242                     operand * result, int offr, int shCount)
8243 {
8244   char *l;
8245   l = aopGet (left, offl, FALSE, FALSE);
8246   MOVA (l);
8247   /* shift left accumulator */
8248   AccLsh (shCount);
8249   aopPut (result, "a", offr);
8250 }
8251
8252 /*-----------------------------------------------------------------*/
8253 /* movLeft2Result - move byte from left to result                  */
8254 /*-----------------------------------------------------------------*/
8255 static void
8256 movLeft2Result (operand * left, int offl,
8257                 operand * result, int offr, int sign)
8258 {
8259   char *l;
8260   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8261     {
8262       l = aopGet (left, offl, FALSE, FALSE);
8263
8264       if (*l == '@' && (IS_AOP_PREG (result)))
8265         {
8266           emitcode ("mov", "a,%s", l);
8267           aopPut (result, "a", offr);
8268         }
8269       else
8270         {
8271           if (!sign)
8272             {
8273               aopPut (result, l, offr);
8274             }
8275           else
8276             {
8277               /* MSB sign in acc.7 ! */
8278               if (getDataSize (left) == offl + 1)
8279                 {
8280                   MOVA (l);
8281                   aopPut (result, "a", offr);
8282                 }
8283             }
8284         }
8285     }
8286 }
8287
8288 /*-----------------------------------------------------------------*/
8289 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8290 /*-----------------------------------------------------------------*/
8291 static void
8292 AccAXRrl1 (char *x)
8293 {
8294   emitcode ("rrc", "a");
8295   emitcode ("xch", "a,%s", x);
8296   emitcode ("rrc", "a");
8297   emitcode ("xch", "a,%s", x);
8298 }
8299
8300 /*-----------------------------------------------------------------*/
8301 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8302 /*-----------------------------------------------------------------*/
8303 static void
8304 AccAXLrl1 (char *x)
8305 {
8306   emitcode ("xch", "a,%s", x);
8307   emitcode ("rlc", "a");
8308   emitcode ("xch", "a,%s", x);
8309   emitcode ("rlc", "a");
8310 }
8311
8312 /*-----------------------------------------------------------------*/
8313 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8314 /*-----------------------------------------------------------------*/
8315 static void
8316 AccAXLsh1 (char *x)
8317 {
8318   emitcode ("xch", "a,%s", x);
8319   emitcode ("add", "a,acc");
8320   emitcode ("xch", "a,%s", x);
8321   emitcode ("rlc", "a");
8322 }
8323
8324 /*-----------------------------------------------------------------*/
8325 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8326 /*-----------------------------------------------------------------*/
8327 static void
8328 AccAXLsh (char *x, int shCount)
8329 {
8330   switch (shCount)
8331     {
8332     case 0:
8333       break;
8334     case 1:
8335       AccAXLsh1 (x);
8336       break;
8337     case 2:
8338       AccAXLsh1 (x);
8339       AccAXLsh1 (x);
8340       break;
8341     case 3:
8342     case 4:
8343     case 5:                     // AAAAABBB:CCCCCDDD
8344
8345       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8346
8347       emitcode ("anl", "a,#0x%02x",
8348                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8349
8350       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8351
8352       AccRol (shCount);         // DDDCCCCC:BBB00000
8353
8354       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8355
8356       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8357
8358       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8359
8360       emitcode ("anl", "a,#0x%02x",
8361                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8362
8363       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8364
8365       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8366
8367       break;
8368     case 6:                     // AAAAAABB:CCCCCCDD
8369       emitcode ("anl", "a,#0x%02x",
8370                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8371       emitcode ("mov", "c,acc.0");      // c = B
8372       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8373 #if 0 // REMOVE ME
8374       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8375       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8376 #else
8377       emitcode("rrc","a");
8378       emitcode("xch","a,%s", x);
8379       emitcode("rrc","a");
8380       emitcode("mov","c,acc.0"); //<< get correct bit
8381       emitcode("xch","a,%s", x);
8382
8383       emitcode("rrc","a");
8384       emitcode("xch","a,%s", x);
8385       emitcode("rrc","a");
8386       emitcode("xch","a,%s", x);
8387 #endif
8388       break;
8389     case 7:                     // a:x <<= 7
8390
8391       emitcode ("anl", "a,#0x%02x",
8392                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8393
8394       emitcode ("mov", "c,acc.0");      // c = B
8395
8396       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8397
8398       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8399
8400       break;
8401     default:
8402       break;
8403     }
8404 }
8405
8406 /*-----------------------------------------------------------------*/
8407 /* AccAXRsh - right shift a:x known count (0..7)                   */
8408 /*-----------------------------------------------------------------*/
8409 static void
8410 AccAXRsh (char *x, int shCount)
8411 {
8412   switch (shCount)
8413     {
8414     case 0:
8415       break;
8416     case 1:
8417       CLRC;
8418       AccAXRrl1 (x);            // 0->a:x
8419
8420       break;
8421     case 2:
8422       CLRC;
8423       AccAXRrl1 (x);            // 0->a:x
8424
8425       CLRC;
8426       AccAXRrl1 (x);            // 0->a:x
8427
8428       break;
8429     case 3:
8430     case 4:
8431     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8432
8433       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8434
8435       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8436
8437       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8438
8439       emitcode ("anl", "a,#0x%02x",
8440                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8441
8442       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8443
8444       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8445
8446       emitcode ("anl", "a,#0x%02x",
8447                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8448
8449       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8450
8451       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8452
8453       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8454
8455       break;
8456     case 6:                     // AABBBBBB:CCDDDDDD
8457
8458       emitcode ("mov", "c,acc.7");
8459       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8460
8461       emitcode ("mov", "c,acc.7");
8462       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8463
8464       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8465
8466       emitcode ("anl", "a,#0x%02x",
8467                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8468
8469       break;
8470     case 7:                     // ABBBBBBB:CDDDDDDD
8471
8472       emitcode ("mov", "c,acc.7");      // c = A
8473
8474       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8475
8476       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8477
8478       emitcode ("anl", "a,#0x%02x",
8479                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8480
8481       break;
8482     default:
8483       break;
8484     }
8485 }
8486
8487 /*-----------------------------------------------------------------*/
8488 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8489 /*-----------------------------------------------------------------*/
8490 static void
8491 AccAXRshS (char *x, int shCount)
8492 {
8493   symbol *tlbl;
8494   switch (shCount)
8495     {
8496     case 0:
8497       break;
8498     case 1:
8499       emitcode ("mov", "c,acc.7");
8500       AccAXRrl1 (x);            // s->a:x
8501
8502       break;
8503     case 2:
8504       emitcode ("mov", "c,acc.7");
8505       AccAXRrl1 (x);            // s->a:x
8506
8507       emitcode ("mov", "c,acc.7");
8508       AccAXRrl1 (x);            // s->a:x
8509
8510       break;
8511     case 3:
8512     case 4:
8513     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8514
8515       tlbl = newiTempLabel (NULL);
8516       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8517
8518       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8519
8520       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8521
8522       emitcode ("anl", "a,#0x%02x",
8523                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8524
8525       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8526
8527       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8528
8529       emitcode ("anl", "a,#0x%02x",
8530                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8531
8532       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8533
8534       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8535
8536       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8537
8538       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8539       emitcode ("orl", "a,#0x%02x",
8540                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8541
8542       emitLabel (tlbl);
8543       break;                    // SSSSAAAA:BBBCCCCC
8544
8545     case 6:                     // AABBBBBB:CCDDDDDD
8546
8547       tlbl = newiTempLabel (NULL);
8548       emitcode ("mov", "c,acc.7");
8549       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8550
8551       emitcode ("mov", "c,acc.7");
8552       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8553
8554       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8555
8556       emitcode ("anl", "a,#0x%02x",
8557                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8558
8559       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8560       emitcode ("orl", "a,#0x%02x",
8561                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8562
8563       emitLabel (tlbl);
8564       break;
8565     case 7:                     // ABBBBBBB:CDDDDDDD
8566
8567       tlbl = newiTempLabel (NULL);
8568       emitcode ("mov", "c,acc.7");      // c = A
8569
8570       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8571
8572       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8573
8574       emitcode ("anl", "a,#0x%02x",
8575                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8576
8577       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8578       emitcode ("orl", "a,#0x%02x",
8579                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8580
8581       emitLabel (tlbl);
8582       break;
8583     default:
8584       break;
8585     }
8586 }
8587
8588 /*-----------------------------------------------------------------*/
8589 /* shiftL2Left2Result - shift left two bytes from left to result   */
8590 /*-----------------------------------------------------------------*/
8591 static void
8592 shiftL2Left2Result (operand * left, int offl,
8593                     operand * result, int offr, int shCount)
8594 {
8595   char * x;
8596   bool pushedB = FALSE;
8597   bool usedB = FALSE;
8598
8599   if (sameRegs (AOP (result), AOP (left)) &&
8600       ((offl + MSB16) == offr))
8601     {
8602       /* don't crash result[offr] */
8603       MOVA (aopGet (left, offl, FALSE, FALSE));
8604       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8605       usedB = !strncmp(x, "b", 1);
8606     }
8607   else if (aopGetUsesAcc (result, offr))
8608     {
8609       movLeft2Result (left, offl, result, offr, 0);
8610       pushedB = pushB ();
8611       usedB = TRUE;
8612       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8613       MOVA (aopGet (result, offr, FALSE, FALSE));
8614       emitcode ("xch", "a,b");
8615       x = "b";
8616     }
8617   else
8618     {
8619       movLeft2Result (left, offl, result, offr, 0);
8620       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8621       x = aopGet (result, offr, FALSE, FALSE);
8622     }
8623   /* ax << shCount (x = lsb(result)) */
8624   AccAXLsh (x, shCount);
8625   if (usedB)
8626     {
8627       emitcode ("xch", "a,b");
8628       aopPut (result, "a", offr);
8629       aopPut (result, "b", offr + MSB16);
8630       popB (pushedB);
8631     }
8632   else
8633     {
8634       aopPut (result, "a", offr + MSB16);
8635     }
8636 }
8637
8638
8639 /*-----------------------------------------------------------------*/
8640 /* shiftR2Left2Result - shift right two bytes from left to result  */
8641 /*-----------------------------------------------------------------*/
8642 static void
8643 shiftR2Left2Result (operand * left, int offl,
8644                     operand * result, int offr,
8645                     int shCount, int sign)
8646 {
8647   char * x;
8648   bool pushedB = FALSE;
8649   bool usedB = FALSE;
8650
8651   if (sameRegs (AOP (result), AOP (left)) &&
8652       ((offl + MSB16) == offr))
8653     {
8654       /* don't crash result[offr] */
8655       MOVA (aopGet (left, offl, FALSE, FALSE));
8656       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8657       usedB = !strncmp(x, "b", 1);
8658     }
8659   else if (aopGetUsesAcc (result, offr))
8660     {
8661       movLeft2Result (left, offl, result, offr, 0);
8662       pushedB = pushB ();
8663       usedB = TRUE;
8664       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8665       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8666       x = "b";
8667     }
8668   else
8669     {
8670       movLeft2Result (left, offl, result, offr, 0);
8671       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8672       x = aopGet (result, offr, FALSE, FALSE);
8673     }
8674   /* a:x >> shCount (x = lsb(result)) */
8675   if (sign)
8676     AccAXRshS (x, shCount);
8677   else
8678     AccAXRsh (x, shCount);
8679   if (usedB)
8680     {
8681       emitcode ("xch", "a,b");
8682       aopPut (result, "a", offr);
8683       emitcode ("xch", "a,b");
8684       popB (pushedB);
8685     }
8686   if (getDataSize (result) > 1)
8687     aopPut (result, "a", offr + MSB16);
8688 }
8689
8690 /*-----------------------------------------------------------------*/
8691 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8692 /*-----------------------------------------------------------------*/
8693 static void
8694 shiftLLeftOrResult (operand * left, int offl,
8695                     operand * result, int offr, int shCount)
8696 {
8697   MOVA (aopGet (left, offl, FALSE, FALSE));
8698   /* shift left accumulator */
8699   AccLsh (shCount);
8700   /* or with result */
8701   if (aopGetUsesAcc (result, offr))
8702     {
8703       emitcode ("xch", "a,b");
8704       MOVA (aopGet (result, offr, FALSE, FALSE));
8705       emitcode ("orl", "a,b");
8706     }
8707   else
8708     {
8709       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8710     }
8711   /* back to result */
8712   aopPut (result, "a", offr);
8713 }
8714
8715 /*-----------------------------------------------------------------*/
8716 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8717 /*-----------------------------------------------------------------*/
8718 static void
8719 shiftRLeftOrResult (operand * left, int offl,
8720                     operand * result, int offr, int shCount)
8721 {
8722   MOVA (aopGet (left, offl, FALSE, FALSE));
8723   /* shift right accumulator */
8724   AccRsh (shCount);
8725   /* or with result */
8726   if (aopGetUsesAcc(result, offr))
8727     {
8728       emitcode ("xch", "a,b");
8729       MOVA (aopGet (result, offr, FALSE, FALSE));
8730       emitcode ("orl", "a,b");
8731     }
8732   else
8733     {
8734       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8735     }
8736   /* back to result */
8737   aopPut (result, "a", offr);
8738 }
8739
8740 /*-----------------------------------------------------------------*/
8741 /* genlshOne - left shift a one byte quantity by known count       */
8742 /*-----------------------------------------------------------------*/
8743 static void
8744 genlshOne (operand * result, operand * left, int shCount)
8745 {
8746   D (emitcode (";", "genlshOne"));
8747
8748   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8749 }
8750
8751 /*-----------------------------------------------------------------*/
8752 /* genlshTwo - left shift two bytes by known amount != 0           */
8753 /*-----------------------------------------------------------------*/
8754 static void
8755 genlshTwo (operand * result, operand * left, int shCount)
8756 {
8757   int size;
8758
8759   D (emitcode (";", "genlshTwo"));
8760
8761   size = getDataSize (result);
8762
8763   /* if shCount >= 8 */
8764   if (shCount >= 8)
8765     {
8766       shCount -= 8;
8767
8768       if (size > 1)
8769         {
8770           if (shCount)
8771             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8772           else
8773             movLeft2Result (left, LSB, result, MSB16, 0);
8774         }
8775       aopPut (result, zero, LSB);
8776     }
8777
8778   /*  1 <= shCount <= 7 */
8779   else
8780     {
8781       if (size == 1)
8782         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8783       else
8784         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8785     }
8786 }
8787
8788 /*-----------------------------------------------------------------*/
8789 /* shiftLLong - shift left one long from left to result            */
8790 /* offl = LSB or MSB16                                             */
8791 /*-----------------------------------------------------------------*/
8792 static void
8793 shiftLLong (operand * left, operand * result, int offr)
8794 {
8795   char *l;
8796   int size = AOP_SIZE (result);
8797
8798   if (size >= LSB + offr)
8799     {
8800       l = aopGet (left, LSB, FALSE, FALSE);
8801       MOVA (l);
8802       emitcode ("add", "a,acc");
8803       if (sameRegs (AOP (left), AOP (result)) &&
8804           size >= MSB16 + offr && offr != LSB)
8805         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8806       else
8807         aopPut (result, "a", LSB + offr);
8808     }
8809
8810   if (size >= MSB16 + offr)
8811     {
8812       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8813         {
8814           l = aopGet (left, MSB16, FALSE, FALSE);
8815           MOVA (l);
8816         }
8817       emitcode ("rlc", "a");
8818       if (sameRegs (AOP (left), AOP (result)) &&
8819           size >= MSB24 + offr && offr != LSB)
8820         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8821       else
8822         aopPut (result, "a", MSB16 + offr);
8823     }
8824
8825   if (size >= MSB24 + offr)
8826     {
8827       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8828         {
8829           l = aopGet (left, MSB24, FALSE, FALSE);
8830           MOVA (l);
8831         }
8832       emitcode ("rlc", "a");
8833       if (sameRegs (AOP (left), AOP (result)) &&
8834           size >= MSB32 + offr && offr != LSB)
8835         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8836       else
8837         aopPut (result, "a", MSB24 + offr);
8838     }
8839
8840   if (size > MSB32 + offr)
8841     {
8842       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8843         {
8844           l = aopGet (left, MSB32, FALSE, FALSE);
8845           MOVA (l);
8846         }
8847       emitcode ("rlc", "a");
8848       aopPut (result, "a", MSB32 + offr);
8849     }
8850   if (offr != LSB)
8851     aopPut (result, zero, LSB);
8852 }
8853
8854 /*-----------------------------------------------------------------*/
8855 /* genlshFour - shift four byte by a known amount != 0             */
8856 /*-----------------------------------------------------------------*/
8857 static void
8858 genlshFour (operand * result, operand * left, int shCount)
8859 {
8860   int size;
8861
8862   D (emitcode (";", "genlshFour"));
8863
8864   size = AOP_SIZE (result);
8865
8866   /* if shifting more that 3 bytes */
8867   if (shCount >= 24)
8868     {
8869       shCount -= 24;
8870       if (shCount)
8871         /* lowest order of left goes to the highest
8872            order of the destination */
8873         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8874       else
8875         movLeft2Result (left, LSB, result, MSB32, 0);
8876       aopPut (result, zero, LSB);
8877       aopPut (result, zero, MSB16);
8878       aopPut (result, zero, MSB24);
8879       return;
8880     }
8881
8882   /* more than two bytes */
8883   else if (shCount >= 16)
8884     {
8885       /* lower order two bytes goes to higher order two bytes */
8886       shCount -= 16;
8887       /* if some more remaining */
8888       if (shCount)
8889         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8890       else
8891         {
8892           movLeft2Result (left, MSB16, result, MSB32, 0);
8893           movLeft2Result (left, LSB, result, MSB24, 0);
8894         }
8895       aopPut (result, zero, MSB16);
8896       aopPut (result, zero, LSB);
8897       return;
8898     }
8899
8900   /* if more than 1 byte */
8901   else if (shCount >= 8)
8902     {
8903       /* lower order three bytes goes to higher order  three bytes */
8904       shCount -= 8;
8905       if (size == 2)
8906         {
8907           if (shCount)
8908             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8909           else
8910             movLeft2Result (left, LSB, result, MSB16, 0);
8911         }
8912       else
8913         {                       /* size = 4 */
8914           if (shCount == 0)
8915             {
8916               movLeft2Result (left, MSB24, result, MSB32, 0);
8917               movLeft2Result (left, MSB16, result, MSB24, 0);
8918               movLeft2Result (left, LSB, result, MSB16, 0);
8919               aopPut (result, zero, LSB);
8920             }
8921           else if (shCount == 1)
8922             shiftLLong (left, result, MSB16);
8923           else
8924             {
8925               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8926               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8927               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8928               aopPut (result, zero, LSB);
8929             }
8930         }
8931     }
8932
8933   /* 1 <= shCount <= 7 */
8934   else if (shCount <= 2)
8935     {
8936       shiftLLong (left, result, LSB);
8937       if (shCount == 2)
8938         shiftLLong (result, result, LSB);
8939     }
8940   /* 3 <= shCount <= 7, optimize */
8941   else
8942     {
8943       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8944       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8945       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8946     }
8947 }
8948
8949 /*-----------------------------------------------------------------*/
8950 /* genLeftShiftLiteral - left shifting by known count              */
8951 /*-----------------------------------------------------------------*/
8952 static void
8953 genLeftShiftLiteral (operand * left,
8954                      operand * right,
8955                      operand * result,
8956                      iCode * ic)
8957 {
8958   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
8959   int size;
8960
8961   D (emitcode (";", "genLeftShiftLiteral"));
8962
8963   freeAsmop (right, NULL, ic, TRUE);
8964
8965   aopOp (left, ic, FALSE);
8966   aopOp (result, ic, FALSE);
8967
8968   size = getSize (operandType (result));
8969
8970 #if VIEW_SIZE
8971   emitcode ("; shift left ", "result %d, left %d", size,
8972             AOP_SIZE (left));
8973 #endif
8974
8975   /* I suppose that the left size >= result size */
8976   if (shCount == 0)
8977     {
8978       while (size--)
8979         {
8980           movLeft2Result (left, size, result, size, 0);
8981         }
8982     }
8983   else if (shCount >= (size * 8))
8984     {
8985       while (size--)
8986         {
8987           aopPut (result, zero, size);
8988         }
8989     }
8990   else
8991     {
8992       switch (size)
8993         {
8994         case 1:
8995           genlshOne (result, left, shCount);
8996           break;
8997
8998         case 2:
8999           genlshTwo (result, left, shCount);
9000           break;
9001
9002         case 4:
9003           genlshFour (result, left, shCount);
9004           break;
9005         default:
9006           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9007                   "*** ack! mystery literal shift!\n");
9008           break;
9009         }
9010     }
9011   freeAsmop (result, NULL, ic, TRUE);
9012   freeAsmop (left, NULL, ic, TRUE);
9013 }
9014
9015 /*-----------------------------------------------------------------*/
9016 /* genLeftShift - generates code for left shifting                 */
9017 /*-----------------------------------------------------------------*/
9018 static void
9019 genLeftShift (iCode * ic)
9020 {
9021   operand *left, *right, *result;
9022   int size, offset;
9023   char *l;
9024   symbol *tlbl, *tlbl1;
9025   bool pushedB;
9026
9027   D (emitcode (";", "genLeftShift"));
9028
9029   right = IC_RIGHT (ic);
9030   left = IC_LEFT (ic);
9031   result = IC_RESULT (ic);
9032
9033   aopOp (right, ic, FALSE);
9034
9035   /* if the shift count is known then do it
9036      as efficiently as possible */
9037   if (AOP_TYPE (right) == AOP_LIT)
9038     {
9039       genLeftShiftLiteral (left, right, result, ic);
9040       return;
9041     }
9042
9043   /* shift count is unknown then we have to form
9044      a loop get the loop count in B : Note: we take
9045      only the lower order byte since shifting
9046      more that 32 bits make no sense anyway, ( the
9047      largest size of an object can be only 32 bits ) */
9048
9049   pushedB = pushB ();
9050   MOVB (aopGet (right, 0, FALSE, FALSE));
9051   emitcode ("inc", "b");
9052   freeAsmop (right, NULL, ic, TRUE);
9053   aopOp (left, ic, FALSE);
9054   aopOp (result, ic, FALSE);
9055
9056   /* now move the left to the result if they are not the same */
9057   if (!sameRegs (AOP (left), AOP (result)) &&
9058       AOP_SIZE (result) > 1)
9059     {
9060
9061       size = AOP_SIZE (result);
9062       offset = 0;
9063       while (size--)
9064         {
9065           l = aopGet (left, offset, FALSE, TRUE);
9066           if (*l == '@' && (IS_AOP_PREG (result)))
9067             {
9068
9069               emitcode ("mov", "a,%s", l);
9070               aopPut (result, "a", offset);
9071             }
9072           else
9073             aopPut (result, l, offset);
9074           offset++;
9075         }
9076     }
9077
9078   tlbl = newiTempLabel (NULL);
9079   size = AOP_SIZE (result);
9080   offset = 0;
9081   tlbl1 = newiTempLabel (NULL);
9082
9083   /* if it is only one byte then */
9084   if (size == 1)
9085     {
9086       symbol *tlbl1 = newiTempLabel (NULL);
9087
9088       l = aopGet (left, 0, FALSE, FALSE);
9089       MOVA (l);
9090       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9091       emitLabel (tlbl);
9092       emitcode ("add", "a,acc");
9093       emitLabel (tlbl1);
9094       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9095       popB (pushedB);
9096       aopPut (result, "a", 0);
9097       goto release;
9098     }
9099
9100   reAdjustPreg (AOP (result));
9101
9102   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9103   emitLabel (tlbl);
9104   l = aopGet (result, offset, FALSE, FALSE);
9105   MOVA (l);
9106   emitcode ("add", "a,acc");
9107   aopPut (result, "a", offset++);
9108   while (--size)
9109     {
9110       l = aopGet (result, offset, FALSE, FALSE);
9111       MOVA (l);
9112       emitcode ("rlc", "a");
9113       aopPut (result, "a", offset++);
9114     }
9115   reAdjustPreg (AOP (result));
9116
9117   emitLabel (tlbl1);
9118   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9119   popB (pushedB);
9120 release:
9121   freeAsmop (result, NULL, ic, TRUE);
9122   freeAsmop (left, NULL, ic, TRUE);
9123 }
9124
9125 /*-----------------------------------------------------------------*/
9126 /* genrshOne - right shift a one byte quantity by known count      */
9127 /*-----------------------------------------------------------------*/
9128 static void
9129 genrshOne (operand * result, operand * left,
9130            int shCount, int sign)
9131 {
9132   D (emitcode (";", "genrshOne"));
9133
9134   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9135 }
9136
9137 /*-----------------------------------------------------------------*/
9138 /* genrshTwo - right shift two bytes by known amount != 0          */
9139 /*-----------------------------------------------------------------*/
9140 static void
9141 genrshTwo (operand * result, operand * left,
9142            int shCount, int sign)
9143 {
9144   D (emitcode (";", "genrshTwo"));
9145
9146   /* if shCount >= 8 */
9147   if (shCount >= 8)
9148     {
9149       shCount -= 8;
9150       if (shCount)
9151         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9152       else
9153         movLeft2Result (left, MSB16, result, LSB, sign);
9154       addSign (result, MSB16, sign);
9155     }
9156
9157   /*  1 <= shCount <= 7 */
9158   else
9159     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9160 }
9161
9162 /*-----------------------------------------------------------------*/
9163 /* shiftRLong - shift right one long from left to result           */
9164 /* offl = LSB or MSB16                                             */
9165 /*-----------------------------------------------------------------*/
9166 static void
9167 shiftRLong (operand * left, int offl,
9168             operand * result, int sign)
9169 {
9170   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9171
9172   if (overlapping && offl>1)
9173     {
9174       // we are in big trouble, but this shouldn't happen
9175       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9176     }
9177
9178   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9179
9180   if (offl==MSB16)
9181     {
9182       // shift is > 8
9183       if (sign)
9184         {
9185           emitcode ("rlc", "a");
9186           emitcode ("subb", "a,acc");
9187           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9188             {
9189               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9190             }
9191           else
9192             {
9193               aopPut (result, "a", MSB32);
9194               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9195             }
9196         }
9197       else
9198         {
9199           if (aopPutUsesAcc (result, zero, MSB32))
9200             {
9201               emitcode("xch", "a,b");
9202               aopPut (result, zero, MSB32);
9203               emitcode("xch", "a,b");
9204             }
9205           else
9206             {
9207               aopPut (result, zero, MSB32);
9208             }
9209         }
9210     }
9211
9212   if (!sign)
9213     {
9214       emitcode ("clr", "c");
9215     }
9216   else
9217     {
9218       emitcode ("mov", "c,acc.7");
9219     }
9220
9221   emitcode ("rrc", "a");
9222
9223   if (overlapping && offl==MSB16 &&
9224       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9225     {
9226       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9227     }
9228   else
9229     {
9230       aopPut (result, "a", MSB32 - offl);
9231       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9232     }
9233
9234   emitcode ("rrc", "a");
9235   if (overlapping && offl==MSB16 &&
9236       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9237     {
9238       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9239     }
9240   else
9241     {
9242       aopPut (result, "a", MSB24 - offl);
9243       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9244     }
9245
9246   emitcode ("rrc", "a");
9247   if (offl != LSB)
9248     {
9249       aopPut (result, "a", MSB16 - offl);
9250     }
9251   else
9252     {
9253       if (overlapping &&
9254           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9255         {
9256           xch_a_aopGet (left, LSB, FALSE, FALSE);
9257         }
9258       else
9259         {
9260           aopPut (result, "a", MSB16 - offl);
9261           MOVA (aopGet (left, LSB, FALSE, FALSE));
9262         }
9263       emitcode ("rrc", "a");
9264       aopPut (result, "a", LSB);
9265     }
9266 }
9267
9268 /*-----------------------------------------------------------------*/
9269 /* genrshFour - shift four byte by a known amount != 0             */
9270 /*-----------------------------------------------------------------*/
9271 static void
9272 genrshFour (operand * result, operand * left,
9273             int shCount, int sign)
9274 {
9275   D (emitcode (";", "genrshFour"));
9276
9277   /* if shifting more that 3 bytes */
9278   if (shCount >= 24)
9279     {
9280       shCount -= 24;
9281       if (shCount)
9282         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9283       else
9284         movLeft2Result (left, MSB32, result, LSB, sign);
9285       addSign (result, MSB16, sign);
9286     }
9287   else if (shCount >= 16)
9288     {
9289       shCount -= 16;
9290       if (shCount)
9291         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9292       else
9293         {
9294           movLeft2Result (left, MSB24, result, LSB, 0);
9295           movLeft2Result (left, MSB32, result, MSB16, sign);
9296         }
9297       addSign (result, MSB24, sign);
9298     }
9299   else if (shCount >= 8)
9300     {
9301       shCount -= 8;
9302       if (shCount == 1)
9303         {
9304           shiftRLong (left, MSB16, result, sign);
9305         }
9306       else if (shCount == 0)
9307         {
9308           movLeft2Result (left, MSB16, result, LSB, 0);
9309           movLeft2Result (left, MSB24, result, MSB16, 0);
9310           movLeft2Result (left, MSB32, result, MSB24, sign);
9311           addSign (result, MSB32, sign);
9312         }
9313       else
9314         {
9315           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9316           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9317           /* the last shift is signed */
9318           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9319           addSign (result, MSB32, sign);
9320         }
9321     }
9322   else
9323     {
9324       /* 1 <= shCount <= 7 */
9325       if (shCount <= 2)
9326         {
9327           shiftRLong (left, LSB, result, sign);
9328           if (shCount == 2)
9329             shiftRLong (result, LSB, result, sign);
9330         }
9331       else
9332         {
9333           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9334           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9335           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9336         }
9337     }
9338 }
9339
9340 /*-----------------------------------------------------------------*/
9341 /* genRightShiftLiteral - right shifting by known count            */
9342 /*-----------------------------------------------------------------*/
9343 static void
9344 genRightShiftLiteral (operand * left,
9345                       operand * right,
9346                       operand * result,
9347                       iCode * ic,
9348                       int sign)
9349 {
9350   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9351   int size;
9352
9353   D (emitcode (";", "genRightShiftLiteral"));
9354
9355   freeAsmop (right, NULL, ic, TRUE);
9356
9357   aopOp (left, ic, FALSE);
9358   aopOp (result, ic, FALSE);
9359
9360 #if VIEW_SIZE
9361   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9362             AOP_SIZE (left));
9363 #endif
9364
9365   size = getDataSize (left);
9366   /* test the LEFT size !!! */
9367
9368   /* I suppose that the left size >= result size */
9369   if (shCount == 0)
9370     {
9371       size = getDataSize (result);
9372       while (size--)
9373         movLeft2Result (left, size, result, size, 0);
9374     }
9375
9376   else if (shCount >= (size * 8))
9377     {
9378       if (sign)
9379         {
9380           /* get sign in acc.7 */
9381           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9382         }
9383       addSign (result, LSB, sign);
9384     }
9385   else
9386     {
9387       switch (size)
9388         {
9389         case 1:
9390           genrshOne (result, left, shCount, sign);
9391           break;
9392
9393         case 2:
9394           genrshTwo (result, left, shCount, sign);
9395           break;
9396
9397         case 4:
9398           genrshFour (result, left, shCount, sign);
9399           break;
9400         default:
9401           break;
9402         }
9403     }
9404   freeAsmop (result, NULL, ic, TRUE);
9405   freeAsmop (left, NULL, ic, TRUE);
9406 }
9407
9408 /*-----------------------------------------------------------------*/
9409 /* genSignedRightShift - right shift of signed number              */
9410 /*-----------------------------------------------------------------*/
9411 static void
9412 genSignedRightShift (iCode * ic)
9413 {
9414   operand *right, *left, *result;
9415   int size, offset;
9416   char *l;
9417   symbol *tlbl, *tlbl1;
9418   bool pushedB;
9419
9420   D (emitcode (";", "genSignedRightShift"));
9421
9422   /* we do it the hard way put the shift count in b
9423      and loop thru preserving the sign */
9424
9425   right = IC_RIGHT (ic);
9426   left = IC_LEFT (ic);
9427   result = IC_RESULT (ic);
9428
9429   aopOp (right, ic, FALSE);
9430
9431
9432   if (AOP_TYPE (right) == AOP_LIT)
9433     {
9434       genRightShiftLiteral (left, right, result, ic, 1);
9435       return;
9436     }
9437   /* shift count is unknown then we have to form
9438      a loop get the loop count in B : Note: we take
9439      only the lower order byte since shifting
9440      more that 32 bits make no sense anyway, ( the
9441      largest size of an object can be only 32 bits ) */
9442
9443   pushedB = pushB ();
9444   MOVB (aopGet (right, 0, FALSE, FALSE));
9445   emitcode ("inc", "b");
9446   freeAsmop (right, NULL, ic, TRUE);
9447   aopOp (left, ic, FALSE);
9448   aopOp (result, ic, FALSE);
9449
9450   /* now move the left to the result if they are not the
9451      same */
9452   if (!sameRegs (AOP (left), AOP (result)) &&
9453       AOP_SIZE (result) > 1)
9454     {
9455
9456       size = AOP_SIZE (result);
9457       offset = 0;
9458       while (size--)
9459         {
9460           l = aopGet (left, offset, FALSE, TRUE);
9461           if (*l == '@' && IS_AOP_PREG (result))
9462             {
9463
9464               emitcode ("mov", "a,%s", l);
9465               aopPut (result, "a", offset);
9466             }
9467           else
9468             aopPut (result, l, offset);
9469           offset++;
9470         }
9471     }
9472
9473   /* mov the highest order bit to OVR */
9474   tlbl = newiTempLabel (NULL);
9475   tlbl1 = newiTempLabel (NULL);
9476
9477   size = AOP_SIZE (result);
9478   offset = size - 1;
9479   MOVA (aopGet (left, offset, FALSE, FALSE));
9480   emitcode ("rlc", "a");
9481   emitcode ("mov", "ov,c");
9482   /* if it is only one byte then */
9483   if (size == 1)
9484     {
9485       l = aopGet (left, 0, FALSE, FALSE);
9486       MOVA (l);
9487       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9488       emitLabel (tlbl);
9489       emitcode ("mov", "c,ov");
9490       emitcode ("rrc", "a");
9491       emitLabel (tlbl1);
9492       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9493       popB (pushedB);
9494       aopPut (result, "a", 0);
9495       goto release;
9496     }
9497
9498   reAdjustPreg (AOP (result));
9499   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9500   emitLabel (tlbl);
9501   emitcode ("mov", "c,ov");
9502   while (size--)
9503     {
9504       l = aopGet (result, offset, FALSE, FALSE);
9505       MOVA (l);
9506       emitcode ("rrc", "a");
9507       aopPut (result, "a", offset--);
9508     }
9509   reAdjustPreg (AOP (result));
9510   emitLabel (tlbl1);
9511   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9512   popB (pushedB);
9513
9514 release:
9515   freeAsmop (result, NULL, ic, TRUE);
9516   freeAsmop (left, NULL, ic, TRUE);
9517 }
9518
9519 /*-----------------------------------------------------------------*/
9520 /* genRightShift - generate code for right shifting                */
9521 /*-----------------------------------------------------------------*/
9522 static void
9523 genRightShift (iCode * ic)
9524 {
9525   operand *right, *left, *result;
9526   sym_link *letype;
9527   int size, offset;
9528   char *l;
9529   symbol *tlbl, *tlbl1;
9530   bool pushedB;
9531
9532   D (emitcode (";", "genRightShift"));
9533
9534   /* if signed then we do it the hard way preserve the
9535      sign bit moving it inwards */
9536   letype = getSpec (operandType (IC_LEFT (ic)));
9537
9538   if (!SPEC_USIGN (letype))
9539     {
9540       genSignedRightShift (ic);
9541       return;
9542     }
9543
9544   /* signed & unsigned types are treated the same : i.e. the
9545      signed is NOT propagated inwards : quoting from the
9546      ANSI - standard : "for E1 >> E2, is equivalent to division
9547      by 2**E2 if unsigned or if it has a non-negative value,
9548      otherwise the result is implementation defined ", MY definition
9549      is that the sign does not get propagated */
9550
9551   right = IC_RIGHT (ic);
9552   left = IC_LEFT (ic);
9553   result = IC_RESULT (ic);
9554
9555   aopOp (right, ic, FALSE);
9556
9557   /* if the shift count is known then do it
9558      as efficiently as possible */
9559   if (AOP_TYPE (right) == AOP_LIT)
9560     {
9561       genRightShiftLiteral (left, right, result, ic, 0);
9562       return;
9563     }
9564
9565   /* shift count is unknown then we have to form
9566      a loop get the loop count in B : Note: we take
9567      only the lower order byte since shifting
9568      more that 32 bits make no sense anyway, ( the
9569      largest size of an object can be only 32 bits ) */
9570
9571   pushedB = pushB ();
9572   MOVB (aopGet (right, 0, FALSE, FALSE));
9573   emitcode ("inc", "b");
9574   freeAsmop (right, NULL, ic, TRUE);
9575   aopOp (left, ic, FALSE);
9576   aopOp (result, ic, FALSE);
9577
9578   /* now move the left to the result if they are not the
9579      same */
9580   if (!sameRegs (AOP (left), AOP (result)) &&
9581       AOP_SIZE (result) > 1)
9582     {
9583       size = AOP_SIZE (result);
9584       offset = 0;
9585       while (size--)
9586         {
9587           l = aopGet (left, offset, FALSE, TRUE);
9588           if (*l == '@' && IS_AOP_PREG (result))
9589             {
9590
9591               emitcode ("mov", "a,%s", l);
9592               aopPut (result, "a", offset);
9593             }
9594           else
9595             aopPut (result, l, offset);
9596           offset++;
9597         }
9598     }
9599
9600   tlbl = newiTempLabel (NULL);
9601   tlbl1 = newiTempLabel (NULL);
9602   size = AOP_SIZE (result);
9603   offset = size - 1;
9604
9605   /* if it is only one byte then */
9606   if (size == 1)
9607     {
9608       l = aopGet (left, 0, FALSE, FALSE);
9609       MOVA (l);
9610       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9611       emitLabel (tlbl);
9612       CLRC;
9613       emitcode ("rrc", "a");
9614       emitLabel (tlbl1);
9615       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9616       popB (pushedB);
9617       aopPut (result, "a", 0);
9618       goto release;
9619     }
9620
9621   reAdjustPreg (AOP (result));
9622   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9623   emitLabel (tlbl);
9624   CLRC;
9625   while (size--)
9626     {
9627       l = aopGet (result, offset, FALSE, FALSE);
9628       MOVA (l);
9629       emitcode ("rrc", "a");
9630       aopPut (result, "a", offset--);
9631     }
9632   reAdjustPreg (AOP (result));
9633
9634   emitLabel (tlbl1);
9635   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9636   popB (pushedB);
9637
9638 release:
9639   freeAsmop (result, NULL, ic, TRUE);
9640   freeAsmop (left, NULL, ic, TRUE);
9641 }
9642
9643 /*-----------------------------------------------------------------*/
9644 /* emitPtrByteGet - emits code to get a byte into A through a      */
9645 /*                  pointer register (R0, R1, or DPTR). The        */
9646 /*                  original value of A can be preserved in B.     */
9647 /*-----------------------------------------------------------------*/
9648 static void
9649 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9650 {
9651   switch (p_type)
9652     {
9653     case IPOINTER:
9654     case POINTER:
9655       if (preserveAinB)
9656         emitcode ("mov", "b,a");
9657       emitcode ("mov", "a,@%s", rname);
9658       break;
9659
9660     case PPOINTER:
9661       if (preserveAinB)
9662         emitcode ("mov", "b,a");
9663       emitcode ("movx", "a,@%s", rname);
9664       break;
9665
9666     case FPOINTER:
9667       if (preserveAinB)
9668         emitcode ("mov", "b,a");
9669       emitcode ("movx", "a,@dptr");
9670       break;
9671
9672     case CPOINTER:
9673       if (preserveAinB)
9674         emitcode ("mov", "b,a");
9675       emitcode ("clr", "a");
9676       emitcode ("movc", "a,@a+dptr");
9677       break;
9678
9679     case GPOINTER:
9680       if (preserveAinB)
9681         {
9682           emitcode ("push", "b");
9683           emitcode ("push", "acc");
9684         }
9685       emitcode ("lcall", "__gptrget");
9686       if (preserveAinB)
9687         emitcode ("pop", "b");
9688       break;
9689     }
9690 }
9691
9692 /*-----------------------------------------------------------------*/
9693 /* emitPtrByteSet - emits code to set a byte from src through a    */
9694 /*                  pointer register (R0, R1, or DPTR).            */
9695 /*-----------------------------------------------------------------*/
9696 static void
9697 emitPtrByteSet (char *rname, int p_type, char *src)
9698 {
9699   switch (p_type)
9700     {
9701     case IPOINTER:
9702     case POINTER:
9703       if (*src=='@')
9704         {
9705           MOVA (src);
9706           emitcode ("mov", "@%s,a", rname);
9707         }
9708       else
9709         emitcode ("mov", "@%s,%s", rname, src);
9710       break;
9711
9712     case PPOINTER:
9713       MOVA (src);
9714       emitcode ("movx", "@%s,a", rname);
9715       break;
9716
9717     case FPOINTER:
9718       MOVA (src);
9719       emitcode ("movx", "@dptr,a");
9720       break;
9721
9722     case GPOINTER:
9723       MOVA (src);
9724       emitcode ("lcall", "__gptrput");
9725       break;
9726     }
9727 }
9728
9729 /*-----------------------------------------------------------------*/
9730 /* genUnpackBits - generates code for unpacking bits               */
9731 /*-----------------------------------------------------------------*/
9732 static void
9733 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9734 {
9735   int offset = 0;       /* result byte offset */
9736   int rsize;            /* result size */
9737   int rlen = 0;         /* remaining bitfield length */
9738   sym_link *etype;      /* bitfield type information */
9739   int blen;             /* bitfield length */
9740   int bstr;             /* bitfield starting bit within byte */
9741   char buffer[10];
9742
9743   D(emitcode (";", "genUnpackBits"));
9744
9745   etype = getSpec (operandType (result));
9746   rsize = getSize (operandType (result));
9747   blen = SPEC_BLEN (etype);
9748   bstr = SPEC_BSTR (etype);
9749
9750   if (ifx && blen <= 8)
9751     {
9752       emitPtrByteGet (rname, ptype, FALSE);
9753       if (blen == 1)
9754         {
9755           SNPRINTF (buffer, sizeof(buffer),
9756                     "acc.%d", bstr);
9757           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9758         }
9759       else
9760         {
9761           if (blen < 8)
9762             emitcode ("anl", "a,#0x%02x",
9763                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9764           genIfxJump (ifx, "a", NULL, NULL, NULL);
9765         }
9766       return;
9767     }
9768   wassert (!ifx);
9769
9770   /* If the bitfield length is less than a byte */
9771   if (blen < 8)
9772     {
9773       emitPtrByteGet (rname, ptype, FALSE);
9774       AccRol (8 - bstr);
9775       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9776       if (!SPEC_USIGN (etype))
9777         {
9778           /* signed bitfield */
9779           symbol *tlbl = newiTempLabel (NULL);
9780
9781           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9782           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9783           emitLabel (tlbl);
9784         }
9785       aopPut (result, "a", offset++);
9786       goto finish;
9787     }
9788
9789   /* Bit field did not fit in a byte. Copy all
9790      but the partial byte at the end.  */
9791   for (rlen=blen;rlen>=8;rlen-=8)
9792     {
9793       emitPtrByteGet (rname, ptype, FALSE);
9794       aopPut (result, "a", offset++);
9795       if (rlen>8)
9796         emitcode ("inc", "%s", rname);
9797     }
9798
9799   /* Handle the partial byte at the end */
9800   if (rlen)
9801     {
9802       emitPtrByteGet (rname, ptype, FALSE);
9803       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9804       if (!SPEC_USIGN (etype))
9805         {
9806           /* signed bitfield */
9807           symbol *tlbl = newiTempLabel (NULL);
9808
9809           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9810           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9811           emitLabel (tlbl);
9812         }
9813       aopPut (result, "a", offset++);
9814     }
9815
9816 finish:
9817   if (offset < rsize)
9818     {
9819       char *source;
9820
9821       if (SPEC_USIGN (etype))
9822         source = zero;
9823       else
9824         {
9825           /* signed bitfield: sign extension with 0x00 or 0xff */
9826           emitcode ("rlc", "a");
9827           emitcode ("subb", "a,acc");
9828
9829           source = "a";
9830         }
9831       rsize -= offset;
9832       while (rsize--)
9833         aopPut (result, source, offset++);
9834     }
9835 }
9836
9837
9838 /*-----------------------------------------------------------------*/
9839 /* genDataPointerGet - generates code when ptr offset is known     */
9840 /*-----------------------------------------------------------------*/
9841 static void
9842 genDataPointerGet (operand * left,
9843                    operand * result,
9844                    iCode * ic)
9845 {
9846   char *l;
9847   char buffer[256];
9848   int size, offset = 0;
9849
9850   D (emitcode (";", "genDataPointerGet"));
9851
9852   aopOp (result, ic, TRUE);
9853
9854   /* get the string representation of the name */
9855   l = aopGet (left, 0, FALSE, TRUE);
9856   l++; // remove #
9857   size = AOP_SIZE (result);
9858   while (size--)
9859     {
9860       if (offset)
9861         {
9862           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9863         }
9864       else
9865         {
9866           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9867         }
9868       aopPut (result, buffer, offset++);
9869     }
9870
9871   freeAsmop (result, NULL, ic, TRUE);
9872   freeAsmop (left, NULL, ic, TRUE);
9873 }
9874
9875 /*-----------------------------------------------------------------*/
9876 /* genNearPointerGet - emitcode for near pointer fetch             */
9877 /*-----------------------------------------------------------------*/
9878 static void
9879 genNearPointerGet (operand * left,
9880                    operand * result,
9881                    iCode * ic,
9882                    iCode * pi,
9883                    iCode * ifx)
9884 {
9885   asmop *aop = NULL;
9886   regs *preg = NULL;
9887   char *rname;
9888   sym_link *rtype, *retype;
9889   sym_link *ltype = operandType (left);
9890   char buffer[80];
9891
9892   D (emitcode (";", "genNearPointerGet"));
9893
9894   rtype = operandType (result);
9895   retype = getSpec (rtype);
9896
9897   aopOp (left, ic, FALSE);
9898
9899   /* if left is rematerialisable and
9900      result is not bitfield variable type and
9901      the left is pointer to data space i.e
9902      lower 128 bytes of space */
9903   if (AOP_TYPE (left) == AOP_IMMD &&
9904       !IS_BITFIELD (retype) &&
9905       DCL_TYPE (ltype) == POINTER)
9906     {
9907       genDataPointerGet (left, result, ic);
9908       return;
9909     }
9910
9911  /* if the value is already in a pointer register
9912      then don't need anything more */
9913   if (!AOP_INPREG (AOP (left)))
9914     {
9915       if (IS_AOP_PREG (left))
9916         {
9917           // Aha, it is a pointer, just in disguise.
9918           rname = aopGet (left, 0, FALSE, FALSE);
9919           if (*rname != '@')
9920             {
9921               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9922                       __FILE__, __LINE__);
9923             }
9924           else
9925             {
9926               // Expected case.
9927               emitcode ("mov", "a%s,%s", rname + 1, rname);
9928               rname++;  // skip the '@'.
9929             }
9930         }
9931       else
9932         {
9933           /* otherwise get a free pointer register */
9934           aop = newAsmop (0);
9935           preg = getFreePtr (ic, &aop, FALSE);
9936           emitcode ("mov", "%s,%s",
9937                     preg->name,
9938                     aopGet (left, 0, FALSE, TRUE));
9939           rname = preg->name;
9940         }
9941     }
9942   else
9943     rname = aopGet (left, 0, FALSE, FALSE);
9944
9945   //aopOp (result, ic, FALSE);
9946   aopOp (result, ic, result?TRUE:FALSE);
9947
9948   /* if bitfield then unpack the bits */
9949   if (IS_BITFIELD (retype))
9950     genUnpackBits (result, rname, POINTER, ifx);
9951   else
9952     {
9953       /* we have can just get the values */
9954       int size = AOP_SIZE (result);
9955       int offset = 0;
9956
9957       while (size--)
9958         {
9959           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9960             {
9961
9962               emitcode ("mov", "a,@%s", rname);
9963               if (!ifx)
9964                 aopPut (result, "a", offset);
9965             }
9966           else
9967             {
9968               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9969               aopPut (result, buffer, offset);
9970             }
9971           offset++;
9972           if (size || pi)
9973             emitcode ("inc", "%s", rname);
9974         }
9975     }
9976
9977   /* now some housekeeping stuff */
9978   if (aop)       /* we had to allocate for this iCode */
9979     {
9980       if (pi) { /* post increment present */
9981         aopPut (left, rname, 0);
9982       }
9983       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9984     }
9985   else
9986     {
9987       /* we did not allocate which means left
9988          already in a pointer register, then
9989          if size > 0 && this could be used again
9990          we have to point it back to where it
9991          belongs */
9992       if ((AOP_SIZE (result) > 1 &&
9993            !OP_SYMBOL (left)->remat &&
9994            (OP_SYMBOL (left)->liveTo > ic->seq ||
9995             ic->depth)) &&
9996           !pi)
9997         {
9998           int size = AOP_SIZE (result) - 1;
9999           while (size--)
10000             emitcode ("dec", "%s", rname);
10001         }
10002     }
10003
10004   if (ifx && !ifx->generated)
10005     {
10006       genIfxJump (ifx, "a", left, NULL, result);
10007     }
10008
10009   /* done */
10010   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10011   freeAsmop (left, NULL, ic, TRUE);
10012   if (pi) pi->generated = 1;
10013 }
10014
10015 /*-----------------------------------------------------------------*/
10016 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10017 /*-----------------------------------------------------------------*/
10018 static void
10019 genPagedPointerGet (operand * left,
10020                     operand * result,
10021                     iCode * ic,
10022                     iCode *pi,
10023                     iCode *ifx)
10024 {
10025   asmop *aop = NULL;
10026   regs *preg = NULL;
10027   char *rname;
10028   sym_link *rtype, *retype;
10029
10030   D (emitcode (";", "genPagedPointerGet"));
10031
10032   rtype = operandType (result);
10033   retype = getSpec (rtype);
10034
10035   aopOp (left, ic, FALSE);
10036
10037   /* if the value is already in a pointer register
10038      then don't need anything more */
10039   if (!AOP_INPREG (AOP (left)))
10040     {
10041       /* otherwise get a free pointer register */
10042       aop = newAsmop (0);
10043       preg = getFreePtr (ic, &aop, FALSE);
10044       emitcode ("mov", "%s,%s",
10045                 preg->name,
10046                 aopGet (left, 0, FALSE, TRUE));
10047       rname = preg->name;
10048     }
10049   else
10050     rname = aopGet (left, 0, FALSE, FALSE);
10051
10052   aopOp (result, ic, FALSE);
10053
10054   /* if bitfield then unpack the bits */
10055   if (IS_BITFIELD (retype))
10056     genUnpackBits (result, rname, PPOINTER, ifx);
10057   else
10058     {
10059       /* we have can just get the values */
10060       int size = AOP_SIZE (result);
10061       int offset = 0;
10062
10063       while (size--)
10064         {
10065
10066           emitcode ("movx", "a,@%s", rname);
10067           if (!ifx)
10068             aopPut (result, "a", offset);
10069
10070           offset++;
10071
10072           if (size || pi)
10073             emitcode ("inc", "%s", rname);
10074         }
10075     }
10076
10077   /* now some housekeeping stuff */
10078   if (aop) /* we had to allocate for this iCode */
10079     {
10080       if (pi)
10081         aopPut (left, rname, 0);
10082       freeAsmop (NULL, aop, ic, TRUE);
10083     }
10084   else
10085     {
10086       /* we did not allocate which means left
10087          already in a pointer register, then
10088          if size > 0 && this could be used again
10089          we have to point it back to where it
10090          belongs */
10091       if ((AOP_SIZE (result) > 1 &&
10092            !OP_SYMBOL (left)->remat &&
10093            (OP_SYMBOL (left)->liveTo > ic->seq ||
10094             ic->depth)) &&
10095           !pi)
10096         {
10097           int size = AOP_SIZE (result) - 1;
10098           while (size--)
10099             emitcode ("dec", "%s", rname);
10100         }
10101     }
10102
10103   if (ifx && !ifx->generated)
10104     {
10105       genIfxJump (ifx, "a", left, NULL, result);
10106     }
10107
10108   /* done */
10109   freeAsmop (result, NULL, ic, TRUE);
10110   freeAsmop (left, NULL, ic, TRUE);
10111   if (pi) pi->generated = 1;
10112 }
10113
10114 /*--------------------------------------------------------------------*/
10115 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10116 /*--------------------------------------------------------------------*/
10117 static void
10118 loadDptrFromOperand (operand *op, bool loadBToo)
10119 {
10120   if (AOP_TYPE (op) != AOP_STR)
10121     {
10122       /* if this is rematerializable */
10123       if (AOP_TYPE (op) == AOP_IMMD)
10124         {
10125           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10126           if (loadBToo)
10127             {
10128               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10129                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10130               else
10131                 {
10132                   wassertl(FALSE, "need pointerCode");
10133                   emitcode (";", "mov b,???");
10134                   /* genPointerGet and genPointerSet originally did different
10135                   ** things for this case. Both seem wrong.
10136                   ** from genPointerGet:
10137                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10138                   ** from genPointerSet:
10139                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10140                   */
10141                 }
10142             }
10143         }
10144       else if (AOP_TYPE (op) == AOP_DPTR)
10145         {
10146           if (loadBToo)
10147             {
10148               MOVA (aopGet (op, 0, FALSE, FALSE));
10149               emitcode ("push", "acc");
10150               MOVA (aopGet (op, 1, FALSE, FALSE));
10151               emitcode ("push", "acc");
10152               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10153               emitcode ("pop", "dph");
10154               emitcode ("pop", "dpl");
10155             }
10156           else
10157             {
10158               MOVA (aopGet (op, 0, FALSE, FALSE));
10159               emitcode ("push", "acc");
10160               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10161               emitcode ("pop", "dpl");
10162             }
10163         }
10164       else
10165         {                       /* we need to get it byte by byte */
10166           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10167           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10168           if (loadBToo)
10169             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10170         }
10171     }
10172 }
10173
10174 /*-----------------------------------------------------------------*/
10175 /* genFarPointerGet - get value from far space                     */
10176 /*-----------------------------------------------------------------*/
10177 static void
10178 genFarPointerGet (operand * left,
10179                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10180 {
10181   int size, offset;
10182   sym_link *retype = getSpec (operandType (result));
10183
10184   D (emitcode (";", "genFarPointerGet"));
10185
10186   aopOp (left, ic, FALSE);
10187   loadDptrFromOperand (left, FALSE);
10188
10189   /* so dptr now contains the address */
10190   aopOp (result, ic, FALSE);
10191
10192   /* if bit then unpack */
10193   if (IS_BITFIELD (retype))
10194     genUnpackBits (result, "dptr", FPOINTER, ifx);
10195   else
10196     {
10197       size = AOP_SIZE (result);
10198       offset = 0;
10199
10200       while (size--)
10201         {
10202           emitcode ("movx", "a,@dptr");
10203           if (!ifx)
10204             aopPut (result, "a", offset++);
10205           if (size || pi)
10206             emitcode ("inc", "dptr");
10207         }
10208     }
10209
10210   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10211     {
10212       aopPut (left, "dpl", 0);
10213       aopPut (left, "dph", 1);
10214       pi->generated = 1;
10215     }
10216
10217   if (ifx && !ifx->generated)
10218     {
10219       genIfxJump (ifx, "a", left, NULL, result);
10220     }
10221
10222   freeAsmop (result, NULL, ic, TRUE);
10223   freeAsmop (left, NULL, ic, TRUE);
10224 }
10225
10226 /*-----------------------------------------------------------------*/
10227 /* genCodePointerGet - get value from code space                   */
10228 /*-----------------------------------------------------------------*/
10229 static void
10230 genCodePointerGet (operand * left,
10231                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10232 {
10233   int size, offset;
10234   sym_link *retype = getSpec (operandType (result));
10235
10236   D (emitcode (";", "genCodePointerGet"));
10237
10238   aopOp (left, ic, FALSE);
10239   loadDptrFromOperand (left, FALSE);
10240
10241   /* so dptr now contains the address */
10242   aopOp (result, ic, FALSE);
10243
10244   /* if bit then unpack */
10245   if (IS_BITFIELD (retype))
10246     genUnpackBits (result, "dptr", CPOINTER, ifx);
10247   else
10248     {
10249       size = AOP_SIZE (result);
10250       offset = 0;
10251
10252       while (size--)
10253         {
10254           emitcode ("clr", "a");
10255           emitcode ("movc", "a,@a+dptr");
10256           if (!ifx)
10257             aopPut (result, "a", offset++);
10258           if (size || pi)
10259             emitcode ("inc", "dptr");
10260         }
10261     }
10262
10263   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10264     {
10265       aopPut (left, "dpl", 0);
10266       aopPut (left, "dph", 1);
10267       pi->generated = 1;
10268     }
10269
10270   if (ifx && !ifx->generated)
10271     {
10272       genIfxJump (ifx, "a", left, NULL, result);
10273     }
10274
10275   freeAsmop (result, NULL, ic, TRUE);
10276   freeAsmop (left, NULL, ic, TRUE);
10277 }
10278
10279 /*-----------------------------------------------------------------*/
10280 /* genGenPointerGet - get value from generic pointer space         */
10281 /*-----------------------------------------------------------------*/
10282 static void
10283 genGenPointerGet (operand * left,
10284                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10285 {
10286   int size, offset;
10287   sym_link *retype = getSpec (operandType (result));
10288
10289   D (emitcode (";", "genGenPointerGet"));
10290
10291   aopOp (left, ic, FALSE);
10292   loadDptrFromOperand (left, TRUE);
10293
10294   /* so dptr now contains the address */
10295   aopOp (result, ic, FALSE);
10296
10297   /* if bit then unpack */
10298   if (IS_BITFIELD (retype))
10299     {
10300       genUnpackBits (result, "dptr", GPOINTER, ifx);
10301     }
10302   else
10303     {
10304       size = AOP_SIZE (result);
10305       offset = 0;
10306
10307       while (size--)
10308         {
10309           emitcode ("lcall", "__gptrget");
10310           if (!ifx)
10311             aopPut (result, "a", offset++);
10312           if (size || pi)
10313             emitcode ("inc", "dptr");
10314         }
10315     }
10316
10317   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10318     {
10319       aopPut (left, "dpl", 0);
10320       aopPut (left, "dph", 1);
10321       pi->generated = 1;
10322     }
10323
10324   if (ifx && !ifx->generated)
10325     {
10326       genIfxJump (ifx, "a", left, NULL, result);
10327     }
10328
10329   freeAsmop (result, NULL, ic, TRUE);
10330   freeAsmop (left, NULL, ic, TRUE);
10331 }
10332
10333 /*-----------------------------------------------------------------*/
10334 /* genPointerGet - generate code for pointer get                   */
10335 /*-----------------------------------------------------------------*/
10336 static void
10337 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10338 {
10339   operand *left, *result;
10340   sym_link *type, *etype;
10341   int p_type;
10342
10343   D (emitcode (";", "genPointerGet"));
10344
10345   left = IC_LEFT (ic);
10346   result = IC_RESULT (ic);
10347
10348   if (getSize (operandType (result))>1)
10349     ifx = NULL;
10350
10351   /* depending on the type of pointer we need to
10352      move it to the correct pointer register */
10353   type = operandType (left);
10354   etype = getSpec (type);
10355   /* if left is of type of pointer then it is simple */
10356   if (IS_PTR (type) && !IS_FUNC (type->next))
10357     p_type = DCL_TYPE (type);
10358   else
10359     {
10360       /* we have to go by the storage class */
10361       p_type = PTR_TYPE (SPEC_OCLS (etype));
10362     }
10363
10364   /* special case when cast remat */
10365   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10366       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10367     {
10368       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10369       type = operandType (left);
10370       p_type = DCL_TYPE (type);
10371     }
10372   /* now that we have the pointer type we assign
10373      the pointer values */
10374   switch (p_type)
10375     {
10376
10377     case POINTER:
10378     case IPOINTER:
10379       genNearPointerGet (left, result, ic, pi, ifx);
10380       break;
10381
10382     case PPOINTER:
10383       genPagedPointerGet (left, result, ic, pi, ifx);
10384       break;
10385
10386     case FPOINTER:
10387       genFarPointerGet (left, result, ic, pi, ifx);
10388       break;
10389
10390     case CPOINTER:
10391       genCodePointerGet (left, result, ic, pi, ifx);
10392       break;
10393
10394     case GPOINTER:
10395       genGenPointerGet (left, result, ic, pi, ifx);
10396       break;
10397     }
10398 }
10399
10400
10401 /*-----------------------------------------------------------------*/
10402 /* genPackBits - generates code for packed bit storage             */
10403 /*-----------------------------------------------------------------*/
10404 static void
10405 genPackBits (sym_link * etype,
10406              operand * right,
10407              char *rname, int p_type)
10408 {
10409   int offset = 0;       /* source byte offset */
10410   int rlen = 0;         /* remaining bitfield length */
10411   int blen;             /* bitfield length */
10412   int bstr;             /* bitfield starting bit within byte */
10413   int litval;           /* source literal value (if AOP_LIT) */
10414   unsigned char mask;   /* bitmask within current byte */
10415
10416   D(emitcode (";", "genPackBits"));
10417
10418   blen = SPEC_BLEN (etype);
10419   bstr = SPEC_BSTR (etype);
10420
10421   /* If the bitfield length is less than a byte */
10422   if (blen < 8)
10423     {
10424       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10425               (unsigned char) (0xFF >> (8 - bstr)));
10426
10427       if (AOP_TYPE (right) == AOP_LIT)
10428         {
10429           /* Case with a bitfield length <8 and literal source
10430           */
10431           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10432           litval <<= bstr;
10433           litval &= (~mask) & 0xff;
10434           emitPtrByteGet (rname, p_type, FALSE);
10435           if ((mask|litval)!=0xff)
10436             emitcode ("anl","a,#0x%02x", mask);
10437           if (litval)
10438             emitcode ("orl","a,#0x%02x", litval);
10439         }
10440       else
10441         {
10442           if ((blen==1) && (p_type!=GPOINTER))
10443             {
10444               /* Case with a bitfield length == 1 and no generic pointer
10445               */
10446               if (AOP_TYPE (right) == AOP_CRY)
10447                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10448               else
10449                 {
10450                   MOVA (aopGet (right, 0, FALSE, FALSE));
10451                   emitcode ("rrc","a");
10452                 }
10453               emitPtrByteGet (rname, p_type, FALSE);
10454               emitcode ("mov","acc.%d,c",bstr);
10455             }
10456           else
10457             {
10458               bool pushedB;
10459               /* Case with a bitfield length < 8 and arbitrary source
10460               */
10461               MOVA (aopGet (right, 0, FALSE, FALSE));
10462               /* shift and mask source value */
10463               AccLsh (bstr);
10464               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10465
10466               pushedB = pushB ();
10467               /* transfer A to B and get next byte */
10468               emitPtrByteGet (rname, p_type, TRUE);
10469
10470               emitcode ("anl", "a,#0x%02x", mask);
10471               emitcode ("orl", "a,b");
10472               if (p_type == GPOINTER)
10473                 emitcode ("pop", "b");
10474
10475               popB (pushedB);
10476            }
10477         }
10478
10479       emitPtrByteSet (rname, p_type, "a");
10480       return;
10481     }
10482
10483   /* Bit length is greater than 7 bits. In this case, copy  */
10484   /* all except the partial byte at the end                 */
10485   for (rlen=blen;rlen>=8;rlen-=8)
10486     {
10487       emitPtrByteSet (rname, p_type,
10488                       aopGet (right, offset++, FALSE, TRUE) );
10489       if (rlen>8)
10490         emitcode ("inc", "%s", rname);
10491     }
10492
10493   /* If there was a partial byte at the end */
10494   if (rlen)
10495     {
10496       mask = (((unsigned char) -1 << rlen) & 0xff);
10497
10498       if (AOP_TYPE (right) == AOP_LIT)
10499         {
10500           /* Case with partial byte and literal source
10501           */
10502           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10503           litval >>= (blen-rlen);
10504           litval &= (~mask) & 0xff;
10505           emitPtrByteGet (rname, p_type, FALSE);
10506           if ((mask|litval)!=0xff)
10507             emitcode ("anl","a,#0x%02x", mask);
10508           if (litval)
10509             emitcode ("orl","a,#0x%02x", litval);
10510         }
10511       else
10512         {
10513           bool pushedB;
10514           /* Case with partial byte and arbitrary source
10515           */
10516           MOVA (aopGet (right, offset++, FALSE, FALSE));
10517           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10518
10519           pushedB = pushB ();
10520           /* transfer A to B and get next byte */
10521           emitPtrByteGet (rname, p_type, TRUE);
10522
10523           emitcode ("anl", "a,#0x%02x", mask);
10524           emitcode ("orl", "a,b");
10525           if (p_type == GPOINTER)
10526             emitcode ("pop", "b");
10527
10528           popB (pushedB);
10529         }
10530       emitPtrByteSet (rname, p_type, "a");
10531     }
10532 }
10533
10534
10535 /*-----------------------------------------------------------------*/
10536 /* genDataPointerSet - remat pointer to data space                 */
10537 /*-----------------------------------------------------------------*/
10538 static void
10539 genDataPointerSet (operand * right,
10540                    operand * result,
10541                    iCode * ic)
10542 {
10543   int size, offset = 0;
10544   char *l, buffer[256];
10545
10546   D (emitcode (";", "genDataPointerSet"));
10547
10548   aopOp (right, ic, FALSE);
10549
10550   l = aopGet (result, 0, FALSE, TRUE);
10551   l++; //remove #
10552   size = max (AOP_SIZE (right), AOP_SIZE (result));
10553   while (size--)
10554     {
10555       if (offset)
10556         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10557       else
10558         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10559       emitcode ("mov", "%s,%s", buffer,
10560                 aopGet (right, offset++, FALSE, FALSE));
10561     }
10562
10563   freeAsmop (right, NULL, ic, TRUE);
10564   freeAsmop (result, NULL, ic, TRUE);
10565 }
10566
10567 /*-----------------------------------------------------------------*/
10568 /* genNearPointerSet - emitcode for near pointer put               */
10569 /*-----------------------------------------------------------------*/
10570 static void
10571 genNearPointerSet (operand * right,
10572                    operand * result,
10573                    iCode * ic,
10574                    iCode * pi)
10575 {
10576   asmop *aop = NULL;
10577   regs *preg = NULL;
10578   char *rname, *l;
10579   sym_link *retype, *letype;
10580   sym_link *ptype = operandType (result);
10581
10582   D (emitcode (";", "genNearPointerSet"));
10583
10584   retype = getSpec (operandType (right));
10585   letype = getSpec (ptype);
10586
10587   aopOp (result, ic, FALSE);
10588
10589   /* if the result is rematerializable &
10590      in data space & not a bit variable */
10591   if (AOP_TYPE (result) == AOP_IMMD &&
10592       DCL_TYPE (ptype) == POINTER &&
10593       !IS_BITVAR (retype) &&
10594       !IS_BITVAR (letype))
10595     {
10596       genDataPointerSet (right, result, ic);
10597       return;
10598     }
10599
10600   /* if the value is already in a pointer register
10601      then don't need anything more */
10602   if (!AOP_INPREG (AOP (result)))
10603     {
10604         if (
10605             //AOP_TYPE (result) == AOP_STK
10606             IS_AOP_PREG(result)
10607             )
10608         {
10609             // Aha, it is a pointer, just in disguise.
10610             rname = aopGet (result, 0, FALSE, FALSE);
10611             if (*rname != '@')
10612             {
10613                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10614                         __FILE__, __LINE__);
10615             }
10616             else
10617             {
10618                 // Expected case.
10619                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10620                 rname++;  // skip the '@'.
10621             }
10622         }
10623         else
10624         {
10625             /* otherwise get a free pointer register */
10626             aop = newAsmop (0);
10627             preg = getFreePtr (ic, &aop, FALSE);
10628             emitcode ("mov", "%s,%s",
10629                       preg->name,
10630                       aopGet (result, 0, FALSE, TRUE));
10631             rname = preg->name;
10632         }
10633     }
10634     else
10635     {
10636         rname = aopGet (result, 0, FALSE, FALSE);
10637     }
10638
10639   aopOp (right, ic, FALSE);
10640
10641   /* if bitfield then unpack the bits */
10642   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10643     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10644   else
10645     {
10646       /* we can just get the values */
10647       int size = AOP_SIZE (right);
10648       int offset = 0;
10649
10650       while (size--)
10651         {
10652           l = aopGet (right, offset, FALSE, TRUE);
10653           if ((*l == '@') || (strcmp (l, "acc") == 0))
10654             {
10655               MOVA (l);
10656               emitcode ("mov", "@%s,a", rname);
10657             }
10658           else
10659             emitcode ("mov", "@%s,%s", rname, l);
10660           if (size || pi)
10661             emitcode ("inc", "%s", rname);
10662           offset++;
10663         }
10664     }
10665
10666   /* now some housekeeping stuff */
10667   if (aop) /* we had to allocate for this iCode */
10668     {
10669       if (pi)
10670         aopPut (result, rname, 0);
10671       freeAsmop (NULL, aop, ic, TRUE);
10672     }
10673   else
10674     {
10675       /* we did not allocate which means left
10676          already in a pointer register, then
10677          if size > 0 && this could be used again
10678          we have to point it back to where it
10679          belongs */
10680       if ((AOP_SIZE (right) > 1 &&
10681            !OP_SYMBOL (result)->remat &&
10682            (OP_SYMBOL (result)->liveTo > ic->seq ||
10683             ic->depth)) &&
10684           !pi)
10685         {
10686           int size = AOP_SIZE (right) - 1;
10687           while (size--)
10688             emitcode ("dec", "%s", rname);
10689         }
10690     }
10691
10692   /* done */
10693   if (pi)
10694     pi->generated = 1;
10695   freeAsmop (right, NULL, ic, TRUE);
10696   freeAsmop (result, NULL, ic, TRUE);
10697 }
10698
10699 /*-----------------------------------------------------------------*/
10700 /* genPagedPointerSet - emitcode for Paged pointer put             */
10701 /*-----------------------------------------------------------------*/
10702 static void
10703 genPagedPointerSet (operand * right,
10704                     operand * result,
10705                     iCode * ic,
10706                     iCode * pi)
10707 {
10708   asmop *aop = NULL;
10709   regs *preg = NULL;
10710   char *rname, *l;
10711   sym_link *retype, *letype;
10712
10713   D (emitcode (";", "genPagedPointerSet"));
10714
10715   retype = getSpec (operandType (right));
10716   letype = getSpec (operandType (result));
10717
10718   aopOp (result, ic, FALSE);
10719
10720   /* if the value is already in a pointer register
10721      then don't need anything more */
10722   if (!AOP_INPREG (AOP (result)))
10723     {
10724       /* otherwise get a free pointer register */
10725       aop = newAsmop (0);
10726       preg = getFreePtr (ic, &aop, FALSE);
10727       emitcode ("mov", "%s,%s",
10728                 preg->name,
10729                 aopGet (result, 0, FALSE, TRUE));
10730       rname = preg->name;
10731     }
10732   else
10733     rname = aopGet (result, 0, FALSE, FALSE);
10734
10735   aopOp (right, ic, FALSE);
10736
10737   /* if bitfield then unpack the bits */
10738   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10739     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10740   else
10741     {
10742       /* we have can just get the values */
10743       int size = AOP_SIZE (right);
10744       int offset = 0;
10745
10746       while (size--)
10747         {
10748           l = aopGet (right, offset, FALSE, TRUE);
10749           MOVA (l);
10750           emitcode ("movx", "@%s,a", rname);
10751
10752           if (size || pi)
10753             emitcode ("inc", "%s", rname);
10754
10755           offset++;
10756         }
10757     }
10758
10759   /* now some housekeeping stuff */
10760   if (aop) /* we had to allocate for this iCode */
10761     {
10762       if (pi)
10763         aopPut (result, rname, 0);
10764       freeAsmop (NULL, aop, ic, TRUE);
10765     }
10766   else
10767     {
10768       /* we did not allocate which means left
10769          already in a pointer register, then
10770          if size > 0 && this could be used again
10771          we have to point it back to where it
10772          belongs */
10773       if (AOP_SIZE (right) > 1 &&
10774           !OP_SYMBOL (result)->remat &&
10775           (OP_SYMBOL (result)->liveTo > ic->seq ||
10776            ic->depth))
10777         {
10778           int size = AOP_SIZE (right) - 1;
10779           while (size--)
10780             emitcode ("dec", "%s", rname);
10781         }
10782     }
10783
10784   /* done */
10785   if (pi) pi->generated = 1;
10786   freeAsmop (result, NULL, ic, TRUE);
10787   freeAsmop (right, NULL, ic, TRUE);
10788 }
10789
10790 /*-----------------------------------------------------------------*/
10791 /* genFarPointerSet - set value from far space                     */
10792 /*-----------------------------------------------------------------*/
10793 static void
10794 genFarPointerSet (operand * right,
10795                   operand * result, iCode * ic, iCode * pi)
10796 {
10797   int size, offset;
10798   sym_link *retype = getSpec (operandType (right));
10799   sym_link *letype = getSpec (operandType (result));
10800
10801   D(emitcode (";", "genFarPointerSet"));
10802
10803   aopOp (result, ic, FALSE);
10804   loadDptrFromOperand (result, FALSE);
10805
10806   /* so dptr now contains the address */
10807   aopOp (right, ic, FALSE);
10808
10809   /* if bit then unpack */
10810   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10811     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10812   else
10813     {
10814       size = AOP_SIZE (right);
10815       offset = 0;
10816
10817       while (size--)
10818         {
10819           char *l = aopGet (right, offset++, FALSE, FALSE);
10820           MOVA (l);
10821           emitcode ("movx", "@dptr,a");
10822           if (size || pi)
10823             emitcode ("inc", "dptr");
10824         }
10825     }
10826   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10827     aopPut (result, "dpl", 0);
10828     aopPut (result, "dph", 1);
10829     pi->generated=1;
10830   }
10831   freeAsmop (result, NULL, ic, TRUE);
10832   freeAsmop (right, NULL, ic, TRUE);
10833 }
10834
10835 /*-----------------------------------------------------------------*/
10836 /* genGenPointerSet - set value from generic pointer space         */
10837 /*-----------------------------------------------------------------*/
10838 static void
10839 genGenPointerSet (operand * right,
10840                   operand * result, iCode * ic, iCode * pi)
10841 {
10842   int size, offset;
10843   sym_link *retype = getSpec (operandType (right));
10844   sym_link *letype = getSpec (operandType (result));
10845
10846   D (emitcode (";", "genGenPointerSet"));
10847
10848   aopOp (result, ic, FALSE);
10849   loadDptrFromOperand (result, TRUE);
10850
10851   /* so dptr now contains the address */
10852   aopOp (right, ic, FALSE);
10853
10854   /* if bit then unpack */
10855   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10856     {
10857       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10858     }
10859   else
10860     {
10861       size = AOP_SIZE (right);
10862       offset = 0;
10863
10864       while (size--)
10865         {
10866           char *l = aopGet (right, offset++, FALSE, FALSE);
10867           MOVA (l);
10868           emitcode ("lcall", "__gptrput");
10869           if (size || pi)
10870             emitcode ("inc", "dptr");
10871         }
10872     }
10873
10874   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10875     aopPut (result, "dpl", 0);
10876     aopPut (result, "dph", 1);
10877     pi->generated=1;
10878   }
10879   freeAsmop (result, NULL, ic, TRUE);
10880   freeAsmop (right, NULL, ic, TRUE);
10881 }
10882
10883 /*-----------------------------------------------------------------*/
10884 /* genPointerSet - stores the value into a pointer location        */
10885 /*-----------------------------------------------------------------*/
10886 static void
10887 genPointerSet (iCode * ic, iCode *pi)
10888 {
10889   operand *right, *result;
10890   sym_link *type, *etype;
10891   int p_type;
10892
10893   D (emitcode (";", "genPointerSet"));
10894
10895   right = IC_RIGHT (ic);
10896   result = IC_RESULT (ic);
10897
10898   /* depending on the type of pointer we need to
10899      move it to the correct pointer register */
10900   type = operandType (result);
10901   etype = getSpec (type);
10902   /* if left is of type of pointer then it is simple */
10903   if (IS_PTR (type) && !IS_FUNC (type->next))
10904     {
10905       p_type = DCL_TYPE (type);
10906     }
10907   else
10908     {
10909       /* we have to go by the storage class */
10910       p_type = PTR_TYPE (SPEC_OCLS (etype));
10911     }
10912
10913   /* special case when cast remat */
10914   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10915       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10916           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10917           type = operandType (result);
10918           p_type = DCL_TYPE (type);
10919   }
10920
10921   /* now that we have the pointer type we assign
10922      the pointer values */
10923   switch (p_type)
10924     {
10925
10926     case POINTER:
10927     case IPOINTER:
10928       genNearPointerSet (right, result, ic, pi);
10929       break;
10930
10931     case PPOINTER:
10932       genPagedPointerSet (right, result, ic, pi);
10933       break;
10934
10935     case FPOINTER:
10936       genFarPointerSet (right, result, ic, pi);
10937       break;
10938
10939     case GPOINTER:
10940       genGenPointerSet (right, result, ic, pi);
10941       break;
10942
10943     default:
10944       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10945               "genPointerSet: illegal pointer type");
10946     }
10947 }
10948
10949 /*-----------------------------------------------------------------*/
10950 /* genIfx - generate code for Ifx statement                        */
10951 /*-----------------------------------------------------------------*/
10952 static void
10953 genIfx (iCode * ic, iCode * popIc)
10954 {
10955   operand *cond = IC_COND (ic);
10956   int isbit = 0;
10957   char *dup = NULL;
10958
10959   D (emitcode (";", "genIfx"));
10960
10961   aopOp (cond, ic, FALSE);
10962
10963   /* get the value into acc */
10964   if (AOP_TYPE (cond) != AOP_CRY)
10965     {
10966       toBoolean (cond);
10967     }
10968   else
10969     {
10970       isbit = 1;
10971       if (AOP(cond)->aopu.aop_dir)
10972         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10973     }
10974
10975   /* the result is now in the accumulator or a directly addressable bit */
10976   freeAsmop (cond, NULL, ic, TRUE);
10977
10978   /* if there was something to be popped then do it */
10979   if (popIc)
10980     genIpop (popIc);
10981
10982   /* if the condition is a bit variable */
10983   if (isbit && dup)
10984     genIfxJump(ic, dup, NULL, NULL, NULL);
10985   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10986     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10987   else if (isbit && !IS_ITEMP (cond))
10988     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10989   else
10990     genIfxJump (ic, "a", NULL, NULL, NULL);
10991
10992   ic->generated = 1;
10993 }
10994
10995 /*-----------------------------------------------------------------*/
10996 /* genAddrOf - generates code for address of                       */
10997 /*-----------------------------------------------------------------*/
10998 static void
10999 genAddrOf (iCode * ic)
11000 {
11001   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11002   int size, offset;
11003
11004   D (emitcode (";", "genAddrOf"));
11005
11006   aopOp (IC_RESULT (ic), ic, FALSE);
11007
11008   /* if the operand is on the stack then we
11009      need to get the stack offset of this
11010      variable */
11011   if (sym->onStack)
11012     {
11013       /* if it has an offset then we need to compute it */
11014       if (sym->stack)
11015         {
11016           int stack_offset = ((sym->stack < 0) ?
11017                               ((char) (sym->stack - _G.nRegsSaved)) :
11018                               ((char) sym->stack)) & 0xff;
11019           if ((abs(stack_offset) == 1) &&
11020               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11021               !isOperandVolatile (IC_RESULT (ic), FALSE))
11022             {
11023               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11024               if (stack_offset > 0)
11025                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11026               else
11027                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11028             }
11029           else
11030             {
11031               emitcode ("mov", "a,%s", SYM_BP (sym));
11032               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11033               aopPut (IC_RESULT (ic), "a", 0);
11034             }
11035         }
11036       else
11037         {
11038           /* we can just move _bp */
11039           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11040         }
11041       /* fill the result with zero */
11042       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11043
11044       offset = 1;
11045       while (size--)
11046         {
11047           aopPut (IC_RESULT (ic), zero, offset++);
11048         }
11049       goto release;
11050     }
11051
11052   /* object not on stack then we need the name */
11053   size = AOP_SIZE (IC_RESULT (ic));
11054   offset = 0;
11055
11056   while (size--)
11057     {
11058       char s[SDCC_NAME_MAX];
11059       if (offset)
11060         sprintf (s, "#(%s >> %d)",
11061                  sym->rname,
11062                  offset * 8);
11063       else
11064         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11065       aopPut (IC_RESULT (ic), s, offset++);
11066     }
11067
11068 release:
11069   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11070
11071 }
11072
11073 /*-----------------------------------------------------------------*/
11074 /* genFarFarAssign - assignment when both are in far space         */
11075 /*-----------------------------------------------------------------*/
11076 static void
11077 genFarFarAssign (operand * result, operand * right, iCode * ic)
11078 {
11079   int size = AOP_SIZE (right);
11080   int offset = 0;
11081   char *l;
11082
11083   D (emitcode (";", "genFarFarAssign"));
11084
11085   /* first push the right side on to the stack */
11086   while (size--)
11087     {
11088       l = aopGet (right, offset++, FALSE, FALSE);
11089       MOVA (l);
11090       emitcode ("push", "acc");
11091     }
11092
11093   freeAsmop (right, NULL, ic, FALSE);
11094   /* now assign DPTR to result */
11095   aopOp (result, ic, FALSE);
11096   size = AOP_SIZE (result);
11097   while (size--)
11098     {
11099       emitcode ("pop", "acc");
11100       aopPut (result, "a", --offset);
11101     }
11102   freeAsmop (result, NULL, ic, FALSE);
11103 }
11104
11105 /*-----------------------------------------------------------------*/
11106 /* genAssign - generate code for assignment                        */
11107 /*-----------------------------------------------------------------*/
11108 static void
11109 genAssign (iCode * ic)
11110 {
11111   operand *result, *right;
11112   int size, offset;
11113   unsigned long lit = 0L;
11114
11115   D (emitcode (";", "genAssign"));
11116
11117   result = IC_RESULT (ic);
11118   right = IC_RIGHT (ic);
11119
11120   /* if they are the same */
11121   if (operandsEqu (result, right) &&
11122       !isOperandVolatile (result, FALSE) &&
11123       !isOperandVolatile (right, FALSE))
11124     return;
11125
11126   aopOp (right, ic, FALSE);
11127
11128   /* special case both in far space */
11129   if (AOP_TYPE (right) == AOP_DPTR &&
11130       IS_TRUE_SYMOP (result) &&
11131       isOperandInFarSpace (result))
11132     {
11133       genFarFarAssign (result, right, ic);
11134       return;
11135     }
11136
11137   aopOp (result, ic, TRUE);
11138
11139   /* if they are the same registers */
11140   if (sameRegs (AOP (right), AOP (result)) &&
11141       !isOperandVolatile (result, FALSE) &&
11142       !isOperandVolatile (right, FALSE))
11143     goto release;
11144
11145   /* if the result is a bit */
11146   if (AOP_TYPE (result) == AOP_CRY)
11147     {
11148       assignBit (result, right);
11149       goto release;
11150     }
11151
11152   /* bit variables done */
11153   /* general case */
11154   size = AOP_SIZE (result);
11155   offset = 0;
11156   if (AOP_TYPE (right) == AOP_LIT)
11157     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11158
11159   if ((size > 1) &&
11160       (AOP_TYPE (result) != AOP_REG) &&
11161       (AOP_TYPE (right) == AOP_LIT) &&
11162       !IS_FLOAT (operandType (right)) &&
11163       (lit < 256L))
11164     {
11165       while ((size) && (lit))
11166         {
11167           aopPut (result,
11168                   aopGet (right, offset, FALSE, FALSE),
11169                   offset);
11170           lit >>= 8;
11171           offset++;
11172           size--;
11173         }
11174       /* And now fill the rest with zeros. */
11175       if (size)
11176         {
11177           emitcode ("clr", "a");
11178         }
11179       while (size--)
11180         {
11181           aopPut (result, "a", offset);
11182           offset++;
11183         }
11184     }
11185   else
11186     {
11187       while (size--)
11188         {
11189           aopPut (result,
11190                   aopGet (right, offset, FALSE, FALSE),
11191                   offset);
11192           offset++;
11193         }
11194     }
11195
11196 release:
11197   freeAsmop (result, NULL, ic, TRUE);
11198   freeAsmop (right, NULL, ic, TRUE);
11199 }
11200
11201 /*-----------------------------------------------------------------*/
11202 /* genJumpTab - generates code for jump table                      */
11203 /*-----------------------------------------------------------------*/
11204 static void
11205 genJumpTab (iCode * ic)
11206 {
11207   symbol *jtab,*jtablo,*jtabhi;
11208   char *l;
11209   unsigned int count;
11210
11211   D (emitcode (";", "genJumpTab"));
11212
11213   count = elementsInSet( IC_JTLABELS (ic) );
11214
11215   if( count <= 16 )
11216     {
11217       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11218          if the switch argument is in a register.
11219          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11220       /* Peephole may not convert ljmp to sjmp or ret
11221          labelIsReturnOnly & labelInRange must check
11222          currPl->ic->op != JUMPTABLE */
11223       aopOp (IC_JTCOND (ic), ic, FALSE);
11224       /* get the condition into accumulator */
11225       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11226       MOVA (l);
11227       /* multiply by three */
11228       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11229         {
11230           emitcode ("mov", "b,#3");
11231           emitcode ("mul", "ab");
11232         }
11233       else
11234         {
11235           emitcode ("add", "a,acc");
11236           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11237         }
11238       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11239
11240       jtab = newiTempLabel (NULL);
11241       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11242       emitcode ("jmp", "@a+dptr");
11243       emitLabel (jtab);
11244       /* now generate the jump labels */
11245       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11246            jtab = setNextItem (IC_JTLABELS (ic)))
11247         emitcode ("ljmp", "%05d$", jtab->key + 100);
11248     }
11249   else
11250     {
11251       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11252          if the switch argument is in a register.
11253          For n>6 this algorithm may be more compact */
11254       jtablo = newiTempLabel (NULL);
11255       jtabhi = newiTempLabel (NULL);
11256
11257       /* get the condition into accumulator.
11258          Using b as temporary storage, if register push/pop is needed */
11259       aopOp (IC_JTCOND (ic), ic, FALSE);
11260       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11261       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11262           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11263         {
11264           // (MB) what if B is in use???
11265           wassertl(!BINUSE, "B was in use");
11266           emitcode ("mov", "b,%s", l);
11267           l = "b";
11268         }
11269       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11270       MOVA (l);
11271       if( count <= 112 )
11272         {
11273           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11274           emitcode ("movc", "a,@a+pc");
11275           emitcode ("push", "acc");
11276
11277           MOVA (l);
11278           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11279           emitcode ("movc", "a,@a+pc");
11280           emitcode ("push", "acc");
11281         }
11282       else
11283         {
11284           /* this scales up to n<=255, but needs two more bytes
11285              and changes dptr */
11286           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11287           emitcode ("movc", "a,@a+dptr");
11288           emitcode ("push", "acc");
11289
11290           MOVA (l);
11291           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11292           emitcode ("movc", "a,@a+dptr");
11293           emitcode ("push", "acc");
11294         }
11295
11296       emitcode ("ret", "");
11297
11298       /* now generate jump table, LSB */
11299       emitLabel (jtablo);
11300       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11301            jtab = setNextItem (IC_JTLABELS (ic)))
11302         emitcode (".db", "%05d$", jtab->key + 100);
11303
11304       /* now generate jump table, MSB */
11305       emitLabel (jtabhi);
11306       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11307            jtab = setNextItem (IC_JTLABELS (ic)))
11308          emitcode (".db", "%05d$>>8", jtab->key + 100);
11309     }
11310 }
11311
11312 /*-----------------------------------------------------------------*/
11313 /* genCast - gen code for casting                                  */
11314 /*-----------------------------------------------------------------*/
11315 static void
11316 genCast (iCode * ic)
11317 {
11318   operand *result = IC_RESULT (ic);
11319   sym_link *ctype = operandType (IC_LEFT (ic));
11320   sym_link *rtype = operandType (IC_RIGHT (ic));
11321   operand *right = IC_RIGHT (ic);
11322   int size, offset;
11323
11324   D (emitcode (";", "genCast"));
11325
11326   /* if they are equivalent then do nothing */
11327   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11328     return;
11329
11330   aopOp (right, ic, FALSE);
11331   aopOp (result, ic, FALSE);
11332
11333   /* if the result is a bit (and not a bitfield) */
11334   if (IS_BIT (OP_SYMBOL (result)->type))
11335     {
11336       assignBit (result, right);
11337       goto release;
11338     }
11339
11340   /* if they are the same size : or less */
11341   if (AOP_SIZE (result) <= AOP_SIZE (right))
11342     {
11343
11344       /* if they are in the same place */
11345       if (sameRegs (AOP (right), AOP (result)))
11346         goto release;
11347
11348       /* if they in different places then copy */
11349       size = AOP_SIZE (result);
11350       offset = 0;
11351       while (size--)
11352         {
11353           aopPut (result,
11354                   aopGet (right, offset, FALSE, FALSE),
11355                   offset);
11356           offset++;
11357         }
11358       goto release;
11359     }
11360
11361   /* if the result is of type pointer */
11362   if (IS_PTR (ctype))
11363     {
11364
11365       int p_type;
11366       sym_link *type = operandType (right);
11367       sym_link *etype = getSpec (type);
11368
11369       /* pointer to generic pointer */
11370       if (IS_GENPTR (ctype))
11371         {
11372           if (IS_PTR (type))
11373             {
11374               p_type = DCL_TYPE (type);
11375             }
11376           else
11377             {
11378               if (SPEC_SCLS(etype)==S_REGISTER) {
11379                 // let's assume it is a generic pointer
11380                 p_type=GPOINTER;
11381               } else {
11382                 /* we have to go by the storage class */
11383                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11384               }
11385             }
11386
11387           /* the first two bytes are known */
11388           size = GPTRSIZE - 1;
11389           offset = 0;
11390           while (size--)
11391             {
11392               aopPut (result,
11393                       aopGet (right, offset, FALSE, FALSE),
11394                       offset);
11395               offset++;
11396             }
11397           /* the last byte depending on type */
11398             {
11399                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11400                 char gpValStr[10];
11401
11402                 if (gpVal == -1)
11403                 {
11404                     // pointerTypeToGPByte will have bitched.
11405                     exit(1);
11406                 }
11407
11408                 sprintf(gpValStr, "#0x%x", gpVal);
11409                 aopPut (result, gpValStr, GPTRSIZE - 1);
11410             }
11411           goto release;
11412         }
11413
11414       /* just copy the pointers */
11415       size = AOP_SIZE (result);
11416       offset = 0;
11417       while (size--)
11418         {
11419           aopPut (result,
11420                   aopGet (right, offset, FALSE, FALSE),
11421                   offset);
11422           offset++;
11423         }
11424       goto release;
11425     }
11426
11427   /* so we now know that the size of destination is greater
11428      than the size of the source */
11429   /* we move to result for the size of source */
11430   size = AOP_SIZE (right);
11431   offset = 0;
11432   while (size--)
11433     {
11434       aopPut (result,
11435               aopGet (right, offset, FALSE, FALSE),
11436               offset);
11437       offset++;
11438     }
11439
11440   /* now depending on the sign of the source && destination */
11441   size = AOP_SIZE (result) - AOP_SIZE (right);
11442   /* if unsigned or not an integral type */
11443   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11444     {
11445       while (size--)
11446         aopPut (result, zero, offset++);
11447     }
11448   else
11449     {
11450       /* we need to extend the sign :{ */
11451       char *l = aopGet (right, AOP_SIZE (right) - 1,
11452                         FALSE, FALSE);
11453       MOVA (l);
11454       emitcode ("rlc", "a");
11455       emitcode ("subb", "a,acc");
11456       while (size--)
11457         aopPut (result, "a", offset++);
11458     }
11459
11460   /* we are done hurray !!!! */
11461
11462 release:
11463   freeAsmop (result, NULL, ic, TRUE);
11464   freeAsmop (right, NULL, ic, TRUE);
11465 }
11466
11467 /*-----------------------------------------------------------------*/
11468 /* genDjnz - generate decrement & jump if not zero instrucion      */
11469 /*-----------------------------------------------------------------*/
11470 static int
11471 genDjnz (iCode * ic, iCode * ifx)
11472 {
11473   symbol *lbl, *lbl1;
11474   if (!ifx)
11475     return 0;
11476
11477   /* if the if condition has a false label
11478      then we cannot save */
11479   if (IC_FALSE (ifx))
11480     return 0;
11481
11482   /* if the minus is not of the form a = a - 1 */
11483   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11484       !IS_OP_LITERAL (IC_RIGHT (ic)))
11485     return 0;
11486
11487   if (operandLitValue (IC_RIGHT (ic)) != 1)
11488     return 0;
11489
11490   /* if the size of this greater than one then no
11491      saving */
11492   if (getSize (operandType (IC_RESULT (ic))) > 1)
11493     return 0;
11494
11495   /* otherwise we can save BIG */
11496
11497   D (emitcode (";", "genDjnz"));
11498
11499   lbl = newiTempLabel (NULL);
11500   lbl1 = newiTempLabel (NULL);
11501
11502   aopOp (IC_RESULT (ic), ic, FALSE);
11503
11504   if (AOP_NEEDSACC(IC_RESULT(ic)))
11505   {
11506       /* If the result is accessed indirectly via
11507        * the accumulator, we must explicitly write
11508        * it back after the decrement.
11509        */
11510       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11511
11512       if (strcmp(rByte, "a"))
11513       {
11514            /* Something is hopelessly wrong */
11515            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11516                    __FILE__, __LINE__);
11517            /* We can just give up; the generated code will be inefficient,
11518             * but what the hey.
11519             */
11520            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11521            return 0;
11522       }
11523       emitcode ("dec", "%s", rByte);
11524       aopPut (IC_RESULT (ic), rByte, 0);
11525       emitcode ("jnz", "%05d$", lbl->key + 100);
11526   }
11527   else if (IS_AOP_PREG (IC_RESULT (ic)))
11528     {
11529       emitcode ("dec", "%s",
11530                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11531       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11532       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11533       ifx->generated = 1;
11534       emitcode ("jnz", "%05d$", lbl->key + 100);
11535     }
11536   else
11537     {
11538       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11539                 lbl->key + 100);
11540     }
11541   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11542   emitLabel (lbl);
11543   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11544   emitLabel (lbl1);
11545
11546   if (!ifx->generated)
11547       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11548   ifx->generated = 1;
11549   return 1;
11550 }
11551
11552 /*-----------------------------------------------------------------*/
11553 /* genReceive - generate code for a receive iCode                  */
11554 /*-----------------------------------------------------------------*/
11555 static void
11556 genReceive (iCode * ic)
11557 {
11558   int size = getSize (operandType (IC_RESULT (ic)));
11559   int offset = 0;
11560
11561   D (emitcode (";", "genReceive"));
11562
11563   if (ic->argreg == 1)
11564     { /* first parameter */
11565       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11566            isOperandInPagedSpace (IC_RESULT (ic))) &&
11567           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11568            IS_TRUE_SYMOP (IC_RESULT (ic))))
11569         {
11570           regs *tempRegs[4];
11571           int receivingA = 0;
11572           int roffset = 0;
11573
11574           for (offset = 0; offset<size; offset++)
11575             if (!strcmp (fReturn[offset], "a"))
11576               receivingA = 1;
11577
11578           if (!receivingA)
11579             {
11580               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11581                 {
11582                   for (offset = size-1; offset>0; offset--)
11583                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11584                   emitcode("mov","a,%s", fReturn[0]);
11585                   _G.accInUse++;
11586                   aopOp (IC_RESULT (ic), ic, FALSE);
11587                   _G.accInUse--;
11588                   aopPut (IC_RESULT (ic), "a", offset);
11589                   for (offset = 1; offset<size; offset++)
11590                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11591                   goto release;
11592                 }
11593             }
11594           else
11595             {
11596               if (getTempRegs(tempRegs, size, ic))
11597                 {
11598                   for (offset = 0; offset<size; offset++)
11599                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11600                   aopOp (IC_RESULT (ic), ic, FALSE);
11601                   for (offset = 0; offset<size; offset++)
11602                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11603                   goto release;
11604                 }
11605             }
11606
11607           offset = fReturnSizeMCS51 - size;
11608           while (size--)
11609             {
11610               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11611                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11612               offset++;
11613             }
11614           aopOp (IC_RESULT (ic), ic, FALSE);
11615           size = AOP_SIZE (IC_RESULT (ic));
11616           offset = 0;
11617           while (size--)
11618             {
11619               emitcode ("pop", "acc");
11620               aopPut (IC_RESULT (ic), "a", offset++);
11621             }
11622         }
11623       else
11624         {
11625           _G.accInUse++;
11626           aopOp (IC_RESULT (ic), ic, FALSE);
11627           _G.accInUse--;
11628           assignResultValue (IC_RESULT (ic), NULL);
11629         }
11630     }
11631   else if (ic->argreg > 12)
11632     { /* bit parameters */
11633       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11634
11635       BitBankUsed = 1;
11636       if (!reg || reg->rIdx != ic->argreg-5)
11637         {
11638           aopOp (IC_RESULT (ic), ic, FALSE);
11639           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11640           outBitC(IC_RESULT (ic));
11641         }
11642     }
11643   else
11644     { /* other parameters */
11645       int rb1off ;
11646       aopOp (IC_RESULT (ic), ic, FALSE);
11647       rb1off = ic->argreg;
11648       while (size--)
11649         {
11650           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11651         }
11652     }
11653
11654 release:
11655   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11656 }
11657
11658 /*-----------------------------------------------------------------*/
11659 /* genDummyRead - generate code for dummy read of volatiles        */
11660 /*-----------------------------------------------------------------*/
11661 static void
11662 genDummyRead (iCode * ic)
11663 {
11664   operand *op;
11665   int size, offset;
11666
11667   D (emitcode(";", "genDummyRead"));
11668
11669   op = IC_RIGHT (ic);
11670   if (op && IS_SYMOP (op))
11671     {
11672       aopOp (op, ic, FALSE);
11673
11674       /* if the result is a bit */
11675       if (AOP_TYPE (op) == AOP_CRY)
11676         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11677       else
11678         {
11679           /* bit variables done */
11680           /* general case */
11681           size = AOP_SIZE (op);
11682           offset = 0;
11683           while (size--)
11684           {
11685             MOVA (aopGet (op, offset, FALSE, FALSE));
11686             offset++;
11687           }
11688         }
11689
11690       freeAsmop (op, NULL, ic, TRUE);
11691     }
11692
11693   op = IC_LEFT (ic);
11694   if (op && IS_SYMOP (op))
11695     {
11696       aopOp (op, ic, FALSE);
11697
11698       /* if the result is a bit */
11699       if (AOP_TYPE (op) == AOP_CRY)
11700         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11701       else
11702         {
11703           /* bit variables done */
11704           /* general case */
11705           size = AOP_SIZE (op);
11706           offset = 0;
11707           while (size--)
11708           {
11709             MOVA (aopGet (op, offset, FALSE, FALSE));
11710             offset++;
11711           }
11712         }
11713
11714       freeAsmop (op, NULL, ic, TRUE);
11715     }
11716 }
11717
11718 /*-----------------------------------------------------------------*/
11719 /* genCritical - generate code for start of a critical sequence    */
11720 /*-----------------------------------------------------------------*/
11721 static void
11722 genCritical (iCode *ic)
11723 {
11724   symbol *tlbl = newiTempLabel (NULL);
11725
11726   D (emitcode(";", "genCritical"));
11727
11728   if (IC_RESULT (ic))
11729     {
11730       aopOp (IC_RESULT (ic), ic, TRUE);
11731       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11732       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11733       aopPut (IC_RESULT (ic), zero, 0);
11734       emitLabel (tlbl);
11735       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11736     }
11737   else
11738     {
11739       emitcode ("setb", "c");
11740       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11741       emitcode ("clr", "c");
11742       emitLabel (tlbl);
11743       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11744     }
11745 }
11746
11747 /*-----------------------------------------------------------------*/
11748 /* genEndCritical - generate code for end of a critical sequence   */
11749 /*-----------------------------------------------------------------*/
11750 static void
11751 genEndCritical (iCode *ic)
11752 {
11753   D(emitcode(";", "genEndCritical"));
11754
11755   if (IC_RIGHT (ic))
11756     {
11757       aopOp (IC_RIGHT (ic), ic, FALSE);
11758       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11759         {
11760           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11761           emitcode ("mov", "ea,c");
11762         }
11763       else
11764         {
11765           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11766             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11767           emitcode ("rrc", "a");
11768           emitcode ("mov", "ea,c");
11769         }
11770       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11771     }
11772   else
11773     {
11774       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11775       emitcode ("mov", "ea,c");
11776     }
11777 }
11778
11779 /*-----------------------------------------------------------------*/
11780 /* gen51Code - generate code for 8051 based controllers            */
11781 /*-----------------------------------------------------------------*/
11782 void
11783 gen51Code (iCode * lic)
11784 {
11785   iCode *ic;
11786   int cln = 0;
11787   /* int cseq = 0; */
11788
11789   _G.currentFunc = NULL;
11790   lineHead = lineCurr = NULL;
11791
11792   /* print the allocation information */
11793   if (allocInfo && currFunc)
11794     printAllocInfo (currFunc, codeOutBuf);
11795   /* if debug information required */
11796   if (options.debug && currFunc)
11797     {
11798       debugFile->writeFunction (currFunc, lic);
11799     }
11800   /* stack pointer name */
11801   if (options.useXstack)
11802     spname = "_spx";
11803   else
11804     spname = "sp";
11805
11806
11807   for (ic = lic; ic; ic = ic->next)
11808     {
11809       _G.current_iCode = ic;
11810
11811       if (ic->lineno && cln != ic->lineno)
11812         {
11813           if (options.debug)
11814             {
11815               debugFile->writeCLine (ic);
11816             }
11817           if (!options.noCcodeInAsm) {
11818             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11819                       printCLine(ic->filename, ic->lineno));
11820           }
11821           cln = ic->lineno;
11822         }
11823       #if 0
11824       if (ic->seqPoint && ic->seqPoint != cseq)
11825         {
11826           emitcode (";", "sequence point %d", ic->seqPoint);
11827           cseq = ic->seqPoint;
11828         }
11829       #endif
11830       if (options.iCodeInAsm) {
11831         char regsInUse[80];
11832         int i;
11833         char *iLine;
11834
11835         #if 0
11836         for (i=0; i<8; i++) {
11837           sprintf (&regsInUse[i],
11838                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11839         regsInUse[i]=0;
11840         #else
11841         strcpy (regsInUse, "--------");
11842         for (i=0; i < 8; i++) {
11843           if (bitVectBitValue (ic->rMask, i))
11844             {
11845               int offset = regs8051[i].offset;
11846               regsInUse[offset] = offset + '0'; /* show rMask */
11847             }
11848         #endif
11849         }
11850         iLine = printILine(ic);
11851         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11852         dbuf_free(iLine);
11853       }
11854       /* if the result is marked as
11855          spilt and rematerializable or code for
11856          this has already been generated then
11857          do nothing */
11858       if (resultRemat (ic) || ic->generated)
11859         continue;
11860
11861       /* depending on the operation */
11862       switch (ic->op)
11863         {
11864         case '!':
11865           genNot (ic);
11866           break;
11867
11868         case '~':
11869           genCpl (ic);
11870           break;
11871
11872         case UNARYMINUS:
11873           genUminus (ic);
11874           break;
11875
11876         case IPUSH:
11877           genIpush (ic);
11878           break;
11879
11880         case IPOP:
11881           /* IPOP happens only when trying to restore a
11882              spilt live range, if there is an ifx statement
11883              following this pop then the if statement might
11884              be using some of the registers being popped which
11885              would destory the contents of the register so
11886              we need to check for this condition and handle it */
11887           if (ic->next &&
11888               ic->next->op == IFX &&
11889               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11890             genIfx (ic->next, ic);
11891           else
11892             genIpop (ic);
11893           break;
11894
11895         case CALL:
11896           genCall (ic);
11897           break;
11898
11899         case PCALL:
11900           genPcall (ic);
11901           break;
11902
11903         case FUNCTION:
11904           genFunction (ic);
11905           break;
11906
11907         case ENDFUNCTION:
11908           genEndFunction (ic);
11909           break;
11910
11911         case RETURN:
11912           genRet (ic);
11913           break;
11914
11915         case LABEL:
11916           genLabel (ic);
11917           break;
11918
11919         case GOTO:
11920           genGoto (ic);
11921           break;
11922
11923         case '+':
11924           genPlus (ic);
11925           break;
11926
11927         case '-':
11928           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11929             genMinus (ic);
11930           break;
11931
11932         case '*':
11933           genMult (ic);
11934           break;
11935
11936         case '/':
11937           genDiv (ic);
11938           break;
11939
11940         case '%':
11941           genMod (ic);
11942           break;
11943
11944         case '>':
11945           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11946           break;
11947
11948         case '<':
11949           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11950           break;
11951
11952         case LE_OP:
11953         case GE_OP:
11954         case NE_OP:
11955
11956           /* note these two are xlated by algebraic equivalence
11957              in decorateType() in SDCCast.c */
11958           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11959                   "got '>=' or '<=' shouldn't have come here");
11960           break;
11961
11962         case EQ_OP:
11963           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11964           break;
11965
11966         case AND_OP:
11967           genAndOp (ic);
11968           break;
11969
11970         case OR_OP:
11971           genOrOp (ic);
11972           break;
11973
11974         case '^':
11975           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11976           break;
11977
11978         case '|':
11979           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11980           break;
11981
11982         case BITWISEAND:
11983           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11984           break;
11985
11986         case INLINEASM:
11987           genInline (ic);
11988           break;
11989
11990         case RRC:
11991           genRRC (ic);
11992           break;
11993
11994         case RLC:
11995           genRLC (ic);
11996           break;
11997
11998         case GETHBIT:
11999           genGetHbit (ic);
12000           break;
12001
12002         case GETABIT:
12003           genGetAbit (ic);
12004           break;
12005
12006         case GETBYTE:
12007           genGetByte (ic);
12008           break;
12009
12010         case GETWORD:
12011           genGetWord (ic);
12012           break;
12013
12014         case LEFT_OP:
12015           genLeftShift (ic);
12016           break;
12017
12018         case RIGHT_OP:
12019           genRightShift (ic);
12020           break;
12021
12022         case GET_VALUE_AT_ADDRESS:
12023           genPointerGet (ic,
12024                          hasInc (IC_LEFT (ic), ic,
12025                                  getSize (operandType (IC_RESULT (ic)))),
12026                          ifxForOp (IC_RESULT (ic), ic) );
12027           break;
12028
12029         case '=':
12030           if (POINTER_SET (ic))
12031             genPointerSet (ic,
12032                            hasInc (IC_RESULT (ic), ic,
12033                                    getSize (operandType (IC_RIGHT (ic)))));
12034           else
12035             genAssign (ic);
12036           break;
12037
12038         case IFX:
12039           genIfx (ic, NULL);
12040           break;
12041
12042         case ADDRESS_OF:
12043           genAddrOf (ic);
12044           break;
12045
12046         case JUMPTABLE:
12047           genJumpTab (ic);
12048           break;
12049
12050         case CAST:
12051           genCast (ic);
12052           break;
12053
12054         case RECEIVE:
12055           genReceive (ic);
12056           break;
12057
12058         case SEND:
12059           addSet (&_G.sendSet, ic);
12060           break;
12061
12062         case DUMMY_READ_VOLATILE:
12063           genDummyRead (ic);
12064           break;
12065
12066         case CRITICAL:
12067           genCritical (ic);
12068           break;
12069
12070         case ENDCRITICAL:
12071           genEndCritical (ic);
12072           break;
12073
12074         case SWAP:
12075           genSwap (ic);
12076           break;
12077
12078         default:
12079           ic = ic;
12080         }
12081     }
12082
12083   _G.current_iCode = NULL;
12084
12085   /* now we are ready to call the
12086      peep hole optimizer */
12087   if (!options.nopeep)
12088     peepHole (&lineHead);
12089
12090   /* now do the actual printing */
12091   printLine (lineHead, codeOutBuf);
12092   return;
12093 }