* src/ds390/peeph.def: replaced 24bitModeAndPortDS390 by
[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               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7080                 {
7081                   symbol *tlbl = newiTempLabel (NULL);
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                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7087                   goto release;
7088                 }
7089               else
7090                 {
7091                   toCarry (right);
7092                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7093                 }
7094             }
7095         }
7096       // bit = c
7097       // val = c
7098       if (size)
7099         outBitC (result);
7100       // if(bit | ...)
7101       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7102         genIfxJump (ifx, "c", left, right, result);
7103       goto release;
7104     }
7105
7106   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7107   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7108   if ((AOP_TYPE (right) == AOP_LIT) &&
7109       (AOP_TYPE (result) == AOP_CRY) &&
7110       (AOP_TYPE (left) != AOP_CRY))
7111     {
7112       if (lit)
7113         {
7114           // result = 1
7115           if (size)
7116             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7117           else
7118             continueIfTrue (ifx);
7119           goto release;
7120         }
7121       else
7122         {
7123           // lit = 0, result = boolean(left)
7124           if (size)
7125             emitcode ("setb", "c");
7126           toBoolean (right);
7127           if (size)
7128             {
7129               symbol *tlbl = newiTempLabel (NULL);
7130               emitcode ("jnz", "%05d$", tlbl->key + 100);
7131               CLRC;
7132               emitLabel (tlbl);
7133             }
7134           else
7135             {
7136               genIfxJump (ifx, "a", left, right, result);
7137               goto release;
7138             }
7139         }
7140       outBitC (result);
7141       goto release;
7142     }
7143
7144   /* if left is same as result */
7145   if (sameRegs (AOP (result), AOP (left)))
7146     {
7147       for (; size--; offset++)
7148         {
7149           if (AOP_TYPE (right) == AOP_LIT)
7150             {
7151               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7152               if (bytelit == 0)
7153                 {
7154                   /* dummy read of volatile operand */
7155                   if (isOperandVolatile (left, FALSE))
7156                     MOVA (aopGet (left, offset, FALSE, FALSE));
7157                   else
7158                     continue;
7159                 }
7160               else if (bytelit == 0x0FF)
7161                 {
7162                   aopPut (result, "#0xFF", offset);
7163                 }
7164               else if (IS_AOP_PREG (left))
7165                 {
7166                   MOVA (aopGet (left, offset, FALSE, TRUE));
7167                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7168                   aopPut (result, "a", offset);
7169                 }
7170               else
7171                 {
7172                   emitcode ("orl", "%s,%s",
7173                             aopGet (left, offset, FALSE, TRUE),
7174                             aopGet (right, offset, FALSE, FALSE));
7175                 }
7176             }
7177           else
7178             {
7179               if (AOP_TYPE (left) == AOP_ACC)
7180                 {
7181                   if (offset)
7182                     emitcode("mov", "a,b");
7183                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7184                 }
7185               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7186                 {
7187                   MOVB (aopGet (left, offset, FALSE, FALSE));
7188                   MOVA (aopGet (right, offset, FALSE, FALSE));
7189                   emitcode ("orl", "a,b");
7190                   aopPut (result, "a", offset);
7191                 }
7192               else if (aopGetUsesAcc (left, offset))
7193                 {
7194                   MOVA (aopGet (left, offset, FALSE, FALSE));
7195                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7196                   aopPut (result, "a", offset);
7197                 }
7198               else
7199                 {
7200                   MOVA (aopGet (right, offset, FALSE, FALSE));
7201                   if (IS_AOP_PREG (left))
7202                     {
7203                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7204                       aopPut (result, "a", offset);
7205                     }
7206                   else
7207                     {
7208                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7209                     }
7210                 }
7211             }
7212         }
7213     }
7214   else
7215     {
7216       // left & result in different registers
7217       if (AOP_TYPE (result) == AOP_CRY)
7218         {
7219           // result = bit
7220           // if(size), result in bit
7221           // if(!size && ifx), conditional oper: if(left | right)
7222           symbol *tlbl = newiTempLabel (NULL);
7223           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7224           if (size)
7225             emitcode ("setb", "c");
7226           while (sizer--)
7227             {
7228               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7229                   && AOP_TYPE(left)==AOP_ACC)
7230                 {
7231                   if (offset)
7232                     emitcode("mov", "a,b");
7233                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7234                 }
7235               else if (AOP_TYPE(left)==AOP_ACC)
7236                 {
7237                   if (!offset)
7238                     {
7239                       bool pushedB = pushB ();
7240                       emitcode("mov", "b,a");
7241                       MOVA (aopGet (right, offset, FALSE, FALSE));
7242                       emitcode("orl", "a,b");
7243                       popB (pushedB);
7244                     }
7245                   else
7246                     {
7247                       MOVA (aopGet (right, offset, FALSE, FALSE));
7248                       emitcode("orl", "a,b");
7249                     }
7250                 }
7251               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7252                 {
7253                   MOVB (aopGet (left, offset, FALSE, FALSE));
7254                   MOVA (aopGet (right, offset, FALSE, FALSE));
7255                   emitcode ("orl", "a,b");
7256                 }
7257               else if (aopGetUsesAcc (left, offset))
7258                 {
7259                   MOVA (aopGet (left, offset, FALSE, FALSE));
7260                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7261                 }
7262               else
7263                 {
7264                   MOVA (aopGet (right, offset, FALSE, FALSE));
7265                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7266               }
7267
7268               emitcode ("jnz", "%05d$", tlbl->key + 100);
7269               offset++;
7270             }
7271           if (size)
7272             {
7273               CLRC;
7274               emitLabel (tlbl);
7275               outBitC (result);
7276             }
7277           else if (ifx)
7278             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7279           else
7280             emitLabel (tlbl);
7281         }
7282       else
7283         {
7284           for (; (size--); offset++)
7285             {
7286               // normal case
7287               // result = left | right
7288               if (AOP_TYPE (right) == AOP_LIT)
7289                 {
7290                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7291                   if (bytelit == 0)
7292                     {
7293                       aopPut (result,
7294                               aopGet (left, offset, FALSE, FALSE),
7295                               offset);
7296                       continue;
7297                     }
7298                   else if (bytelit == 0x0FF)
7299                     {
7300                       /* dummy read of volatile operand */
7301                       if (isOperandVolatile (left, FALSE))
7302                         MOVA (aopGet (left, offset, FALSE, FALSE));
7303                       aopPut (result, "#0xFF", offset);
7304                       continue;
7305                     }
7306                 }
7307               // faster than result <- left, orl result,right
7308               // and better if result is SFR
7309               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7310                   && AOP_TYPE(left)==AOP_ACC)
7311                 {
7312                   if (offset)
7313                     emitcode("mov", "a,b");
7314                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7315                 }
7316               else if (AOP_TYPE(left)==AOP_ACC)
7317                 {
7318                   if (!offset)
7319                     {
7320                       bool pushedB = pushB ();
7321                       emitcode("mov", "b,a");
7322                       MOVA (aopGet (right, offset, FALSE, FALSE));
7323                       emitcode("orl", "a,b");
7324                       popB (pushedB);
7325                     }
7326                   else
7327                     {
7328                       MOVA (aopGet (right, offset, FALSE, FALSE));
7329                       emitcode("orl", "a,b");
7330                     }
7331                 }
7332               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7333                 {
7334                   MOVB (aopGet (left, offset, FALSE, FALSE));
7335                   MOVA (aopGet (right, offset, FALSE, FALSE));
7336                   emitcode ("orl", "a,b");
7337                 }
7338               else if (aopGetUsesAcc (left, offset))
7339                 {
7340                   MOVA (aopGet (left, offset, FALSE, FALSE));
7341                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7342                 }
7343               else
7344                 {
7345                   MOVA (aopGet (right, offset, FALSE, FALSE));
7346                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7347                 }
7348               aopPut (result, "a", offset);
7349             }
7350         }
7351     }
7352
7353 release:
7354   freeAsmop (result, NULL, ic, TRUE);
7355   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7356   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7357 }
7358
7359 /*-----------------------------------------------------------------*/
7360 /* genXor - code for xclusive or                                   */
7361 /*-----------------------------------------------------------------*/
7362 static void
7363 genXor (iCode * ic, iCode * ifx)
7364 {
7365   operand *left, *right, *result;
7366   int size, offset = 0;
7367   unsigned long lit = 0L;
7368   int bytelit = 0;
7369
7370   D (emitcode (";", "genXor"));
7371
7372   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7373   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7374   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7375
7376 #ifdef DEBUG_TYPE
7377   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7378             AOP_TYPE (result),
7379             AOP_TYPE (left), AOP_TYPE (right));
7380   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7381             AOP_SIZE (result),
7382             AOP_SIZE (left), AOP_SIZE (right));
7383 #endif
7384
7385   /* if left is a literal & right is not ||
7386      if left needs acc & right does not */
7387   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7388       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7389     {
7390       operand *tmp = right;
7391       right = left;
7392       left = tmp;
7393     }
7394
7395   /* if result = right then exchange them */
7396   if (sameRegs (AOP (result), AOP (right)))
7397     {
7398       operand *tmp = right;
7399       right = left;
7400       left = tmp;
7401     }
7402
7403   /* if right is bit then exchange them */
7404   if (AOP_TYPE (right) == AOP_CRY &&
7405       AOP_TYPE (left) != AOP_CRY)
7406     {
7407       operand *tmp = right;
7408       right = left;
7409       left = tmp;
7410     }
7411
7412   if (AOP_TYPE (right) == AOP_LIT)
7413     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7414
7415   size = AOP_SIZE (result);
7416
7417   // if(bit ^ yy)
7418   // xx = bit ^ yy;
7419   if (AOP_TYPE (left) == AOP_CRY)
7420     {
7421       if (AOP_TYPE (right) == AOP_LIT)
7422         {
7423           // c = bit & literal;
7424           if (lit >> 1)
7425             {
7426               // lit>>1  != 0 => result = 1
7427               if (AOP_TYPE (result) == AOP_CRY)
7428                 {
7429                   if (size)
7430                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7431                   else if (ifx)
7432                     continueIfTrue (ifx);
7433                   goto release;
7434                 }
7435               emitcode ("setb", "c");
7436             }
7437           else
7438             {
7439               // lit == (0 or 1)
7440               if (lit == 0)
7441                 {
7442                   // lit == 0, result = left
7443                   if (size && sameRegs (AOP (result), AOP (left)))
7444                     goto release;
7445                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7446                 }
7447               else
7448                 {
7449                   // lit == 1, result = not(left)
7450                   if (size && sameRegs (AOP (result), AOP (left)))
7451                     {
7452                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7453                       goto release;
7454                     }
7455                   else
7456                     {
7457                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7458                       emitcode ("cpl", "c");
7459                     }
7460                 }
7461             }
7462         }
7463       else
7464         {
7465           // right != literal
7466           symbol *tlbl = newiTempLabel (NULL);
7467           if (AOP_TYPE (right) == AOP_CRY)
7468             {
7469               // c = bit ^ bit;
7470               if (IS_OP_ACCUSE (left))
7471                 {// left already is in the carry
7472                   operand *tmp = right;
7473                   right = left;
7474                   left = tmp;
7475                 }
7476               else
7477                 {
7478                   toCarry (right);
7479                 }
7480             }
7481           else
7482             {
7483               // c = bit ^ val
7484               toCarry (right);
7485             }
7486           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7487           emitcode ("cpl", "c");
7488           emitLabel (tlbl);
7489         }
7490       // bit = c
7491       // val = c
7492       if (size)
7493         outBitC (result);
7494       // if(bit ^ ...)
7495       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7496         genIfxJump (ifx, "c", left, right, result);
7497       goto release;
7498     }
7499
7500   /* if left is same as result */
7501   if (sameRegs (AOP (result), AOP (left)))
7502     {
7503       for (; size--; offset++)
7504         {
7505           if (AOP_TYPE (right) == AOP_LIT)
7506             {
7507               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7508               if (bytelit == 0)
7509                 {
7510                   /* dummy read of volatile operand */
7511                   if (isOperandVolatile (left, FALSE))
7512                     MOVA (aopGet (left, offset, FALSE, FALSE));
7513                   else
7514                     continue;
7515                 }
7516               else if (IS_AOP_PREG (left))
7517                 {
7518                   MOVA (aopGet (left, offset, FALSE, TRUE));
7519                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7520                   aopPut (result, "a", offset);
7521                 }
7522               else
7523                 {
7524                   emitcode ("xrl", "%s,%s",
7525                             aopGet (left, offset, FALSE, TRUE),
7526                             aopGet (right, offset, FALSE, FALSE));
7527                 }
7528             }
7529           else
7530             {
7531               if (AOP_TYPE (left) == AOP_ACC)
7532                 {
7533                   if (offset)
7534                     emitcode("mov", "a,b");
7535                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7536                 }
7537               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7538                 {
7539                   MOVB (aopGet (left, offset, FALSE, FALSE));
7540                   MOVA (aopGet (right, offset, FALSE, FALSE));
7541                   emitcode ("xrl", "a,b");
7542                   aopPut (result, "a", offset);
7543                 }
7544               else if (aopGetUsesAcc (left, offset))
7545                 {
7546                   MOVA (aopGet (left, offset, FALSE, FALSE));
7547                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7548                   aopPut (result, "a", offset);
7549                 }
7550               else
7551                 {
7552                   MOVA (aopGet (right, offset, FALSE, FALSE));
7553                   if (IS_AOP_PREG (left))
7554                     {
7555                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7556                       aopPut (result, "a", offset);
7557                     }
7558                   else
7559                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7560                 }
7561             }
7562         }
7563     }
7564   else
7565     {
7566       // left & result in different registers
7567       if (AOP_TYPE (result) == AOP_CRY)
7568         {
7569           // result = bit
7570           // if(size), result in bit
7571           // if(!size && ifx), conditional oper: if(left ^ right)
7572           symbol *tlbl = newiTempLabel (NULL);
7573           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7574
7575           if (size)
7576             emitcode ("setb", "c");
7577           while (sizer--)
7578             {
7579               if ((AOP_TYPE (right) == AOP_LIT) &&
7580                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7581                 {
7582                   MOVA (aopGet (left, offset, FALSE, FALSE));
7583                 }
7584               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7585                   && AOP_TYPE(left)==AOP_ACC)
7586                 {
7587                   if (offset)
7588                     emitcode("mov", "a,b");
7589                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7590                 }
7591               else if (AOP_TYPE(left)==AOP_ACC)
7592                 {
7593                   if (!offset)
7594                     {
7595                       bool pushedB = pushB ();
7596                       emitcode("mov", "b,a");
7597                       MOVA (aopGet (right, offset, FALSE, FALSE));
7598                       emitcode("xrl", "a,b");
7599                       popB (pushedB);
7600                     }
7601                   else
7602                     {
7603                       MOVA (aopGet (right, offset, FALSE, FALSE));
7604                       emitcode("xrl", "a,b");
7605                     }
7606                 }
7607               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7608                 {
7609                   MOVB (aopGet (left, offset, FALSE, FALSE));
7610                   MOVA (aopGet (right, offset, FALSE, FALSE));
7611                   emitcode ("xrl", "a,b");
7612                 }
7613               else if (aopGetUsesAcc (left, offset))
7614                 {
7615                   MOVA (aopGet (left, offset, FALSE, FALSE));
7616                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7617                 }
7618               else
7619                 {
7620                   MOVA (aopGet (right, offset, FALSE, FALSE));
7621                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7622                 }
7623
7624               emitcode ("jnz", "%05d$", tlbl->key + 100);
7625               offset++;
7626             }
7627           if (size)
7628             {
7629               CLRC;
7630               emitLabel (tlbl);
7631               outBitC (result);
7632             }
7633           else if (ifx)
7634             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7635         }
7636       else
7637         {
7638           for (; (size--); offset++)
7639             {
7640               // normal case
7641               // result = left ^ right
7642               if (AOP_TYPE (right) == AOP_LIT)
7643                 {
7644                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7645                   if (bytelit == 0)
7646                     {
7647                       aopPut (result,
7648                               aopGet (left, offset, FALSE, FALSE),
7649                               offset);
7650                       continue;
7651                     }
7652                 }
7653               // faster than result <- left, xrl result,right
7654               // and better if result is SFR
7655               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7656                   && AOP_TYPE(left)==AOP_ACC)
7657                 {
7658                   if (offset)
7659                     emitcode("mov", "a,b");
7660                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7661                 }
7662               else if (AOP_TYPE(left)==AOP_ACC)
7663                 {
7664                   if (!offset)
7665                     {
7666                       bool pushedB = pushB ();
7667                       emitcode("mov", "b,a");
7668                       MOVA (aopGet (right, offset, FALSE, FALSE));
7669                       emitcode("xrl", "a,b");
7670                       popB (pushedB);
7671                     }
7672                   else
7673                     {
7674                       MOVA (aopGet (right, offset, FALSE, FALSE));
7675                       emitcode("xrl", "a,b");
7676                     }
7677                 }
7678               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7679                 {
7680                   MOVB (aopGet (left, offset, FALSE, FALSE));
7681                   MOVA (aopGet (right, offset, FALSE, FALSE));
7682                   emitcode ("xrl", "a,b");
7683                 }
7684               else if (aopGetUsesAcc (left, offset))
7685                 {
7686                   MOVA (aopGet (left, offset, FALSE, FALSE));
7687                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7688                 }
7689               else
7690                 {
7691                   MOVA (aopGet (right, offset, FALSE, FALSE));
7692                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7693                 }
7694               aopPut (result, "a", offset);
7695             }
7696         }
7697     }
7698
7699 release:
7700   freeAsmop (result, NULL, ic, TRUE);
7701   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7702   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7703 }
7704
7705 /*-----------------------------------------------------------------*/
7706 /* genInline - write the inline code out                           */
7707 /*-----------------------------------------------------------------*/
7708 static void
7709 genInline (iCode * ic)
7710 {
7711   char *buffer, *bp, *bp1;
7712   bool inComment = FALSE;
7713
7714   D (emitcode (";", "genInline"));
7715
7716   _G.inLine += (!options.asmpeep);
7717
7718   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7719
7720   /* emit each line as a code */
7721   while (*bp)
7722     {
7723       switch (*bp)
7724         {
7725         case ';':
7726           inComment = TRUE;
7727           ++bp;
7728           break;
7729
7730         case '\n':
7731           inComment = FALSE;
7732           *bp++ = '\0';
7733           emitcode (bp1, "");
7734           bp1 = bp;
7735           break;
7736
7737         default:
7738           /* Add \n for labels, not dirs such as c:\mydir */
7739           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7740             {
7741               ++bp;
7742               *bp = '\0';
7743               ++bp;
7744               emitcode (bp1, "");
7745               bp1 = bp;
7746             }
7747           else
7748             ++bp;
7749           break;
7750         }
7751     }
7752   if (bp1 != bp)
7753     emitcode (bp1, "");
7754
7755   Safe_free (buffer);
7756
7757   _G.inLine -= (!options.asmpeep);
7758 }
7759
7760 /*-----------------------------------------------------------------*/
7761 /* genRRC - rotate right with carry                                */
7762 /*-----------------------------------------------------------------*/
7763 static void
7764 genRRC (iCode * ic)
7765 {
7766   operand *left, *result;
7767   int size, offset;
7768   char *l;
7769
7770   D (emitcode (";", "genRRC"));
7771
7772   /* rotate right with carry */
7773   left = IC_LEFT (ic);
7774   result = IC_RESULT (ic);
7775   aopOp (left, ic, FALSE);
7776   aopOp (result, ic, FALSE);
7777
7778   /* move it to the result */
7779   size = AOP_SIZE (result);
7780   offset = size - 1;
7781   if (size == 1) { /* special case for 1 byte */
7782       l = aopGet (left, offset, FALSE, FALSE);
7783       MOVA (l);
7784       emitcode ("rr", "a");
7785       goto release;
7786   }
7787   /* no need to clear carry, bit7 will be written later */
7788   while (size--)
7789     {
7790       l = aopGet (left, offset, FALSE, FALSE);
7791       MOVA (l);
7792       emitcode ("rrc", "a");
7793       if (AOP_SIZE (result) > 1)
7794         aopPut (result, "a", offset--);
7795     }
7796   /* now we need to put the carry into the
7797      highest order byte of the result */
7798   if (AOP_SIZE (result) > 1)
7799     {
7800       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7801       MOVA (l);
7802     }
7803   emitcode ("mov", "acc.7,c");
7804  release:
7805   aopPut (result, "a", AOP_SIZE (result) - 1);
7806   freeAsmop (result, NULL, ic, TRUE);
7807   freeAsmop (left, NULL, ic, TRUE);
7808 }
7809
7810 /*-----------------------------------------------------------------*/
7811 /* genRLC - generate code for rotate left with carry               */
7812 /*-----------------------------------------------------------------*/
7813 static void
7814 genRLC (iCode * ic)
7815 {
7816   operand *left, *result;
7817   int size, offset;
7818   char *l;
7819
7820   D (emitcode (";", "genRLC"));
7821
7822   /* rotate right with carry */
7823   left = IC_LEFT (ic);
7824   result = IC_RESULT (ic);
7825   aopOp (left, ic, FALSE);
7826   aopOp (result, ic, FALSE);
7827
7828   /* move it to the result */
7829   size = AOP_SIZE (result);
7830   offset = 0;
7831   if (size--)
7832     {
7833       l = aopGet (left, offset, FALSE, FALSE);
7834       MOVA (l);
7835       if (size == 0) { /* special case for 1 byte */
7836               emitcode("rl","a");
7837               goto release;
7838       }
7839       emitcode("rlc","a"); /* bit0 will be written later */
7840       if (AOP_SIZE (result) > 1)
7841         {
7842           aopPut (result, "a", offset++);
7843         }
7844
7845       while (size--)
7846         {
7847           l = aopGet (left, offset, FALSE, FALSE);
7848           MOVA (l);
7849           emitcode ("rlc", "a");
7850           if (AOP_SIZE (result) > 1)
7851             aopPut (result, "a", offset++);
7852         }
7853     }
7854   /* now we need to put the carry into the
7855      highest order byte of the result */
7856   if (AOP_SIZE (result) > 1)
7857     {
7858       l = aopGet (result, 0, FALSE, FALSE);
7859       MOVA (l);
7860     }
7861   emitcode ("mov", "acc.0,c");
7862  release:
7863   aopPut (result, "a", 0);
7864   freeAsmop (result, NULL, ic, TRUE);
7865   freeAsmop (left, NULL, ic, TRUE);
7866 }
7867
7868 /*-----------------------------------------------------------------*/
7869 /* genGetHbit - generates code get highest order bit               */
7870 /*-----------------------------------------------------------------*/
7871 static void
7872 genGetHbit (iCode * ic)
7873 {
7874   operand *left, *result;
7875
7876   D (emitcode (";", "genGetHbit"));
7877
7878   left = IC_LEFT (ic);
7879   result = IC_RESULT (ic);
7880   aopOp (left, ic, FALSE);
7881   aopOp (result, ic, FALSE);
7882
7883   /* get the highest order byte into a */
7884   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7885   if (AOP_TYPE (result) == AOP_CRY)
7886     {
7887       emitcode ("rlc", "a");
7888       outBitC (result);
7889     }
7890   else
7891     {
7892       emitcode ("rl", "a");
7893       emitcode ("anl", "a,#0x01");
7894       outAcc (result);
7895     }
7896
7897   freeAsmop (result, NULL, ic, TRUE);
7898   freeAsmop (left, NULL, ic, TRUE);
7899 }
7900
7901 /*-----------------------------------------------------------------*/
7902 /* genGetAbit - generates code get a single bit                    */
7903 /*-----------------------------------------------------------------*/
7904 static void
7905 genGetAbit (iCode * ic)
7906 {
7907   operand *left, *right, *result;
7908   int shCount;
7909
7910   D (emitcode (";", "genGetAbit"));
7911
7912   left = IC_LEFT (ic);
7913   right = IC_RIGHT (ic);
7914   result = IC_RESULT (ic);
7915   aopOp (left, ic, FALSE);
7916   aopOp (right, ic, FALSE);
7917   aopOp (result, ic, FALSE);
7918
7919   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7920
7921   /* get the needed byte into a */
7922   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7923   shCount %= 8;
7924   if (AOP_TYPE (result) == AOP_CRY)
7925     {
7926       if ((shCount) == 7)
7927           emitcode ("rlc", "a");
7928       else if ((shCount) == 0)
7929           emitcode ("rrc", "a");
7930       else
7931           emitcode ("mov", "c,acc[%d]", shCount);
7932       outBitC (result);
7933     }
7934   else
7935     {
7936       switch (shCount)
7937         {
7938         case 2:
7939           emitcode ("rr", "a");
7940           //fallthrough
7941         case 1:
7942           emitcode ("rr", "a");
7943           //fallthrough
7944         case 0:
7945           emitcode ("anl", "a,#0x01");
7946           break;
7947         case 3:
7948         case 5:
7949           emitcode ("mov", "c,acc[%d]", shCount);
7950           emitcode ("clr", "a");
7951           emitcode ("rlc", "a");
7952           break;
7953         case 4:
7954           emitcode ("swap", "a");
7955           emitcode ("anl", "a,#0x01");
7956           break;
7957         case 6:
7958           emitcode ("rl", "a");
7959           //fallthrough
7960         case 7:
7961           emitcode ("rl", "a");
7962           emitcode ("anl", "a,#0x01");
7963           break;
7964         }
7965       outAcc (result);
7966     }
7967
7968   freeAsmop (result, NULL, ic, TRUE);
7969   freeAsmop (right, NULL, ic, TRUE);
7970   freeAsmop (left, NULL, ic, TRUE);
7971 }
7972
7973 /*-----------------------------------------------------------------*/
7974 /* genGetByte - generates code get a single byte                   */
7975 /*-----------------------------------------------------------------*/
7976 static void
7977 genGetByte (iCode * ic)
7978 {
7979   operand *left, *right, *result;
7980   int offset;
7981
7982   D (emitcode (";", "genGetByte"));
7983
7984   left = IC_LEFT (ic);
7985   right = IC_RIGHT (ic);
7986   result = IC_RESULT (ic);
7987   aopOp (left, ic, FALSE);
7988   aopOp (right, ic, FALSE);
7989   aopOp (result, ic, FALSE);
7990
7991   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
7992   aopPut (result,
7993           aopGet (left, offset, FALSE, FALSE),
7994           0);
7995
7996   freeAsmop (result, NULL, ic, TRUE);
7997   freeAsmop (right, NULL, ic, TRUE);
7998   freeAsmop (left, NULL, ic, TRUE);
7999 }
8000
8001 /*-----------------------------------------------------------------*/
8002 /* genGetWord - generates code get two bytes                       */
8003 /*-----------------------------------------------------------------*/
8004 static void
8005 genGetWord (iCode * ic)
8006 {
8007   operand *left, *right, *result;
8008   int offset;
8009
8010   D (emitcode (";", "genGetWord"));
8011
8012   left = IC_LEFT (ic);
8013   right = IC_RIGHT (ic);
8014   result = IC_RESULT (ic);
8015   aopOp (left, ic, FALSE);
8016   aopOp (right, ic, FALSE);
8017   aopOp (result, ic, FALSE);
8018
8019   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8020   aopPut (result,
8021           aopGet (left, offset, FALSE, FALSE),
8022           0);
8023   aopPut (result,
8024           aopGet (left, offset+1, FALSE, FALSE),
8025           1);
8026
8027   freeAsmop (result, NULL, ic, TRUE);
8028   freeAsmop (right, NULL, ic, TRUE);
8029   freeAsmop (left, NULL, ic, TRUE);
8030 }
8031
8032 /*-----------------------------------------------------------------*/
8033 /* genSwap - generates code to swap nibbles or bytes               */
8034 /*-----------------------------------------------------------------*/
8035 static void
8036 genSwap (iCode * ic)
8037 {
8038   operand *left, *result;
8039
8040   D(emitcode (";", "genSwap"));
8041
8042   left = IC_LEFT (ic);
8043   result = IC_RESULT (ic);
8044   aopOp (left, ic, FALSE);
8045   aopOp (result, ic, FALSE);
8046
8047   switch (AOP_SIZE (left))
8048     {
8049     case 1: /* swap nibbles in byte */
8050       MOVA (aopGet (left, 0, FALSE, FALSE));
8051       emitcode ("swap", "a");
8052       aopPut (result, "a", 0);
8053       break;
8054     case 2: /* swap bytes in word */
8055       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8056         {
8057           MOVA (aopGet (left, 0, FALSE, FALSE));
8058           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8059           aopPut (result, "a", 1);
8060         }
8061       else if (operandsEqu (left, result))
8062         {
8063           char * reg = "a";
8064           bool pushedB = FALSE, leftInB = FALSE;
8065
8066           MOVA (aopGet (left, 0, FALSE, FALSE));
8067           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8068             {
8069               pushedB = pushB ();
8070               emitcode ("mov", "b,a");
8071               reg = "b";
8072               leftInB = TRUE;
8073             }
8074           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8075           aopPut (result, reg, 1);
8076
8077           if (leftInB)
8078             popB (pushedB);
8079         }
8080       else
8081         {
8082           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8083           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8084         }
8085       break;
8086     default:
8087       wassertl(FALSE, "unsupported SWAP operand size");
8088     }
8089
8090   freeAsmop (result, NULL, ic, TRUE);
8091   freeAsmop (left, NULL, ic, TRUE);
8092 }
8093
8094 /*-----------------------------------------------------------------*/
8095 /* AccRol - rotate left accumulator by known count                 */
8096 /*-----------------------------------------------------------------*/
8097 static void
8098 AccRol (int shCount)
8099 {
8100   shCount &= 0x0007;            // shCount : 0..7
8101
8102   switch (shCount)
8103     {
8104     case 0:
8105       break;
8106     case 1:
8107       emitcode ("rl", "a");
8108       break;
8109     case 2:
8110       emitcode ("rl", "a");
8111       emitcode ("rl", "a");
8112       break;
8113     case 3:
8114       emitcode ("swap", "a");
8115       emitcode ("rr", "a");
8116       break;
8117     case 4:
8118       emitcode ("swap", "a");
8119       break;
8120     case 5:
8121       emitcode ("swap", "a");
8122       emitcode ("rl", "a");
8123       break;
8124     case 6:
8125       emitcode ("rr", "a");
8126       emitcode ("rr", "a");
8127       break;
8128     case 7:
8129       emitcode ("rr", "a");
8130       break;
8131     }
8132 }
8133
8134 /*-----------------------------------------------------------------*/
8135 /* AccLsh - left shift accumulator by known count                  */
8136 /*-----------------------------------------------------------------*/
8137 static void
8138 AccLsh (int shCount)
8139 {
8140   if (shCount != 0)
8141     {
8142       if (shCount == 1)
8143         emitcode ("add", "a,acc");
8144       else if (shCount == 2)
8145         {
8146           emitcode ("add", "a,acc");
8147           emitcode ("add", "a,acc");
8148         }
8149       else
8150         {
8151           /* rotate left accumulator */
8152           AccRol (shCount);
8153           /* and kill the lower order bits */
8154           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8155         }
8156     }
8157 }
8158
8159 /*-----------------------------------------------------------------*/
8160 /* AccRsh - right shift accumulator by known count                 */
8161 /*-----------------------------------------------------------------*/
8162 static void
8163 AccRsh (int shCount)
8164 {
8165   if (shCount != 0)
8166     {
8167       if (shCount == 1)
8168         {
8169           CLRC;
8170           emitcode ("rrc", "a");
8171         }
8172       else
8173         {
8174           /* rotate right accumulator */
8175           AccRol (8 - shCount);
8176           /* and kill the higher order bits */
8177           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8178         }
8179     }
8180 }
8181
8182 /*-----------------------------------------------------------------*/
8183 /* AccSRsh - signed right shift accumulator by known count                 */
8184 /*-----------------------------------------------------------------*/
8185 static void
8186 AccSRsh (int shCount)
8187 {
8188   symbol *tlbl;
8189   if (shCount != 0)
8190     {
8191       if (shCount == 1)
8192         {
8193           emitcode ("mov", "c,acc.7");
8194           emitcode ("rrc", "a");
8195         }
8196       else if (shCount == 2)
8197         {
8198           emitcode ("mov", "c,acc.7");
8199           emitcode ("rrc", "a");
8200           emitcode ("mov", "c,acc.7");
8201           emitcode ("rrc", "a");
8202         }
8203       else
8204         {
8205           tlbl = newiTempLabel (NULL);
8206           /* rotate right accumulator */
8207           AccRol (8 - shCount);
8208           /* and kill the higher order bits */
8209           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8210           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8211           emitcode ("orl", "a,#0x%02x",
8212                     (unsigned char) ~SRMask[shCount]);
8213           emitLabel (tlbl);
8214         }
8215     }
8216 }
8217
8218 /*-----------------------------------------------------------------*/
8219 /* shiftR1Left2Result - shift right one byte from left to result   */
8220 /*-----------------------------------------------------------------*/
8221 static void
8222 shiftR1Left2Result (operand * left, int offl,
8223                     operand * result, int offr,
8224                     int shCount, int sign)
8225 {
8226   MOVA (aopGet (left, offl, FALSE, FALSE));
8227   /* shift right accumulator */
8228   if (sign)
8229     AccSRsh (shCount);
8230   else
8231     AccRsh (shCount);
8232   aopPut (result, "a", offr);
8233 }
8234
8235 /*-----------------------------------------------------------------*/
8236 /* shiftL1Left2Result - shift left one byte from left to result    */
8237 /*-----------------------------------------------------------------*/
8238 static void
8239 shiftL1Left2Result (operand * left, int offl,
8240                     operand * result, int offr, int shCount)
8241 {
8242   char *l;
8243   l = aopGet (left, offl, FALSE, FALSE);
8244   MOVA (l);
8245   /* shift left accumulator */
8246   AccLsh (shCount);
8247   aopPut (result, "a", offr);
8248 }
8249
8250 /*-----------------------------------------------------------------*/
8251 /* movLeft2Result - move byte from left to result                  */
8252 /*-----------------------------------------------------------------*/
8253 static void
8254 movLeft2Result (operand * left, int offl,
8255                 operand * result, int offr, int sign)
8256 {
8257   char *l;
8258   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8259     {
8260       l = aopGet (left, offl, FALSE, FALSE);
8261
8262       if (*l == '@' && (IS_AOP_PREG (result)))
8263         {
8264           emitcode ("mov", "a,%s", l);
8265           aopPut (result, "a", offr);
8266         }
8267       else
8268         {
8269           if (!sign)
8270             {
8271               aopPut (result, l, offr);
8272             }
8273           else
8274             {
8275               /* MSB sign in acc.7 ! */
8276               if (getDataSize (left) == offl + 1)
8277                 {
8278                   MOVA (l);
8279                   aopPut (result, "a", offr);
8280                 }
8281             }
8282         }
8283     }
8284 }
8285
8286 /*-----------------------------------------------------------------*/
8287 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8288 /*-----------------------------------------------------------------*/
8289 static void
8290 AccAXRrl1 (char *x)
8291 {
8292   emitcode ("rrc", "a");
8293   emitcode ("xch", "a,%s", x);
8294   emitcode ("rrc", "a");
8295   emitcode ("xch", "a,%s", x);
8296 }
8297
8298 /*-----------------------------------------------------------------*/
8299 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8300 /*-----------------------------------------------------------------*/
8301 static void
8302 AccAXLrl1 (char *x)
8303 {
8304   emitcode ("xch", "a,%s", x);
8305   emitcode ("rlc", "a");
8306   emitcode ("xch", "a,%s", x);
8307   emitcode ("rlc", "a");
8308 }
8309
8310 /*-----------------------------------------------------------------*/
8311 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8312 /*-----------------------------------------------------------------*/
8313 static void
8314 AccAXLsh1 (char *x)
8315 {
8316   emitcode ("xch", "a,%s", x);
8317   emitcode ("add", "a,acc");
8318   emitcode ("xch", "a,%s", x);
8319   emitcode ("rlc", "a");
8320 }
8321
8322 /*-----------------------------------------------------------------*/
8323 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8324 /*-----------------------------------------------------------------*/
8325 static void
8326 AccAXLsh (char *x, int shCount)
8327 {
8328   switch (shCount)
8329     {
8330     case 0:
8331       break;
8332     case 1:
8333       AccAXLsh1 (x);
8334       break;
8335     case 2:
8336       AccAXLsh1 (x);
8337       AccAXLsh1 (x);
8338       break;
8339     case 3:
8340     case 4:
8341     case 5:                     // AAAAABBB:CCCCCDDD
8342
8343       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8344
8345       emitcode ("anl", "a,#0x%02x",
8346                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8347
8348       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8349
8350       AccRol (shCount);         // DDDCCCCC:BBB00000
8351
8352       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8353
8354       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8355
8356       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8357
8358       emitcode ("anl", "a,#0x%02x",
8359                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8360
8361       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8362
8363       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8364
8365       break;
8366     case 6:                     // AAAAAABB:CCCCCCDD
8367       emitcode ("anl", "a,#0x%02x",
8368                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8369       emitcode ("mov", "c,acc.0");      // c = B
8370       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8371 #if 0 // REMOVE ME
8372       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8373       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8374 #else
8375       emitcode("rrc","a");
8376       emitcode("xch","a,%s", x);
8377       emitcode("rrc","a");
8378       emitcode("mov","c,acc.0"); //<< get correct bit
8379       emitcode("xch","a,%s", x);
8380
8381       emitcode("rrc","a");
8382       emitcode("xch","a,%s", x);
8383       emitcode("rrc","a");
8384       emitcode("xch","a,%s", x);
8385 #endif
8386       break;
8387     case 7:                     // a:x <<= 7
8388
8389       emitcode ("anl", "a,#0x%02x",
8390                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8391
8392       emitcode ("mov", "c,acc.0");      // c = B
8393
8394       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8395
8396       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8397
8398       break;
8399     default:
8400       break;
8401     }
8402 }
8403
8404 /*-----------------------------------------------------------------*/
8405 /* AccAXRsh - right shift a:x known count (0..7)                   */
8406 /*-----------------------------------------------------------------*/
8407 static void
8408 AccAXRsh (char *x, int shCount)
8409 {
8410   switch (shCount)
8411     {
8412     case 0:
8413       break;
8414     case 1:
8415       CLRC;
8416       AccAXRrl1 (x);            // 0->a:x
8417
8418       break;
8419     case 2:
8420       CLRC;
8421       AccAXRrl1 (x);            // 0->a:x
8422
8423       CLRC;
8424       AccAXRrl1 (x);            // 0->a:x
8425
8426       break;
8427     case 3:
8428     case 4:
8429     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8430
8431       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8432
8433       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8434
8435       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8436
8437       emitcode ("anl", "a,#0x%02x",
8438                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8439
8440       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8441
8442       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8443
8444       emitcode ("anl", "a,#0x%02x",
8445                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8446
8447       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8448
8449       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8450
8451       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8452
8453       break;
8454     case 6:                     // AABBBBBB:CCDDDDDD
8455
8456       emitcode ("mov", "c,acc.7");
8457       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8458
8459       emitcode ("mov", "c,acc.7");
8460       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8461
8462       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8463
8464       emitcode ("anl", "a,#0x%02x",
8465                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8466
8467       break;
8468     case 7:                     // ABBBBBBB:CDDDDDDD
8469
8470       emitcode ("mov", "c,acc.7");      // c = A
8471
8472       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8473
8474       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8475
8476       emitcode ("anl", "a,#0x%02x",
8477                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8478
8479       break;
8480     default:
8481       break;
8482     }
8483 }
8484
8485 /*-----------------------------------------------------------------*/
8486 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8487 /*-----------------------------------------------------------------*/
8488 static void
8489 AccAXRshS (char *x, int shCount)
8490 {
8491   symbol *tlbl;
8492   switch (shCount)
8493     {
8494     case 0:
8495       break;
8496     case 1:
8497       emitcode ("mov", "c,acc.7");
8498       AccAXRrl1 (x);            // s->a:x
8499
8500       break;
8501     case 2:
8502       emitcode ("mov", "c,acc.7");
8503       AccAXRrl1 (x);            // s->a:x
8504
8505       emitcode ("mov", "c,acc.7");
8506       AccAXRrl1 (x);            // s->a:x
8507
8508       break;
8509     case 3:
8510     case 4:
8511     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8512
8513       tlbl = newiTempLabel (NULL);
8514       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8515
8516       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8517
8518       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8519
8520       emitcode ("anl", "a,#0x%02x",
8521                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8522
8523       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8524
8525       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8526
8527       emitcode ("anl", "a,#0x%02x",
8528                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8529
8530       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8531
8532       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8533
8534       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8535
8536       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8537       emitcode ("orl", "a,#0x%02x",
8538                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8539
8540       emitLabel (tlbl);
8541       break;                    // SSSSAAAA:BBBCCCCC
8542
8543     case 6:                     // AABBBBBB:CCDDDDDD
8544
8545       tlbl = newiTempLabel (NULL);
8546       emitcode ("mov", "c,acc.7");
8547       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8548
8549       emitcode ("mov", "c,acc.7");
8550       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8551
8552       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8553
8554       emitcode ("anl", "a,#0x%02x",
8555                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8556
8557       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8558       emitcode ("orl", "a,#0x%02x",
8559                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8560
8561       emitLabel (tlbl);
8562       break;
8563     case 7:                     // ABBBBBBB:CDDDDDDD
8564
8565       tlbl = newiTempLabel (NULL);
8566       emitcode ("mov", "c,acc.7");      // c = A
8567
8568       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8569
8570       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8571
8572       emitcode ("anl", "a,#0x%02x",
8573                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8574
8575       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8576       emitcode ("orl", "a,#0x%02x",
8577                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8578
8579       emitLabel (tlbl);
8580       break;
8581     default:
8582       break;
8583     }
8584 }
8585
8586 /*-----------------------------------------------------------------*/
8587 /* shiftL2Left2Result - shift left two bytes from left to result   */
8588 /*-----------------------------------------------------------------*/
8589 static void
8590 shiftL2Left2Result (operand * left, int offl,
8591                     operand * result, int offr, int shCount)
8592 {
8593   char * x;
8594   bool pushedB = FALSE;
8595   bool usedB = FALSE;
8596
8597   if (sameRegs (AOP (result), AOP (left)) &&
8598       ((offl + MSB16) == offr))
8599     {
8600       /* don't crash result[offr] */
8601       MOVA (aopGet (left, offl, FALSE, FALSE));
8602       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8603       usedB = !strncmp(x, "b", 1);
8604     }
8605   else if (aopGetUsesAcc (result, offr))
8606     {
8607       movLeft2Result (left, offl, result, offr, 0);
8608       pushedB = pushB ();
8609       usedB = TRUE;
8610       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8611       MOVA (aopGet (result, offr, FALSE, FALSE));
8612       emitcode ("xch", "a,b");
8613       x = "b";
8614     }
8615   else
8616     {
8617       movLeft2Result (left, offl, result, offr, 0);
8618       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8619       x = aopGet (result, offr, FALSE, FALSE);
8620     }
8621   /* ax << shCount (x = lsb(result)) */
8622   AccAXLsh (x, shCount);
8623   if (usedB)
8624     {
8625       emitcode ("xch", "a,b");
8626       aopPut (result, "a", offr);
8627       aopPut (result, "b", offr + MSB16);
8628       popB (pushedB);
8629     }
8630   else
8631     {
8632       aopPut (result, "a", offr + MSB16);
8633     }
8634 }
8635
8636
8637 /*-----------------------------------------------------------------*/
8638 /* shiftR2Left2Result - shift right two bytes from left to result  */
8639 /*-----------------------------------------------------------------*/
8640 static void
8641 shiftR2Left2Result (operand * left, int offl,
8642                     operand * result, int offr,
8643                     int shCount, int sign)
8644 {
8645   char * x;
8646   bool pushedB = FALSE;
8647   bool usedB = FALSE;
8648
8649   if (sameRegs (AOP (result), AOP (left)) &&
8650       ((offl + MSB16) == offr))
8651     {
8652       /* don't crash result[offr] */
8653       MOVA (aopGet (left, offl, FALSE, FALSE));
8654       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8655       usedB = !strncmp(x, "b", 1);
8656     }
8657   else if (aopGetUsesAcc (result, offr))
8658     {
8659       movLeft2Result (left, offl, result, offr, 0);
8660       pushedB = pushB ();
8661       usedB = TRUE;
8662       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8663       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8664       x = "b";
8665     }
8666   else
8667     {
8668       movLeft2Result (left, offl, result, offr, 0);
8669       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8670       x = aopGet (result, offr, FALSE, FALSE);
8671     }
8672   /* a:x >> shCount (x = lsb(result)) */
8673   if (sign)
8674     AccAXRshS (x, shCount);
8675   else
8676     AccAXRsh (x, shCount);
8677   if (usedB)
8678     {
8679       emitcode ("xch", "a,b");
8680       aopPut (result, "a", offr);
8681       emitcode ("xch", "a,b");
8682       popB (pushedB);
8683     }
8684   if (getDataSize (result) > 1)
8685     aopPut (result, "a", offr + MSB16);
8686 }
8687
8688 /*-----------------------------------------------------------------*/
8689 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8690 /*-----------------------------------------------------------------*/
8691 static void
8692 shiftLLeftOrResult (operand * left, int offl,
8693                     operand * result, int offr, int shCount)
8694 {
8695   MOVA (aopGet (left, offl, FALSE, FALSE));
8696   /* shift left accumulator */
8697   AccLsh (shCount);
8698   /* or with result */
8699   if (aopGetUsesAcc (result, offr))
8700     {
8701       emitcode ("xch", "a,b");
8702       MOVA (aopGet (result, offr, FALSE, FALSE));
8703       emitcode ("orl", "a,b");
8704     }
8705   else
8706     {
8707       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8708     }
8709   /* back to result */
8710   aopPut (result, "a", offr);
8711 }
8712
8713 /*-----------------------------------------------------------------*/
8714 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8715 /*-----------------------------------------------------------------*/
8716 static void
8717 shiftRLeftOrResult (operand * left, int offl,
8718                     operand * result, int offr, int shCount)
8719 {
8720   MOVA (aopGet (left, offl, FALSE, FALSE));
8721   /* shift right accumulator */
8722   AccRsh (shCount);
8723   /* or with result */
8724   if (aopGetUsesAcc(result, offr))
8725     {
8726       emitcode ("xch", "a,b");
8727       MOVA (aopGet (result, offr, FALSE, FALSE));
8728       emitcode ("orl", "a,b");
8729     }
8730   else
8731     {
8732       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8733     }
8734   /* back to result */
8735   aopPut (result, "a", offr);
8736 }
8737
8738 /*-----------------------------------------------------------------*/
8739 /* genlshOne - left shift a one byte quantity by known count       */
8740 /*-----------------------------------------------------------------*/
8741 static void
8742 genlshOne (operand * result, operand * left, int shCount)
8743 {
8744   D (emitcode (";", "genlshOne"));
8745
8746   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8747 }
8748
8749 /*-----------------------------------------------------------------*/
8750 /* genlshTwo - left shift two bytes by known amount != 0           */
8751 /*-----------------------------------------------------------------*/
8752 static void
8753 genlshTwo (operand * result, operand * left, int shCount)
8754 {
8755   int size;
8756
8757   D (emitcode (";", "genlshTwo"));
8758
8759   size = getDataSize (result);
8760
8761   /* if shCount >= 8 */
8762   if (shCount >= 8)
8763     {
8764       shCount -= 8;
8765
8766       if (size > 1)
8767         {
8768           if (shCount)
8769             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8770           else
8771             movLeft2Result (left, LSB, result, MSB16, 0);
8772         }
8773       aopPut (result, zero, LSB);
8774     }
8775
8776   /*  1 <= shCount <= 7 */
8777   else
8778     {
8779       if (size == 1)
8780         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8781       else
8782         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8783     }
8784 }
8785
8786 /*-----------------------------------------------------------------*/
8787 /* shiftLLong - shift left one long from left to result            */
8788 /* offl = LSB or MSB16                                             */
8789 /*-----------------------------------------------------------------*/
8790 static void
8791 shiftLLong (operand * left, operand * result, int offr)
8792 {
8793   char *l;
8794   int size = AOP_SIZE (result);
8795
8796   if (size >= LSB + offr)
8797     {
8798       l = aopGet (left, LSB, FALSE, FALSE);
8799       MOVA (l);
8800       emitcode ("add", "a,acc");
8801       if (sameRegs (AOP (left), AOP (result)) &&
8802           size >= MSB16 + offr && offr != LSB)
8803         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8804       else
8805         aopPut (result, "a", LSB + offr);
8806     }
8807
8808   if (size >= MSB16 + offr)
8809     {
8810       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8811         {
8812           l = aopGet (left, MSB16, FALSE, FALSE);
8813           MOVA (l);
8814         }
8815       emitcode ("rlc", "a");
8816       if (sameRegs (AOP (left), AOP (result)) &&
8817           size >= MSB24 + offr && offr != LSB)
8818         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8819       else
8820         aopPut (result, "a", MSB16 + offr);
8821     }
8822
8823   if (size >= MSB24 + offr)
8824     {
8825       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8826         {
8827           l = aopGet (left, MSB24, FALSE, FALSE);
8828           MOVA (l);
8829         }
8830       emitcode ("rlc", "a");
8831       if (sameRegs (AOP (left), AOP (result)) &&
8832           size >= MSB32 + offr && offr != LSB)
8833         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8834       else
8835         aopPut (result, "a", MSB24 + offr);
8836     }
8837
8838   if (size > MSB32 + offr)
8839     {
8840       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8841         {
8842           l = aopGet (left, MSB32, FALSE, FALSE);
8843           MOVA (l);
8844         }
8845       emitcode ("rlc", "a");
8846       aopPut (result, "a", MSB32 + offr);
8847     }
8848   if (offr != LSB)
8849     aopPut (result, zero, LSB);
8850 }
8851
8852 /*-----------------------------------------------------------------*/
8853 /* genlshFour - shift four byte by a known amount != 0             */
8854 /*-----------------------------------------------------------------*/
8855 static void
8856 genlshFour (operand * result, operand * left, int shCount)
8857 {
8858   int size;
8859
8860   D (emitcode (";", "genlshFour"));
8861
8862   size = AOP_SIZE (result);
8863
8864   /* if shifting more that 3 bytes */
8865   if (shCount >= 24)
8866     {
8867       shCount -= 24;
8868       if (shCount)
8869         /* lowest order of left goes to the highest
8870            order of the destination */
8871         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8872       else
8873         movLeft2Result (left, LSB, result, MSB32, 0);
8874       aopPut (result, zero, LSB);
8875       aopPut (result, zero, MSB16);
8876       aopPut (result, zero, MSB24);
8877       return;
8878     }
8879
8880   /* more than two bytes */
8881   else if (shCount >= 16)
8882     {
8883       /* lower order two bytes goes to higher order two bytes */
8884       shCount -= 16;
8885       /* if some more remaining */
8886       if (shCount)
8887         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8888       else
8889         {
8890           movLeft2Result (left, MSB16, result, MSB32, 0);
8891           movLeft2Result (left, LSB, result, MSB24, 0);
8892         }
8893       aopPut (result, zero, MSB16);
8894       aopPut (result, zero, LSB);
8895       return;
8896     }
8897
8898   /* if more than 1 byte */
8899   else if (shCount >= 8)
8900     {
8901       /* lower order three bytes goes to higher order  three bytes */
8902       shCount -= 8;
8903       if (size == 2)
8904         {
8905           if (shCount)
8906             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8907           else
8908             movLeft2Result (left, LSB, result, MSB16, 0);
8909         }
8910       else
8911         {                       /* size = 4 */
8912           if (shCount == 0)
8913             {
8914               movLeft2Result (left, MSB24, result, MSB32, 0);
8915               movLeft2Result (left, MSB16, result, MSB24, 0);
8916               movLeft2Result (left, LSB, result, MSB16, 0);
8917               aopPut (result, zero, LSB);
8918             }
8919           else if (shCount == 1)
8920             shiftLLong (left, result, MSB16);
8921           else
8922             {
8923               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8924               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8925               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8926               aopPut (result, zero, LSB);
8927             }
8928         }
8929     }
8930
8931   /* 1 <= shCount <= 7 */
8932   else if (shCount <= 2)
8933     {
8934       shiftLLong (left, result, LSB);
8935       if (shCount == 2)
8936         shiftLLong (result, result, LSB);
8937     }
8938   /* 3 <= shCount <= 7, optimize */
8939   else
8940     {
8941       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8942       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8943       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8944     }
8945 }
8946
8947 /*-----------------------------------------------------------------*/
8948 /* genLeftShiftLiteral - left shifting by known count              */
8949 /*-----------------------------------------------------------------*/
8950 static void
8951 genLeftShiftLiteral (operand * left,
8952                      operand * right,
8953                      operand * result,
8954                      iCode * ic)
8955 {
8956   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
8957   int size;
8958
8959   D (emitcode (";", "genLeftShiftLiteral"));
8960
8961   freeAsmop (right, NULL, ic, TRUE);
8962
8963   aopOp (left, ic, FALSE);
8964   aopOp (result, ic, FALSE);
8965
8966   size = getSize (operandType (result));
8967
8968 #if VIEW_SIZE
8969   emitcode ("; shift left ", "result %d, left %d", size,
8970             AOP_SIZE (left));
8971 #endif
8972
8973   /* I suppose that the left size >= result size */
8974   if (shCount == 0)
8975     {
8976       while (size--)
8977         {
8978           movLeft2Result (left, size, result, size, 0);
8979         }
8980     }
8981   else if (shCount >= (size * 8))
8982     {
8983       while (size--)
8984         {
8985           aopPut (result, zero, size);
8986         }
8987     }
8988   else
8989     {
8990       switch (size)
8991         {
8992         case 1:
8993           genlshOne (result, left, shCount);
8994           break;
8995
8996         case 2:
8997           genlshTwo (result, left, shCount);
8998           break;
8999
9000         case 4:
9001           genlshFour (result, left, shCount);
9002           break;
9003         default:
9004           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9005                   "*** ack! mystery literal shift!\n");
9006           break;
9007         }
9008     }
9009   freeAsmop (result, NULL, ic, TRUE);
9010   freeAsmop (left, NULL, ic, TRUE);
9011 }
9012
9013 /*-----------------------------------------------------------------*/
9014 /* genLeftShift - generates code for left shifting                 */
9015 /*-----------------------------------------------------------------*/
9016 static void
9017 genLeftShift (iCode * ic)
9018 {
9019   operand *left, *right, *result;
9020   int size, offset;
9021   char *l;
9022   symbol *tlbl, *tlbl1;
9023   bool pushedB;
9024
9025   D (emitcode (";", "genLeftShift"));
9026
9027   right = IC_RIGHT (ic);
9028   left = IC_LEFT (ic);
9029   result = IC_RESULT (ic);
9030
9031   aopOp (right, ic, FALSE);
9032
9033   /* if the shift count is known then do it
9034      as efficiently as possible */
9035   if (AOP_TYPE (right) == AOP_LIT)
9036     {
9037       genLeftShiftLiteral (left, right, result, ic);
9038       return;
9039     }
9040
9041   /* shift count is unknown then we have to form
9042      a loop get the loop count in B : Note: we take
9043      only the lower order byte since shifting
9044      more that 32 bits make no sense anyway, ( the
9045      largest size of an object can be only 32 bits ) */
9046
9047   pushedB = pushB ();
9048   MOVB (aopGet (right, 0, FALSE, FALSE));
9049   emitcode ("inc", "b");
9050   freeAsmop (right, NULL, ic, TRUE);
9051   aopOp (left, ic, FALSE);
9052   aopOp (result, ic, FALSE);
9053
9054   /* now move the left to the result if they are not the same */
9055   if (!sameRegs (AOP (left), AOP (result)) &&
9056       AOP_SIZE (result) > 1)
9057     {
9058
9059       size = AOP_SIZE (result);
9060       offset = 0;
9061       while (size--)
9062         {
9063           l = aopGet (left, offset, FALSE, TRUE);
9064           if (*l == '@' && (IS_AOP_PREG (result)))
9065             {
9066
9067               emitcode ("mov", "a,%s", l);
9068               aopPut (result, "a", offset);
9069             }
9070           else
9071             aopPut (result, l, offset);
9072           offset++;
9073         }
9074     }
9075
9076   tlbl = newiTempLabel (NULL);
9077   size = AOP_SIZE (result);
9078   offset = 0;
9079   tlbl1 = newiTempLabel (NULL);
9080
9081   /* if it is only one byte then */
9082   if (size == 1)
9083     {
9084       symbol *tlbl1 = newiTempLabel (NULL);
9085
9086       l = aopGet (left, 0, FALSE, FALSE);
9087       MOVA (l);
9088       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9089       emitLabel (tlbl);
9090       emitcode ("add", "a,acc");
9091       emitLabel (tlbl1);
9092       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9093       popB (pushedB);
9094       aopPut (result, "a", 0);
9095       goto release;
9096     }
9097
9098   reAdjustPreg (AOP (result));
9099
9100   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9101   emitLabel (tlbl);
9102   l = aopGet (result, offset, FALSE, FALSE);
9103   MOVA (l);
9104   emitcode ("add", "a,acc");
9105   aopPut (result, "a", offset++);
9106   while (--size)
9107     {
9108       l = aopGet (result, offset, FALSE, FALSE);
9109       MOVA (l);
9110       emitcode ("rlc", "a");
9111       aopPut (result, "a", offset++);
9112     }
9113   reAdjustPreg (AOP (result));
9114
9115   emitLabel (tlbl1);
9116   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9117   popB (pushedB);
9118 release:
9119   freeAsmop (result, NULL, ic, TRUE);
9120   freeAsmop (left, NULL, ic, TRUE);
9121 }
9122
9123 /*-----------------------------------------------------------------*/
9124 /* genrshOne - right shift a one byte quantity by known count      */
9125 /*-----------------------------------------------------------------*/
9126 static void
9127 genrshOne (operand * result, operand * left,
9128            int shCount, int sign)
9129 {
9130   D (emitcode (";", "genrshOne"));
9131
9132   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9133 }
9134
9135 /*-----------------------------------------------------------------*/
9136 /* genrshTwo - right shift two bytes by known amount != 0          */
9137 /*-----------------------------------------------------------------*/
9138 static void
9139 genrshTwo (operand * result, operand * left,
9140            int shCount, int sign)
9141 {
9142   D (emitcode (";", "genrshTwo"));
9143
9144   /* if shCount >= 8 */
9145   if (shCount >= 8)
9146     {
9147       shCount -= 8;
9148       if (shCount)
9149         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9150       else
9151         movLeft2Result (left, MSB16, result, LSB, sign);
9152       addSign (result, MSB16, sign);
9153     }
9154
9155   /*  1 <= shCount <= 7 */
9156   else
9157     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9158 }
9159
9160 /*-----------------------------------------------------------------*/
9161 /* shiftRLong - shift right one long from left to result           */
9162 /* offl = LSB or MSB16                                             */
9163 /*-----------------------------------------------------------------*/
9164 static void
9165 shiftRLong (operand * left, int offl,
9166             operand * result, int sign)
9167 {
9168   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9169
9170   if (overlapping && offl>1)
9171     {
9172       // we are in big trouble, but this shouldn't happen
9173       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9174     }
9175
9176   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9177
9178   if (offl==MSB16)
9179     {
9180       // shift is > 8
9181       if (sign)
9182         {
9183           emitcode ("rlc", "a");
9184           emitcode ("subb", "a,acc");
9185           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9186             {
9187               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9188             }
9189           else
9190             {
9191               aopPut (result, "a", MSB32);
9192               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9193             }
9194         }
9195       else
9196         {
9197           if (aopPutUsesAcc (result, zero, MSB32))
9198             {
9199               emitcode("xch", "a,b");
9200               aopPut (result, zero, MSB32);
9201               emitcode("xch", "a,b");
9202             }
9203           else
9204             {
9205               aopPut (result, zero, MSB32);
9206             }
9207         }
9208     }
9209
9210   if (!sign)
9211     {
9212       emitcode ("clr", "c");
9213     }
9214   else
9215     {
9216       emitcode ("mov", "c,acc.7");
9217     }
9218
9219   emitcode ("rrc", "a");
9220
9221   if (overlapping && offl==MSB16 &&
9222       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9223     {
9224       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9225     }
9226   else
9227     {
9228       aopPut (result, "a", MSB32 - offl);
9229       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9230     }
9231
9232   emitcode ("rrc", "a");
9233   if (overlapping && offl==MSB16 &&
9234       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9235     {
9236       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9237     }
9238   else
9239     {
9240       aopPut (result, "a", MSB24 - offl);
9241       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9242     }
9243
9244   emitcode ("rrc", "a");
9245   if (offl != LSB)
9246     {
9247       aopPut (result, "a", MSB16 - offl);
9248     }
9249   else
9250     {
9251       if (overlapping &&
9252           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9253         {
9254           xch_a_aopGet (left, LSB, FALSE, FALSE);
9255         }
9256       else
9257         {
9258           aopPut (result, "a", MSB16 - offl);
9259           MOVA (aopGet (left, LSB, FALSE, FALSE));
9260         }
9261       emitcode ("rrc", "a");
9262       aopPut (result, "a", LSB);
9263     }
9264 }
9265
9266 /*-----------------------------------------------------------------*/
9267 /* genrshFour - shift four byte by a known amount != 0             */
9268 /*-----------------------------------------------------------------*/
9269 static void
9270 genrshFour (operand * result, operand * left,
9271             int shCount, int sign)
9272 {
9273   D (emitcode (";", "genrshFour"));
9274
9275   /* if shifting more that 3 bytes */
9276   if (shCount >= 24)
9277     {
9278       shCount -= 24;
9279       if (shCount)
9280         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9281       else
9282         movLeft2Result (left, MSB32, result, LSB, sign);
9283       addSign (result, MSB16, sign);
9284     }
9285   else if (shCount >= 16)
9286     {
9287       shCount -= 16;
9288       if (shCount)
9289         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9290       else
9291         {
9292           movLeft2Result (left, MSB24, result, LSB, 0);
9293           movLeft2Result (left, MSB32, result, MSB16, sign);
9294         }
9295       addSign (result, MSB24, sign);
9296     }
9297   else if (shCount >= 8)
9298     {
9299       shCount -= 8;
9300       if (shCount == 1)
9301         {
9302           shiftRLong (left, MSB16, result, sign);
9303         }
9304       else if (shCount == 0)
9305         {
9306           movLeft2Result (left, MSB16, result, LSB, 0);
9307           movLeft2Result (left, MSB24, result, MSB16, 0);
9308           movLeft2Result (left, MSB32, result, MSB24, sign);
9309           addSign (result, MSB32, sign);
9310         }
9311       else
9312         {
9313           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9314           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9315           /* the last shift is signed */
9316           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9317           addSign (result, MSB32, sign);
9318         }
9319     }
9320   else
9321     {
9322       /* 1 <= shCount <= 7 */
9323       if (shCount <= 2)
9324         {
9325           shiftRLong (left, LSB, result, sign);
9326           if (shCount == 2)
9327             shiftRLong (result, LSB, result, sign);
9328         }
9329       else
9330         {
9331           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9332           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9333           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9334         }
9335     }
9336 }
9337
9338 /*-----------------------------------------------------------------*/
9339 /* genRightShiftLiteral - right shifting by known count            */
9340 /*-----------------------------------------------------------------*/
9341 static void
9342 genRightShiftLiteral (operand * left,
9343                       operand * right,
9344                       operand * result,
9345                       iCode * ic,
9346                       int sign)
9347 {
9348   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9349   int size;
9350
9351   D (emitcode (";", "genRightShiftLiteral"));
9352
9353   freeAsmop (right, NULL, ic, TRUE);
9354
9355   aopOp (left, ic, FALSE);
9356   aopOp (result, ic, FALSE);
9357
9358 #if VIEW_SIZE
9359   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9360             AOP_SIZE (left));
9361 #endif
9362
9363   size = getDataSize (left);
9364   /* test the LEFT size !!! */
9365
9366   /* I suppose that the left size >= result size */
9367   if (shCount == 0)
9368     {
9369       size = getDataSize (result);
9370       while (size--)
9371         movLeft2Result (left, size, result, size, 0);
9372     }
9373
9374   else if (shCount >= (size * 8))
9375     {
9376       if (sign)
9377         {
9378           /* get sign in acc.7 */
9379           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9380         }
9381       addSign (result, LSB, sign);
9382     }
9383   else
9384     {
9385       switch (size)
9386         {
9387         case 1:
9388           genrshOne (result, left, shCount, sign);
9389           break;
9390
9391         case 2:
9392           genrshTwo (result, left, shCount, sign);
9393           break;
9394
9395         case 4:
9396           genrshFour (result, left, shCount, sign);
9397           break;
9398         default:
9399           break;
9400         }
9401     }
9402   freeAsmop (result, NULL, ic, TRUE);
9403   freeAsmop (left, NULL, ic, TRUE);
9404 }
9405
9406 /*-----------------------------------------------------------------*/
9407 /* genSignedRightShift - right shift of signed number              */
9408 /*-----------------------------------------------------------------*/
9409 static void
9410 genSignedRightShift (iCode * ic)
9411 {
9412   operand *right, *left, *result;
9413   int size, offset;
9414   char *l;
9415   symbol *tlbl, *tlbl1;
9416   bool pushedB;
9417
9418   D (emitcode (";", "genSignedRightShift"));
9419
9420   /* we do it the hard way put the shift count in b
9421      and loop thru preserving the sign */
9422
9423   right = IC_RIGHT (ic);
9424   left = IC_LEFT (ic);
9425   result = IC_RESULT (ic);
9426
9427   aopOp (right, ic, FALSE);
9428
9429
9430   if (AOP_TYPE (right) == AOP_LIT)
9431     {
9432       genRightShiftLiteral (left, right, result, ic, 1);
9433       return;
9434     }
9435   /* shift count is unknown then we have to form
9436      a loop get the loop count in B : Note: we take
9437      only the lower order byte since shifting
9438      more that 32 bits make no sense anyway, ( the
9439      largest size of an object can be only 32 bits ) */
9440
9441   pushedB = pushB ();
9442   MOVB (aopGet (right, 0, FALSE, FALSE));
9443   emitcode ("inc", "b");
9444   freeAsmop (right, NULL, ic, TRUE);
9445   aopOp (left, ic, FALSE);
9446   aopOp (result, ic, FALSE);
9447
9448   /* now move the left to the result if they are not the
9449      same */
9450   if (!sameRegs (AOP (left), AOP (result)) &&
9451       AOP_SIZE (result) > 1)
9452     {
9453
9454       size = AOP_SIZE (result);
9455       offset = 0;
9456       while (size--)
9457         {
9458           l = aopGet (left, offset, FALSE, TRUE);
9459           if (*l == '@' && IS_AOP_PREG (result))
9460             {
9461
9462               emitcode ("mov", "a,%s", l);
9463               aopPut (result, "a", offset);
9464             }
9465           else
9466             aopPut (result, l, offset);
9467           offset++;
9468         }
9469     }
9470
9471   /* mov the highest order bit to OVR */
9472   tlbl = newiTempLabel (NULL);
9473   tlbl1 = newiTempLabel (NULL);
9474
9475   size = AOP_SIZE (result);
9476   offset = size - 1;
9477   MOVA (aopGet (left, offset, FALSE, FALSE));
9478   emitcode ("rlc", "a");
9479   emitcode ("mov", "ov,c");
9480   /* if it is only one byte then */
9481   if (size == 1)
9482     {
9483       l = aopGet (left, 0, FALSE, FALSE);
9484       MOVA (l);
9485       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9486       emitLabel (tlbl);
9487       emitcode ("mov", "c,ov");
9488       emitcode ("rrc", "a");
9489       emitLabel (tlbl1);
9490       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9491       popB (pushedB);
9492       aopPut (result, "a", 0);
9493       goto release;
9494     }
9495
9496   reAdjustPreg (AOP (result));
9497   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9498   emitLabel (tlbl);
9499   emitcode ("mov", "c,ov");
9500   while (size--)
9501     {
9502       l = aopGet (result, offset, FALSE, FALSE);
9503       MOVA (l);
9504       emitcode ("rrc", "a");
9505       aopPut (result, "a", offset--);
9506     }
9507   reAdjustPreg (AOP (result));
9508   emitLabel (tlbl1);
9509   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9510   popB (pushedB);
9511
9512 release:
9513   freeAsmop (result, NULL, ic, TRUE);
9514   freeAsmop (left, NULL, ic, TRUE);
9515 }
9516
9517 /*-----------------------------------------------------------------*/
9518 /* genRightShift - generate code for right shifting                */
9519 /*-----------------------------------------------------------------*/
9520 static void
9521 genRightShift (iCode * ic)
9522 {
9523   operand *right, *left, *result;
9524   sym_link *letype;
9525   int size, offset;
9526   char *l;
9527   symbol *tlbl, *tlbl1;
9528   bool pushedB;
9529
9530   D (emitcode (";", "genRightShift"));
9531
9532   /* if signed then we do it the hard way preserve the
9533      sign bit moving it inwards */
9534   letype = getSpec (operandType (IC_LEFT (ic)));
9535
9536   if (!SPEC_USIGN (letype))
9537     {
9538       genSignedRightShift (ic);
9539       return;
9540     }
9541
9542   /* signed & unsigned types are treated the same : i.e. the
9543      signed is NOT propagated inwards : quoting from the
9544      ANSI - standard : "for E1 >> E2, is equivalent to division
9545      by 2**E2 if unsigned or if it has a non-negative value,
9546      otherwise the result is implementation defined ", MY definition
9547      is that the sign does not get propagated */
9548
9549   right = IC_RIGHT (ic);
9550   left = IC_LEFT (ic);
9551   result = IC_RESULT (ic);
9552
9553   aopOp (right, ic, FALSE);
9554
9555   /* if the shift count is known then do it
9556      as efficiently as possible */
9557   if (AOP_TYPE (right) == AOP_LIT)
9558     {
9559       genRightShiftLiteral (left, right, result, ic, 0);
9560       return;
9561     }
9562
9563   /* shift count is unknown then we have to form
9564      a loop get the loop count in B : Note: we take
9565      only the lower order byte since shifting
9566      more that 32 bits make no sense anyway, ( the
9567      largest size of an object can be only 32 bits ) */
9568
9569   pushedB = pushB ();
9570   MOVB (aopGet (right, 0, FALSE, FALSE));
9571   emitcode ("inc", "b");
9572   freeAsmop (right, NULL, ic, TRUE);
9573   aopOp (left, ic, FALSE);
9574   aopOp (result, ic, FALSE);
9575
9576   /* now move the left to the result if they are not the
9577      same */
9578   if (!sameRegs (AOP (left), AOP (result)) &&
9579       AOP_SIZE (result) > 1)
9580     {
9581       size = AOP_SIZE (result);
9582       offset = 0;
9583       while (size--)
9584         {
9585           l = aopGet (left, offset, FALSE, TRUE);
9586           if (*l == '@' && IS_AOP_PREG (result))
9587             {
9588
9589               emitcode ("mov", "a,%s", l);
9590               aopPut (result, "a", offset);
9591             }
9592           else
9593             aopPut (result, l, offset);
9594           offset++;
9595         }
9596     }
9597
9598   tlbl = newiTempLabel (NULL);
9599   tlbl1 = newiTempLabel (NULL);
9600   size = AOP_SIZE (result);
9601   offset = size - 1;
9602
9603   /* if it is only one byte then */
9604   if (size == 1)
9605     {
9606       l = aopGet (left, 0, FALSE, FALSE);
9607       MOVA (l);
9608       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9609       emitLabel (tlbl);
9610       CLRC;
9611       emitcode ("rrc", "a");
9612       emitLabel (tlbl1);
9613       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9614       popB (pushedB);
9615       aopPut (result, "a", 0);
9616       goto release;
9617     }
9618
9619   reAdjustPreg (AOP (result));
9620   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9621   emitLabel (tlbl);
9622   CLRC;
9623   while (size--)
9624     {
9625       l = aopGet (result, offset, FALSE, FALSE);
9626       MOVA (l);
9627       emitcode ("rrc", "a");
9628       aopPut (result, "a", offset--);
9629     }
9630   reAdjustPreg (AOP (result));
9631
9632   emitLabel (tlbl1);
9633   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9634   popB (pushedB);
9635
9636 release:
9637   freeAsmop (result, NULL, ic, TRUE);
9638   freeAsmop (left, NULL, ic, TRUE);
9639 }
9640
9641 /*-----------------------------------------------------------------*/
9642 /* emitPtrByteGet - emits code to get a byte into A through a      */
9643 /*                  pointer register (R0, R1, or DPTR). The        */
9644 /*                  original value of A can be preserved in B.     */
9645 /*-----------------------------------------------------------------*/
9646 static void
9647 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9648 {
9649   switch (p_type)
9650     {
9651     case IPOINTER:
9652     case POINTER:
9653       if (preserveAinB)
9654         emitcode ("mov", "b,a");
9655       emitcode ("mov", "a,@%s", rname);
9656       break;
9657
9658     case PPOINTER:
9659       if (preserveAinB)
9660         emitcode ("mov", "b,a");
9661       emitcode ("movx", "a,@%s", rname);
9662       break;
9663
9664     case FPOINTER:
9665       if (preserveAinB)
9666         emitcode ("mov", "b,a");
9667       emitcode ("movx", "a,@dptr");
9668       break;
9669
9670     case CPOINTER:
9671       if (preserveAinB)
9672         emitcode ("mov", "b,a");
9673       emitcode ("clr", "a");
9674       emitcode ("movc", "a,@a+dptr");
9675       break;
9676
9677     case GPOINTER:
9678       if (preserveAinB)
9679         {
9680           emitcode ("push", "b");
9681           emitcode ("push", "acc");
9682         }
9683       emitcode ("lcall", "__gptrget");
9684       if (preserveAinB)
9685         emitcode ("pop", "b");
9686       break;
9687     }
9688 }
9689
9690 /*-----------------------------------------------------------------*/
9691 /* emitPtrByteSet - emits code to set a byte from src through a    */
9692 /*                  pointer register (R0, R1, or DPTR).            */
9693 /*-----------------------------------------------------------------*/
9694 static void
9695 emitPtrByteSet (char *rname, int p_type, char *src)
9696 {
9697   switch (p_type)
9698     {
9699     case IPOINTER:
9700     case POINTER:
9701       if (*src=='@')
9702         {
9703           MOVA (src);
9704           emitcode ("mov", "@%s,a", rname);
9705         }
9706       else
9707         emitcode ("mov", "@%s,%s", rname, src);
9708       break;
9709
9710     case PPOINTER:
9711       MOVA (src);
9712       emitcode ("movx", "@%s,a", rname);
9713       break;
9714
9715     case FPOINTER:
9716       MOVA (src);
9717       emitcode ("movx", "@dptr,a");
9718       break;
9719
9720     case GPOINTER:
9721       MOVA (src);
9722       emitcode ("lcall", "__gptrput");
9723       break;
9724     }
9725 }
9726
9727 /*-----------------------------------------------------------------*/
9728 /* genUnpackBits - generates code for unpacking bits               */
9729 /*-----------------------------------------------------------------*/
9730 static void
9731 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9732 {
9733   int offset = 0;       /* result byte offset */
9734   int rsize;            /* result size */
9735   int rlen = 0;         /* remaining bitfield length */
9736   sym_link *etype;      /* bitfield type information */
9737   int blen;             /* bitfield length */
9738   int bstr;             /* bitfield starting bit within byte */
9739   char buffer[10];
9740
9741   D(emitcode (";", "genUnpackBits"));
9742
9743   etype = getSpec (operandType (result));
9744   rsize = getSize (operandType (result));
9745   blen = SPEC_BLEN (etype);
9746   bstr = SPEC_BSTR (etype);
9747
9748   if (ifx && blen <= 8)
9749     {
9750       emitPtrByteGet (rname, ptype, FALSE);
9751       if (blen == 1)
9752         {
9753           SNPRINTF (buffer, sizeof(buffer),
9754                     "acc.%d", bstr);
9755           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9756         }
9757       else
9758         {
9759           if (blen < 8)
9760             emitcode ("anl", "a,#0x%02x",
9761                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9762           genIfxJump (ifx, "a", NULL, NULL, NULL);
9763         }
9764       return;
9765     }
9766   wassert (!ifx);
9767
9768   /* If the bitfield length is less than a byte */
9769   if (blen < 8)
9770     {
9771       emitPtrByteGet (rname, ptype, FALSE);
9772       AccRol (8 - bstr);
9773       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9774       if (!SPEC_USIGN (etype))
9775         {
9776           /* signed bitfield */
9777           symbol *tlbl = newiTempLabel (NULL);
9778
9779           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9780           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9781           emitLabel (tlbl);
9782         }
9783       aopPut (result, "a", offset++);
9784       goto finish;
9785     }
9786
9787   /* Bit field did not fit in a byte. Copy all
9788      but the partial byte at the end.  */
9789   for (rlen=blen;rlen>=8;rlen-=8)
9790     {
9791       emitPtrByteGet (rname, ptype, FALSE);
9792       aopPut (result, "a", offset++);
9793       if (rlen>8)
9794         emitcode ("inc", "%s", rname);
9795     }
9796
9797   /* Handle the partial byte at the end */
9798   if (rlen)
9799     {
9800       emitPtrByteGet (rname, ptype, FALSE);
9801       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9802       if (!SPEC_USIGN (etype))
9803         {
9804           /* signed bitfield */
9805           symbol *tlbl = newiTempLabel (NULL);
9806
9807           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9808           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9809           emitLabel (tlbl);
9810         }
9811       aopPut (result, "a", offset++);
9812     }
9813
9814 finish:
9815   if (offset < rsize)
9816     {
9817       char *source;
9818
9819       if (SPEC_USIGN (etype))
9820         source = zero;
9821       else
9822         {
9823           /* signed bitfield: sign extension with 0x00 or 0xff */
9824           emitcode ("rlc", "a");
9825           emitcode ("subb", "a,acc");
9826
9827           source = "a";
9828         }
9829       rsize -= offset;
9830       while (rsize--)
9831         aopPut (result, source, offset++);
9832     }
9833 }
9834
9835
9836 /*-----------------------------------------------------------------*/
9837 /* genDataPointerGet - generates code when ptr offset is known     */
9838 /*-----------------------------------------------------------------*/
9839 static void
9840 genDataPointerGet (operand * left,
9841                    operand * result,
9842                    iCode * ic)
9843 {
9844   char *l;
9845   char buffer[256];
9846   int size, offset = 0;
9847
9848   D (emitcode (";", "genDataPointerGet"));
9849
9850   aopOp (result, ic, TRUE);
9851
9852   /* get the string representation of the name */
9853   l = aopGet (left, 0, FALSE, TRUE);
9854   l++; // remove #
9855   size = AOP_SIZE (result);
9856   while (size--)
9857     {
9858       if (offset)
9859         {
9860           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9861         }
9862       else
9863         {
9864           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9865         }
9866       aopPut (result, buffer, offset++);
9867     }
9868
9869   freeAsmop (result, NULL, ic, TRUE);
9870   freeAsmop (left, NULL, ic, TRUE);
9871 }
9872
9873 /*-----------------------------------------------------------------*/
9874 /* genNearPointerGet - emitcode for near pointer fetch             */
9875 /*-----------------------------------------------------------------*/
9876 static void
9877 genNearPointerGet (operand * left,
9878                    operand * result,
9879                    iCode * ic,
9880                    iCode * pi,
9881                    iCode * ifx)
9882 {
9883   asmop *aop = NULL;
9884   regs *preg = NULL;
9885   char *rname;
9886   sym_link *rtype, *retype;
9887   sym_link *ltype = operandType (left);
9888   char buffer[80];
9889
9890   D (emitcode (";", "genNearPointerGet"));
9891
9892   rtype = operandType (result);
9893   retype = getSpec (rtype);
9894
9895   aopOp (left, ic, FALSE);
9896
9897   /* if left is rematerialisable and
9898      result is not bitfield variable type and
9899      the left is pointer to data space i.e
9900      lower 128 bytes of space */
9901   if (AOP_TYPE (left) == AOP_IMMD &&
9902       !IS_BITFIELD (retype) &&
9903       DCL_TYPE (ltype) == POINTER)
9904     {
9905       genDataPointerGet (left, result, ic);
9906       return;
9907     }
9908
9909  /* if the value is already in a pointer register
9910      then don't need anything more */
9911   if (!AOP_INPREG (AOP (left)))
9912     {
9913       if (IS_AOP_PREG (left))
9914         {
9915           // Aha, it is a pointer, just in disguise.
9916           rname = aopGet (left, 0, FALSE, FALSE);
9917           if (*rname != '@')
9918             {
9919               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9920                       __FILE__, __LINE__);
9921             }
9922           else
9923             {
9924               // Expected case.
9925               emitcode ("mov", "a%s,%s", rname + 1, rname);
9926               rname++;  // skip the '@'.
9927             }
9928         }
9929       else
9930         {
9931           /* otherwise get a free pointer register */
9932           aop = newAsmop (0);
9933           preg = getFreePtr (ic, &aop, FALSE);
9934           emitcode ("mov", "%s,%s",
9935                     preg->name,
9936                     aopGet (left, 0, FALSE, TRUE));
9937           rname = preg->name;
9938         }
9939     }
9940   else
9941     rname = aopGet (left, 0, FALSE, FALSE);
9942
9943   //aopOp (result, ic, FALSE);
9944   aopOp (result, ic, result?TRUE:FALSE);
9945
9946   /* if bitfield then unpack the bits */
9947   if (IS_BITFIELD (retype))
9948     genUnpackBits (result, rname, POINTER, ifx);
9949   else
9950     {
9951       /* we have can just get the values */
9952       int size = AOP_SIZE (result);
9953       int offset = 0;
9954
9955       while (size--)
9956         {
9957           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9958             {
9959
9960               emitcode ("mov", "a,@%s", rname);
9961               if (!ifx)
9962                 aopPut (result, "a", offset);
9963             }
9964           else
9965             {
9966               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9967               aopPut (result, buffer, offset);
9968             }
9969           offset++;
9970           if (size || pi)
9971             emitcode ("inc", "%s", rname);
9972         }
9973     }
9974
9975   /* now some housekeeping stuff */
9976   if (aop)       /* we had to allocate for this iCode */
9977     {
9978       if (pi) { /* post increment present */
9979         aopPut (left, rname, 0);
9980       }
9981       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9982     }
9983   else
9984     {
9985       /* we did not allocate which means left
9986          already in a pointer register, then
9987          if size > 0 && this could be used again
9988          we have to point it back to where it
9989          belongs */
9990       if ((AOP_SIZE (result) > 1 &&
9991            !OP_SYMBOL (left)->remat &&
9992            (OP_SYMBOL (left)->liveTo > ic->seq ||
9993             ic->depth)) &&
9994           !pi)
9995         {
9996           int size = AOP_SIZE (result) - 1;
9997           while (size--)
9998             emitcode ("dec", "%s", rname);
9999         }
10000     }
10001
10002   if (ifx && !ifx->generated)
10003     {
10004       genIfxJump (ifx, "a", left, NULL, result);
10005     }
10006
10007   /* done */
10008   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10009   freeAsmop (left, NULL, ic, TRUE);
10010   if (pi) pi->generated = 1;
10011 }
10012
10013 /*-----------------------------------------------------------------*/
10014 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10015 /*-----------------------------------------------------------------*/
10016 static void
10017 genPagedPointerGet (operand * left,
10018                     operand * result,
10019                     iCode * ic,
10020                     iCode *pi,
10021                     iCode *ifx)
10022 {
10023   asmop *aop = NULL;
10024   regs *preg = NULL;
10025   char *rname;
10026   sym_link *rtype, *retype;
10027
10028   D (emitcode (";", "genPagedPointerGet"));
10029
10030   rtype = operandType (result);
10031   retype = getSpec (rtype);
10032
10033   aopOp (left, ic, FALSE);
10034
10035   /* if the value is already in a pointer register
10036      then don't need anything more */
10037   if (!AOP_INPREG (AOP (left)))
10038     {
10039       /* otherwise get a free pointer register */
10040       aop = newAsmop (0);
10041       preg = getFreePtr (ic, &aop, FALSE);
10042       emitcode ("mov", "%s,%s",
10043                 preg->name,
10044                 aopGet (left, 0, FALSE, TRUE));
10045       rname = preg->name;
10046     }
10047   else
10048     rname = aopGet (left, 0, FALSE, FALSE);
10049
10050   aopOp (result, ic, FALSE);
10051
10052   /* if bitfield then unpack the bits */
10053   if (IS_BITFIELD (retype))
10054     genUnpackBits (result, rname, PPOINTER, ifx);
10055   else
10056     {
10057       /* we have can just get the values */
10058       int size = AOP_SIZE (result);
10059       int offset = 0;
10060
10061       while (size--)
10062         {
10063
10064           emitcode ("movx", "a,@%s", rname);
10065           if (!ifx)
10066             aopPut (result, "a", offset);
10067
10068           offset++;
10069
10070           if (size || pi)
10071             emitcode ("inc", "%s", rname);
10072         }
10073     }
10074
10075   /* now some housekeeping stuff */
10076   if (aop) /* we had to allocate for this iCode */
10077     {
10078       if (pi)
10079         aopPut (left, rname, 0);
10080       freeAsmop (NULL, aop, ic, TRUE);
10081     }
10082   else
10083     {
10084       /* we did not allocate which means left
10085          already in a pointer register, then
10086          if size > 0 && this could be used again
10087          we have to point it back to where it
10088          belongs */
10089       if ((AOP_SIZE (result) > 1 &&
10090            !OP_SYMBOL (left)->remat &&
10091            (OP_SYMBOL (left)->liveTo > ic->seq ||
10092             ic->depth)) &&
10093           !pi)
10094         {
10095           int size = AOP_SIZE (result) - 1;
10096           while (size--)
10097             emitcode ("dec", "%s", rname);
10098         }
10099     }
10100
10101   if (ifx && !ifx->generated)
10102     {
10103       genIfxJump (ifx, "a", left, NULL, result);
10104     }
10105
10106   /* done */
10107   freeAsmop (result, NULL, ic, TRUE);
10108   freeAsmop (left, NULL, ic, TRUE);
10109   if (pi) pi->generated = 1;
10110 }
10111
10112 /*--------------------------------------------------------------------*/
10113 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10114 /*--------------------------------------------------------------------*/
10115 static void
10116 loadDptrFromOperand (operand *op, bool loadBToo)
10117 {
10118   if (AOP_TYPE (op) != AOP_STR)
10119     {
10120       /* if this is rematerializable */
10121       if (AOP_TYPE (op) == AOP_IMMD)
10122         {
10123           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10124           if (loadBToo)
10125             {
10126               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10127                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10128               else
10129                 {
10130                   wassertl(FALSE, "need pointerCode");
10131                   emitcode (";", "mov b,???");
10132                   /* genPointerGet and genPointerSet originally did different
10133                   ** things for this case. Both seem wrong.
10134                   ** from genPointerGet:
10135                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10136                   ** from genPointerSet:
10137                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10138                   */
10139                 }
10140             }
10141         }
10142       else if (AOP_TYPE (op) == AOP_DPTR)
10143         {
10144           if (loadBToo)
10145             {
10146               MOVA (aopGet (op, 0, FALSE, FALSE));
10147               emitcode ("push", "acc");
10148               MOVA (aopGet (op, 1, FALSE, FALSE));
10149               emitcode ("push", "acc");
10150               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10151               emitcode ("pop", "dph");
10152               emitcode ("pop", "dpl");
10153             }
10154           else
10155             {
10156               MOVA (aopGet (op, 0, FALSE, FALSE));
10157               emitcode ("push", "acc");
10158               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10159               emitcode ("pop", "dpl");
10160             }
10161         }
10162       else
10163         {                       /* we need to get it byte by byte */
10164           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10165           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10166           if (loadBToo)
10167             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10168         }
10169     }
10170 }
10171
10172 /*-----------------------------------------------------------------*/
10173 /* genFarPointerGet - get value from far space                     */
10174 /*-----------------------------------------------------------------*/
10175 static void
10176 genFarPointerGet (operand * left,
10177                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10178 {
10179   int size, offset;
10180   sym_link *retype = getSpec (operandType (result));
10181
10182   D (emitcode (";", "genFarPointerGet"));
10183
10184   aopOp (left, ic, FALSE);
10185   loadDptrFromOperand (left, FALSE);
10186
10187   /* so dptr now contains the address */
10188   aopOp (result, ic, FALSE);
10189
10190   /* if bit then unpack */
10191   if (IS_BITFIELD (retype))
10192     genUnpackBits (result, "dptr", FPOINTER, ifx);
10193   else
10194     {
10195       size = AOP_SIZE (result);
10196       offset = 0;
10197
10198       while (size--)
10199         {
10200           emitcode ("movx", "a,@dptr");
10201           if (!ifx)
10202             aopPut (result, "a", offset++);
10203           if (size || pi)
10204             emitcode ("inc", "dptr");
10205         }
10206     }
10207
10208   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10209     {
10210       aopPut (left, "dpl", 0);
10211       aopPut (left, "dph", 1);
10212       pi->generated = 1;
10213     }
10214
10215   if (ifx && !ifx->generated)
10216     {
10217       genIfxJump (ifx, "a", left, NULL, result);
10218     }
10219
10220   freeAsmop (result, NULL, ic, TRUE);
10221   freeAsmop (left, NULL, ic, TRUE);
10222 }
10223
10224 /*-----------------------------------------------------------------*/
10225 /* genCodePointerGet - get value from code space                   */
10226 /*-----------------------------------------------------------------*/
10227 static void
10228 genCodePointerGet (operand * left,
10229                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10230 {
10231   int size, offset;
10232   sym_link *retype = getSpec (operandType (result));
10233
10234   D (emitcode (";", "genCodePointerGet"));
10235
10236   aopOp (left, ic, FALSE);
10237   loadDptrFromOperand (left, FALSE);
10238
10239   /* so dptr now contains the address */
10240   aopOp (result, ic, FALSE);
10241
10242   /* if bit then unpack */
10243   if (IS_BITFIELD (retype))
10244     genUnpackBits (result, "dptr", CPOINTER, ifx);
10245   else
10246     {
10247       size = AOP_SIZE (result);
10248       offset = 0;
10249
10250       while (size--)
10251         {
10252           emitcode ("clr", "a");
10253           emitcode ("movc", "a,@a+dptr");
10254           if (!ifx)
10255             aopPut (result, "a", offset++);
10256           if (size || pi)
10257             emitcode ("inc", "dptr");
10258         }
10259     }
10260
10261   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10262     {
10263       aopPut (left, "dpl", 0);
10264       aopPut (left, "dph", 1);
10265       pi->generated = 1;
10266     }
10267
10268   if (ifx && !ifx->generated)
10269     {
10270       genIfxJump (ifx, "a", left, NULL, result);
10271     }
10272
10273   freeAsmop (result, NULL, ic, TRUE);
10274   freeAsmop (left, NULL, ic, TRUE);
10275 }
10276
10277 /*-----------------------------------------------------------------*/
10278 /* genGenPointerGet - get value from generic pointer space         */
10279 /*-----------------------------------------------------------------*/
10280 static void
10281 genGenPointerGet (operand * left,
10282                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10283 {
10284   int size, offset;
10285   sym_link *retype = getSpec (operandType (result));
10286
10287   D (emitcode (";", "genGenPointerGet"));
10288
10289   aopOp (left, ic, FALSE);
10290   loadDptrFromOperand (left, TRUE);
10291
10292   /* so dptr now contains the address */
10293   aopOp (result, ic, FALSE);
10294
10295   /* if bit then unpack */
10296   if (IS_BITFIELD (retype))
10297     {
10298       genUnpackBits (result, "dptr", GPOINTER, ifx);
10299     }
10300   else
10301     {
10302       size = AOP_SIZE (result);
10303       offset = 0;
10304
10305       while (size--)
10306         {
10307           emitcode ("lcall", "__gptrget");
10308           if (!ifx)
10309             aopPut (result, "a", offset++);
10310           if (size || pi)
10311             emitcode ("inc", "dptr");
10312         }
10313     }
10314
10315   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10316     {
10317       aopPut (left, "dpl", 0);
10318       aopPut (left, "dph", 1);
10319       pi->generated = 1;
10320     }
10321
10322   if (ifx && !ifx->generated)
10323     {
10324       genIfxJump (ifx, "a", left, NULL, result);
10325     }
10326
10327   freeAsmop (result, NULL, ic, TRUE);
10328   freeAsmop (left, NULL, ic, TRUE);
10329 }
10330
10331 /*-----------------------------------------------------------------*/
10332 /* genPointerGet - generate code for pointer get                   */
10333 /*-----------------------------------------------------------------*/
10334 static void
10335 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10336 {
10337   operand *left, *result;
10338   sym_link *type, *etype;
10339   int p_type;
10340
10341   D (emitcode (";", "genPointerGet"));
10342
10343   left = IC_LEFT (ic);
10344   result = IC_RESULT (ic);
10345
10346   if (getSize (operandType (result))>1)
10347     ifx = NULL;
10348
10349   /* depending on the type of pointer we need to
10350      move it to the correct pointer register */
10351   type = operandType (left);
10352   etype = getSpec (type);
10353   /* if left is of type of pointer then it is simple */
10354   if (IS_PTR (type) && !IS_FUNC (type->next))
10355     p_type = DCL_TYPE (type);
10356   else
10357     {
10358       /* we have to go by the storage class */
10359       p_type = PTR_TYPE (SPEC_OCLS (etype));
10360     }
10361
10362   /* special case when cast remat */
10363   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10364       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10365     {
10366       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10367       type = operandType (left);
10368       p_type = DCL_TYPE (type);
10369     }
10370   /* now that we have the pointer type we assign
10371      the pointer values */
10372   switch (p_type)
10373     {
10374
10375     case POINTER:
10376     case IPOINTER:
10377       genNearPointerGet (left, result, ic, pi, ifx);
10378       break;
10379
10380     case PPOINTER:
10381       genPagedPointerGet (left, result, ic, pi, ifx);
10382       break;
10383
10384     case FPOINTER:
10385       genFarPointerGet (left, result, ic, pi, ifx);
10386       break;
10387
10388     case CPOINTER:
10389       genCodePointerGet (left, result, ic, pi, ifx);
10390       break;
10391
10392     case GPOINTER:
10393       genGenPointerGet (left, result, ic, pi, ifx);
10394       break;
10395     }
10396 }
10397
10398
10399 /*-----------------------------------------------------------------*/
10400 /* genPackBits - generates code for packed bit storage             */
10401 /*-----------------------------------------------------------------*/
10402 static void
10403 genPackBits (sym_link * etype,
10404              operand * right,
10405              char *rname, int p_type)
10406 {
10407   int offset = 0;       /* source byte offset */
10408   int rlen = 0;         /* remaining bitfield length */
10409   int blen;             /* bitfield length */
10410   int bstr;             /* bitfield starting bit within byte */
10411   int litval;           /* source literal value (if AOP_LIT) */
10412   unsigned char mask;   /* bitmask within current byte */
10413
10414   D(emitcode (";", "genPackBits"));
10415
10416   blen = SPEC_BLEN (etype);
10417   bstr = SPEC_BSTR (etype);
10418
10419   /* If the bitfield length is less than a byte */
10420   if (blen < 8)
10421     {
10422       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10423               (unsigned char) (0xFF >> (8 - bstr)));
10424
10425       if (AOP_TYPE (right) == AOP_LIT)
10426         {
10427           /* Case with a bitfield length <8 and literal source
10428           */
10429           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10430           litval <<= bstr;
10431           litval &= (~mask) & 0xff;
10432           emitPtrByteGet (rname, p_type, FALSE);
10433           if ((mask|litval)!=0xff)
10434             emitcode ("anl","a,#0x%02x", mask);
10435           if (litval)
10436             emitcode ("orl","a,#0x%02x", litval);
10437         }
10438       else
10439         {
10440           if ((blen==1) && (p_type!=GPOINTER))
10441             {
10442               /* Case with a bitfield length == 1 and no generic pointer
10443               */
10444               if (AOP_TYPE (right) == AOP_CRY)
10445                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10446               else
10447                 {
10448                   MOVA (aopGet (right, 0, FALSE, FALSE));
10449                   emitcode ("rrc","a");
10450                 }
10451               emitPtrByteGet (rname, p_type, FALSE);
10452               emitcode ("mov","acc.%d,c",bstr);
10453             }
10454           else
10455             {
10456               bool pushedB;
10457               /* Case with a bitfield length < 8 and arbitrary source
10458               */
10459               MOVA (aopGet (right, 0, FALSE, FALSE));
10460               /* shift and mask source value */
10461               AccLsh (bstr);
10462               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10463
10464               pushedB = pushB ();
10465               /* transfer A to B and get next byte */
10466               emitPtrByteGet (rname, p_type, TRUE);
10467
10468               emitcode ("anl", "a,#0x%02x", mask);
10469               emitcode ("orl", "a,b");
10470               if (p_type == GPOINTER)
10471                 emitcode ("pop", "b");
10472
10473               popB (pushedB);
10474            }
10475         }
10476
10477       emitPtrByteSet (rname, p_type, "a");
10478       return;
10479     }
10480
10481   /* Bit length is greater than 7 bits. In this case, copy  */
10482   /* all except the partial byte at the end                 */
10483   for (rlen=blen;rlen>=8;rlen-=8)
10484     {
10485       emitPtrByteSet (rname, p_type,
10486                       aopGet (right, offset++, FALSE, TRUE) );
10487       if (rlen>8)
10488         emitcode ("inc", "%s", rname);
10489     }
10490
10491   /* If there was a partial byte at the end */
10492   if (rlen)
10493     {
10494       mask = (((unsigned char) -1 << rlen) & 0xff);
10495
10496       if (AOP_TYPE (right) == AOP_LIT)
10497         {
10498           /* Case with partial byte and literal source
10499           */
10500           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10501           litval >>= (blen-rlen);
10502           litval &= (~mask) & 0xff;
10503           emitPtrByteGet (rname, p_type, FALSE);
10504           if ((mask|litval)!=0xff)
10505             emitcode ("anl","a,#0x%02x", mask);
10506           if (litval)
10507             emitcode ("orl","a,#0x%02x", litval);
10508         }
10509       else
10510         {
10511           bool pushedB;
10512           /* Case with partial byte and arbitrary source
10513           */
10514           MOVA (aopGet (right, offset++, FALSE, FALSE));
10515           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10516
10517           pushedB = pushB ();
10518           /* transfer A to B and get next byte */
10519           emitPtrByteGet (rname, p_type, TRUE);
10520
10521           emitcode ("anl", "a,#0x%02x", mask);
10522           emitcode ("orl", "a,b");
10523           if (p_type == GPOINTER)
10524             emitcode ("pop", "b");
10525
10526           popB (pushedB);
10527         }
10528       emitPtrByteSet (rname, p_type, "a");
10529     }
10530 }
10531
10532
10533 /*-----------------------------------------------------------------*/
10534 /* genDataPointerSet - remat pointer to data space                 */
10535 /*-----------------------------------------------------------------*/
10536 static void
10537 genDataPointerSet (operand * right,
10538                    operand * result,
10539                    iCode * ic)
10540 {
10541   int size, offset = 0;
10542   char *l, buffer[256];
10543
10544   D (emitcode (";", "genDataPointerSet"));
10545
10546   aopOp (right, ic, FALSE);
10547
10548   l = aopGet (result, 0, FALSE, TRUE);
10549   l++; //remove #
10550   size = max (AOP_SIZE (right), AOP_SIZE (result));
10551   while (size--)
10552     {
10553       if (offset)
10554         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10555       else
10556         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10557       emitcode ("mov", "%s,%s", buffer,
10558                 aopGet (right, offset++, FALSE, FALSE));
10559     }
10560
10561   freeAsmop (right, NULL, ic, TRUE);
10562   freeAsmop (result, NULL, ic, TRUE);
10563 }
10564
10565 /*-----------------------------------------------------------------*/
10566 /* genNearPointerSet - emitcode for near pointer put               */
10567 /*-----------------------------------------------------------------*/
10568 static void
10569 genNearPointerSet (operand * right,
10570                    operand * result,
10571                    iCode * ic,
10572                    iCode * pi)
10573 {
10574   asmop *aop = NULL;
10575   regs *preg = NULL;
10576   char *rname, *l;
10577   sym_link *retype, *letype;
10578   sym_link *ptype = operandType (result);
10579
10580   D (emitcode (";", "genNearPointerSet"));
10581
10582   retype = getSpec (operandType (right));
10583   letype = getSpec (ptype);
10584
10585   aopOp (result, ic, FALSE);
10586
10587   /* if the result is rematerializable &
10588      in data space & not a bit variable */
10589   if (AOP_TYPE (result) == AOP_IMMD &&
10590       DCL_TYPE (ptype) == POINTER &&
10591       !IS_BITVAR (retype) &&
10592       !IS_BITVAR (letype))
10593     {
10594       genDataPointerSet (right, result, ic);
10595       return;
10596     }
10597
10598   /* if the value is already in a pointer register
10599      then don't need anything more */
10600   if (!AOP_INPREG (AOP (result)))
10601     {
10602         if (
10603             //AOP_TYPE (result) == AOP_STK
10604             IS_AOP_PREG(result)
10605             )
10606         {
10607             // Aha, it is a pointer, just in disguise.
10608             rname = aopGet (result, 0, FALSE, FALSE);
10609             if (*rname != '@')
10610             {
10611                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10612                         __FILE__, __LINE__);
10613             }
10614             else
10615             {
10616                 // Expected case.
10617                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10618                 rname++;  // skip the '@'.
10619             }
10620         }
10621         else
10622         {
10623             /* otherwise get a free pointer register */
10624             aop = newAsmop (0);
10625             preg = getFreePtr (ic, &aop, FALSE);
10626             emitcode ("mov", "%s,%s",
10627                       preg->name,
10628                       aopGet (result, 0, FALSE, TRUE));
10629             rname = preg->name;
10630         }
10631     }
10632     else
10633     {
10634         rname = aopGet (result, 0, FALSE, FALSE);
10635     }
10636
10637   aopOp (right, ic, FALSE);
10638
10639   /* if bitfield then unpack the bits */
10640   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10641     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10642   else
10643     {
10644       /* we can just get the values */
10645       int size = AOP_SIZE (right);
10646       int offset = 0;
10647
10648       while (size--)
10649         {
10650           l = aopGet (right, offset, FALSE, TRUE);
10651           if ((*l == '@') || (strcmp (l, "acc") == 0))
10652             {
10653               MOVA (l);
10654               emitcode ("mov", "@%s,a", rname);
10655             }
10656           else
10657             emitcode ("mov", "@%s,%s", rname, l);
10658           if (size || pi)
10659             emitcode ("inc", "%s", rname);
10660           offset++;
10661         }
10662     }
10663
10664   /* now some housekeeping stuff */
10665   if (aop) /* we had to allocate for this iCode */
10666     {
10667       if (pi)
10668         aopPut (result, rname, 0);
10669       freeAsmop (NULL, aop, ic, TRUE);
10670     }
10671   else
10672     {
10673       /* we did not allocate which means left
10674          already in a pointer register, then
10675          if size > 0 && this could be used again
10676          we have to point it back to where it
10677          belongs */
10678       if ((AOP_SIZE (right) > 1 &&
10679            !OP_SYMBOL (result)->remat &&
10680            (OP_SYMBOL (result)->liveTo > ic->seq ||
10681             ic->depth)) &&
10682           !pi)
10683         {
10684           int size = AOP_SIZE (right) - 1;
10685           while (size--)
10686             emitcode ("dec", "%s", rname);
10687         }
10688     }
10689
10690   /* done */
10691   if (pi)
10692     pi->generated = 1;
10693   freeAsmop (right, NULL, ic, TRUE);
10694   freeAsmop (result, NULL, ic, TRUE);
10695 }
10696
10697 /*-----------------------------------------------------------------*/
10698 /* genPagedPointerSet - emitcode for Paged pointer put             */
10699 /*-----------------------------------------------------------------*/
10700 static void
10701 genPagedPointerSet (operand * right,
10702                     operand * result,
10703                     iCode * ic,
10704                     iCode * pi)
10705 {
10706   asmop *aop = NULL;
10707   regs *preg = NULL;
10708   char *rname, *l;
10709   sym_link *retype, *letype;
10710
10711   D (emitcode (";", "genPagedPointerSet"));
10712
10713   retype = getSpec (operandType (right));
10714   letype = getSpec (operandType (result));
10715
10716   aopOp (result, ic, FALSE);
10717
10718   /* if the value is already in a pointer register
10719      then don't need anything more */
10720   if (!AOP_INPREG (AOP (result)))
10721     {
10722       /* otherwise get a free pointer register */
10723       aop = newAsmop (0);
10724       preg = getFreePtr (ic, &aop, FALSE);
10725       emitcode ("mov", "%s,%s",
10726                 preg->name,
10727                 aopGet (result, 0, FALSE, TRUE));
10728       rname = preg->name;
10729     }
10730   else
10731     rname = aopGet (result, 0, FALSE, FALSE);
10732
10733   aopOp (right, ic, FALSE);
10734
10735   /* if bitfield then unpack the bits */
10736   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10737     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10738   else
10739     {
10740       /* we have can just get the values */
10741       int size = AOP_SIZE (right);
10742       int offset = 0;
10743
10744       while (size--)
10745         {
10746           l = aopGet (right, offset, FALSE, TRUE);
10747           MOVA (l);
10748           emitcode ("movx", "@%s,a", rname);
10749
10750           if (size || pi)
10751             emitcode ("inc", "%s", rname);
10752
10753           offset++;
10754         }
10755     }
10756
10757   /* now some housekeeping stuff */
10758   if (aop) /* we had to allocate for this iCode */
10759     {
10760       if (pi)
10761         aopPut (result, rname, 0);
10762       freeAsmop (NULL, aop, ic, TRUE);
10763     }
10764   else
10765     {
10766       /* we did not allocate which means left
10767          already in a pointer register, then
10768          if size > 0 && this could be used again
10769          we have to point it back to where it
10770          belongs */
10771       if (AOP_SIZE (right) > 1 &&
10772           !OP_SYMBOL (result)->remat &&
10773           (OP_SYMBOL (result)->liveTo > ic->seq ||
10774            ic->depth))
10775         {
10776           int size = AOP_SIZE (right) - 1;
10777           while (size--)
10778             emitcode ("dec", "%s", rname);
10779         }
10780     }
10781
10782   /* done */
10783   if (pi) pi->generated = 1;
10784   freeAsmop (result, NULL, ic, TRUE);
10785   freeAsmop (right, NULL, ic, TRUE);
10786 }
10787
10788 /*-----------------------------------------------------------------*/
10789 /* genFarPointerSet - set value from far space                     */
10790 /*-----------------------------------------------------------------*/
10791 static void
10792 genFarPointerSet (operand * right,
10793                   operand * result, iCode * ic, iCode * pi)
10794 {
10795   int size, offset;
10796   sym_link *retype = getSpec (operandType (right));
10797   sym_link *letype = getSpec (operandType (result));
10798
10799   D(emitcode (";", "genFarPointerSet"));
10800
10801   aopOp (result, ic, FALSE);
10802   loadDptrFromOperand (result, FALSE);
10803
10804   /* so dptr now contains the address */
10805   aopOp (right, ic, FALSE);
10806
10807   /* if bit then unpack */
10808   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10809     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10810   else
10811     {
10812       size = AOP_SIZE (right);
10813       offset = 0;
10814
10815       while (size--)
10816         {
10817           char *l = aopGet (right, offset++, FALSE, FALSE);
10818           MOVA (l);
10819           emitcode ("movx", "@dptr,a");
10820           if (size || pi)
10821             emitcode ("inc", "dptr");
10822         }
10823     }
10824   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10825     aopPut (result, "dpl", 0);
10826     aopPut (result, "dph", 1);
10827     pi->generated=1;
10828   }
10829   freeAsmop (result, NULL, ic, TRUE);
10830   freeAsmop (right, NULL, ic, TRUE);
10831 }
10832
10833 /*-----------------------------------------------------------------*/
10834 /* genGenPointerSet - set value from generic pointer space         */
10835 /*-----------------------------------------------------------------*/
10836 static void
10837 genGenPointerSet (operand * right,
10838                   operand * result, iCode * ic, iCode * pi)
10839 {
10840   int size, offset;
10841   sym_link *retype = getSpec (operandType (right));
10842   sym_link *letype = getSpec (operandType (result));
10843
10844   D (emitcode (";", "genGenPointerSet"));
10845
10846   aopOp (result, ic, FALSE);
10847   loadDptrFromOperand (result, TRUE);
10848
10849   /* so dptr now contains the address */
10850   aopOp (right, ic, FALSE);
10851
10852   /* if bit then unpack */
10853   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10854     {
10855       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10856     }
10857   else
10858     {
10859       size = AOP_SIZE (right);
10860       offset = 0;
10861
10862       while (size--)
10863         {
10864           char *l = aopGet (right, offset++, FALSE, FALSE);
10865           MOVA (l);
10866           emitcode ("lcall", "__gptrput");
10867           if (size || pi)
10868             emitcode ("inc", "dptr");
10869         }
10870     }
10871
10872   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10873     aopPut (result, "dpl", 0);
10874     aopPut (result, "dph", 1);
10875     pi->generated=1;
10876   }
10877   freeAsmop (result, NULL, ic, TRUE);
10878   freeAsmop (right, NULL, ic, TRUE);
10879 }
10880
10881 /*-----------------------------------------------------------------*/
10882 /* genPointerSet - stores the value into a pointer location        */
10883 /*-----------------------------------------------------------------*/
10884 static void
10885 genPointerSet (iCode * ic, iCode *pi)
10886 {
10887   operand *right, *result;
10888   sym_link *type, *etype;
10889   int p_type;
10890
10891   D (emitcode (";", "genPointerSet"));
10892
10893   right = IC_RIGHT (ic);
10894   result = IC_RESULT (ic);
10895
10896   /* depending on the type of pointer we need to
10897      move it to the correct pointer register */
10898   type = operandType (result);
10899   etype = getSpec (type);
10900   /* if left is of type of pointer then it is simple */
10901   if (IS_PTR (type) && !IS_FUNC (type->next))
10902     {
10903       p_type = DCL_TYPE (type);
10904     }
10905   else
10906     {
10907       /* we have to go by the storage class */
10908       p_type = PTR_TYPE (SPEC_OCLS (etype));
10909     }
10910
10911   /* special case when cast remat */
10912   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10913       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10914           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10915           type = operandType (result);
10916           p_type = DCL_TYPE (type);
10917   }
10918
10919   /* now that we have the pointer type we assign
10920      the pointer values */
10921   switch (p_type)
10922     {
10923
10924     case POINTER:
10925     case IPOINTER:
10926       genNearPointerSet (right, result, ic, pi);
10927       break;
10928
10929     case PPOINTER:
10930       genPagedPointerSet (right, result, ic, pi);
10931       break;
10932
10933     case FPOINTER:
10934       genFarPointerSet (right, result, ic, pi);
10935       break;
10936
10937     case GPOINTER:
10938       genGenPointerSet (right, result, ic, pi);
10939       break;
10940
10941     default:
10942       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10943               "genPointerSet: illegal pointer type");
10944     }
10945 }
10946
10947 /*-----------------------------------------------------------------*/
10948 /* genIfx - generate code for Ifx statement                        */
10949 /*-----------------------------------------------------------------*/
10950 static void
10951 genIfx (iCode * ic, iCode * popIc)
10952 {
10953   operand *cond = IC_COND (ic);
10954   int isbit = 0;
10955   char *dup = NULL;
10956
10957   D (emitcode (";", "genIfx"));
10958
10959   aopOp (cond, ic, FALSE);
10960
10961   /* get the value into acc */
10962   if (AOP_TYPE (cond) != AOP_CRY)
10963     {
10964       toBoolean (cond);
10965     }
10966   else
10967     {
10968       isbit = 1;
10969       if (AOP(cond)->aopu.aop_dir)
10970         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10971     }
10972
10973   /* the result is now in the accumulator or a directly addressable bit */
10974   freeAsmop (cond, NULL, ic, TRUE);
10975
10976   /* if there was something to be popped then do it */
10977   if (popIc)
10978     genIpop (popIc);
10979
10980   /* if the condition is a bit variable */
10981   if (isbit && dup)
10982     genIfxJump(ic, dup, NULL, NULL, NULL);
10983   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10984     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10985   else if (isbit && !IS_ITEMP (cond))
10986     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10987   else
10988     genIfxJump (ic, "a", NULL, NULL, NULL);
10989
10990   ic->generated = 1;
10991 }
10992
10993 /*-----------------------------------------------------------------*/
10994 /* genAddrOf - generates code for address of                       */
10995 /*-----------------------------------------------------------------*/
10996 static void
10997 genAddrOf (iCode * ic)
10998 {
10999   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11000   int size, offset;
11001
11002   D (emitcode (";", "genAddrOf"));
11003
11004   aopOp (IC_RESULT (ic), ic, FALSE);
11005
11006   /* if the operand is on the stack then we
11007      need to get the stack offset of this
11008      variable */
11009   if (sym->onStack)
11010     {
11011       /* if it has an offset then we need to compute it */
11012       if (sym->stack)
11013         {
11014           int stack_offset = ((sym->stack < 0) ?
11015                               ((char) (sym->stack - _G.nRegsSaved)) :
11016                               ((char) sym->stack)) & 0xff;
11017           if ((abs(stack_offset) == 1) &&
11018               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11019               !isOperandVolatile (IC_RESULT (ic), FALSE))
11020             {
11021               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11022               if (stack_offset > 0)
11023                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11024               else
11025                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11026             }
11027           else
11028             {
11029               emitcode ("mov", "a,%s", SYM_BP (sym));
11030               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11031               aopPut (IC_RESULT (ic), "a", 0);
11032             }
11033         }
11034       else
11035         {
11036           /* we can just move _bp */
11037           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11038         }
11039       /* fill the result with zero */
11040       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11041
11042       offset = 1;
11043       while (size--)
11044         {
11045           aopPut (IC_RESULT (ic), zero, offset++);
11046         }
11047       goto release;
11048     }
11049
11050   /* object not on stack then we need the name */
11051   size = AOP_SIZE (IC_RESULT (ic));
11052   offset = 0;
11053
11054   while (size--)
11055     {
11056       char s[SDCC_NAME_MAX];
11057       if (offset)
11058         sprintf (s, "#(%s >> %d)",
11059                  sym->rname,
11060                  offset * 8);
11061       else
11062         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11063       aopPut (IC_RESULT (ic), s, offset++);
11064     }
11065
11066 release:
11067   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11068
11069 }
11070
11071 /*-----------------------------------------------------------------*/
11072 /* genFarFarAssign - assignment when both are in far space         */
11073 /*-----------------------------------------------------------------*/
11074 static void
11075 genFarFarAssign (operand * result, operand * right, iCode * ic)
11076 {
11077   int size = AOP_SIZE (right);
11078   int offset = 0;
11079   char *l;
11080
11081   D (emitcode (";", "genFarFarAssign"));
11082
11083   /* first push the right side on to the stack */
11084   while (size--)
11085     {
11086       l = aopGet (right, offset++, FALSE, FALSE);
11087       MOVA (l);
11088       emitcode ("push", "acc");
11089     }
11090
11091   freeAsmop (right, NULL, ic, FALSE);
11092   /* now assign DPTR to result */
11093   aopOp (result, ic, FALSE);
11094   size = AOP_SIZE (result);
11095   while (size--)
11096     {
11097       emitcode ("pop", "acc");
11098       aopPut (result, "a", --offset);
11099     }
11100   freeAsmop (result, NULL, ic, FALSE);
11101 }
11102
11103 /*-----------------------------------------------------------------*/
11104 /* genAssign - generate code for assignment                        */
11105 /*-----------------------------------------------------------------*/
11106 static void
11107 genAssign (iCode * ic)
11108 {
11109   operand *result, *right;
11110   int size, offset;
11111   unsigned long lit = 0L;
11112
11113   D (emitcode (";", "genAssign"));
11114
11115   result = IC_RESULT (ic);
11116   right = IC_RIGHT (ic);
11117
11118   /* if they are the same */
11119   if (operandsEqu (result, right) &&
11120       !isOperandVolatile (result, FALSE) &&
11121       !isOperandVolatile (right, FALSE))
11122     return;
11123
11124   aopOp (right, ic, FALSE);
11125
11126   /* special case both in far space */
11127   if (AOP_TYPE (right) == AOP_DPTR &&
11128       IS_TRUE_SYMOP (result) &&
11129       isOperandInFarSpace (result))
11130     {
11131       genFarFarAssign (result, right, ic);
11132       return;
11133     }
11134
11135   aopOp (result, ic, TRUE);
11136
11137   /* if they are the same registers */
11138   if (sameRegs (AOP (right), AOP (result)) &&
11139       !isOperandVolatile (result, FALSE) &&
11140       !isOperandVolatile (right, FALSE))
11141     goto release;
11142
11143   /* if the result is a bit */
11144   if (AOP_TYPE (result) == AOP_CRY)
11145     {
11146       assignBit (result, right);
11147       goto release;
11148     }
11149
11150   /* bit variables done */
11151   /* general case */
11152   size = AOP_SIZE (result);
11153   offset = 0;
11154   if (AOP_TYPE (right) == AOP_LIT)
11155     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11156
11157   if ((size > 1) &&
11158       (AOP_TYPE (result) != AOP_REG) &&
11159       (AOP_TYPE (right) == AOP_LIT) &&
11160       !IS_FLOAT (operandType (right)) &&
11161       (lit < 256L))
11162     {
11163       while ((size) && (lit))
11164         {
11165           aopPut (result,
11166                   aopGet (right, offset, FALSE, FALSE),
11167                   offset);
11168           lit >>= 8;
11169           offset++;
11170           size--;
11171         }
11172       /* And now fill the rest with zeros. */
11173       if (size)
11174         {
11175           emitcode ("clr", "a");
11176         }
11177       while (size--)
11178         {
11179           aopPut (result, "a", offset);
11180           offset++;
11181         }
11182     }
11183   else
11184     {
11185       while (size--)
11186         {
11187           aopPut (result,
11188                   aopGet (right, offset, FALSE, FALSE),
11189                   offset);
11190           offset++;
11191         }
11192     }
11193
11194 release:
11195   freeAsmop (result, NULL, ic, TRUE);
11196   freeAsmop (right, NULL, ic, TRUE);
11197 }
11198
11199 /*-----------------------------------------------------------------*/
11200 /* genJumpTab - generates code for jump table                      */
11201 /*-----------------------------------------------------------------*/
11202 static void
11203 genJumpTab (iCode * ic)
11204 {
11205   symbol *jtab,*jtablo,*jtabhi;
11206   char *l;
11207   unsigned int count;
11208
11209   D (emitcode (";", "genJumpTab"));
11210
11211   count = elementsInSet( IC_JTLABELS (ic) );
11212
11213   if( count <= 16 )
11214     {
11215       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11216          if the switch argument is in a register.
11217          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11218       /* Peephole may not convert ljmp to sjmp or ret
11219          labelIsReturnOnly & labelInRange must check
11220          currPl->ic->op != JUMPTABLE */
11221       aopOp (IC_JTCOND (ic), ic, FALSE);
11222       /* get the condition into accumulator */
11223       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11224       MOVA (l);
11225       /* multiply by three */
11226       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11227         {
11228           emitcode ("mov", "b,#3");
11229           emitcode ("mul", "ab");
11230         }
11231       else
11232         {
11233           emitcode ("add", "a,acc");
11234           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11235         }
11236       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11237
11238       jtab = newiTempLabel (NULL);
11239       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11240       emitcode ("jmp", "@a+dptr");
11241       emitLabel (jtab);
11242       /* now generate the jump labels */
11243       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11244            jtab = setNextItem (IC_JTLABELS (ic)))
11245         emitcode ("ljmp", "%05d$", jtab->key + 100);
11246     }
11247   else
11248     {
11249       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11250          if the switch argument is in a register.
11251          For n>6 this algorithm may be more compact */
11252       jtablo = newiTempLabel (NULL);
11253       jtabhi = newiTempLabel (NULL);
11254
11255       /* get the condition into accumulator.
11256          Using b as temporary storage, if register push/pop is needed */
11257       aopOp (IC_JTCOND (ic), ic, FALSE);
11258       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11259       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11260           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11261         {
11262           // (MB) what if B is in use???
11263           wassertl(!BINUSE, "B was in use");
11264           emitcode ("mov", "b,%s", l);
11265           l = "b";
11266         }
11267       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11268       MOVA (l);
11269       if( count <= 112 )
11270         {
11271           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11272           emitcode ("movc", "a,@a+pc");
11273           emitcode ("push", "acc");
11274
11275           MOVA (l);
11276           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11277           emitcode ("movc", "a,@a+pc");
11278           emitcode ("push", "acc");
11279         }
11280       else
11281         {
11282           /* this scales up to n<=255, but needs two more bytes
11283              and changes dptr */
11284           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11285           emitcode ("movc", "a,@a+dptr");
11286           emitcode ("push", "acc");
11287
11288           MOVA (l);
11289           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11290           emitcode ("movc", "a,@a+dptr");
11291           emitcode ("push", "acc");
11292         }
11293
11294       emitcode ("ret", "");
11295
11296       /* now generate jump table, LSB */
11297       emitLabel (jtablo);
11298       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11299            jtab = setNextItem (IC_JTLABELS (ic)))
11300         emitcode (".db", "%05d$", jtab->key + 100);
11301
11302       /* now generate jump table, MSB */
11303       emitLabel (jtabhi);
11304       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11305            jtab = setNextItem (IC_JTLABELS (ic)))
11306          emitcode (".db", "%05d$>>8", jtab->key + 100);
11307     }
11308 }
11309
11310 /*-----------------------------------------------------------------*/
11311 /* genCast - gen code for casting                                  */
11312 /*-----------------------------------------------------------------*/
11313 static void
11314 genCast (iCode * ic)
11315 {
11316   operand *result = IC_RESULT (ic);
11317   sym_link *ctype = operandType (IC_LEFT (ic));
11318   sym_link *rtype = operandType (IC_RIGHT (ic));
11319   operand *right = IC_RIGHT (ic);
11320   int size, offset;
11321
11322   D (emitcode (";", "genCast"));
11323
11324   /* if they are equivalent then do nothing */
11325   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11326     return;
11327
11328   aopOp (right, ic, FALSE);
11329   aopOp (result, ic, FALSE);
11330
11331   /* if the result is a bit (and not a bitfield) */
11332   if (IS_BIT (OP_SYMBOL (result)->type))
11333     {
11334       assignBit (result, right);
11335       goto release;
11336     }
11337
11338   /* if they are the same size : or less */
11339   if (AOP_SIZE (result) <= AOP_SIZE (right))
11340     {
11341
11342       /* if they are in the same place */
11343       if (sameRegs (AOP (right), AOP (result)))
11344         goto release;
11345
11346       /* if they in different places then copy */
11347       size = AOP_SIZE (result);
11348       offset = 0;
11349       while (size--)
11350         {
11351           aopPut (result,
11352                   aopGet (right, offset, FALSE, FALSE),
11353                   offset);
11354           offset++;
11355         }
11356       goto release;
11357     }
11358
11359   /* if the result is of type pointer */
11360   if (IS_PTR (ctype))
11361     {
11362
11363       int p_type;
11364       sym_link *type = operandType (right);
11365       sym_link *etype = getSpec (type);
11366
11367       /* pointer to generic pointer */
11368       if (IS_GENPTR (ctype))
11369         {
11370           if (IS_PTR (type))
11371             {
11372               p_type = DCL_TYPE (type);
11373             }
11374           else
11375             {
11376               if (SPEC_SCLS(etype)==S_REGISTER) {
11377                 // let's assume it is a generic pointer
11378                 p_type=GPOINTER;
11379               } else {
11380                 /* we have to go by the storage class */
11381                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11382               }
11383             }
11384
11385           /* the first two bytes are known */
11386           size = GPTRSIZE - 1;
11387           offset = 0;
11388           while (size--)
11389             {
11390               aopPut (result,
11391                       aopGet (right, offset, FALSE, FALSE),
11392                       offset);
11393               offset++;
11394             }
11395           /* the last byte depending on type */
11396             {
11397                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11398                 char gpValStr[10];
11399
11400                 if (gpVal == -1)
11401                 {
11402                     // pointerTypeToGPByte will have bitched.
11403                     exit(1);
11404                 }
11405
11406                 sprintf(gpValStr, "#0x%x", gpVal);
11407                 aopPut (result, gpValStr, GPTRSIZE - 1);
11408             }
11409           goto release;
11410         }
11411
11412       /* just copy the pointers */
11413       size = AOP_SIZE (result);
11414       offset = 0;
11415       while (size--)
11416         {
11417           aopPut (result,
11418                   aopGet (right, offset, FALSE, FALSE),
11419                   offset);
11420           offset++;
11421         }
11422       goto release;
11423     }
11424
11425   /* so we now know that the size of destination is greater
11426      than the size of the source */
11427   /* we move to result for the size of source */
11428   size = AOP_SIZE (right);
11429   offset = 0;
11430   while (size--)
11431     {
11432       aopPut (result,
11433               aopGet (right, offset, FALSE, FALSE),
11434               offset);
11435       offset++;
11436     }
11437
11438   /* now depending on the sign of the source && destination */
11439   size = AOP_SIZE (result) - AOP_SIZE (right);
11440   /* if unsigned or not an integral type */
11441   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11442     {
11443       while (size--)
11444         aopPut (result, zero, offset++);
11445     }
11446   else
11447     {
11448       /* we need to extend the sign :{ */
11449       char *l = aopGet (right, AOP_SIZE (right) - 1,
11450                         FALSE, FALSE);
11451       MOVA (l);
11452       emitcode ("rlc", "a");
11453       emitcode ("subb", "a,acc");
11454       while (size--)
11455         aopPut (result, "a", offset++);
11456     }
11457
11458   /* we are done hurray !!!! */
11459
11460 release:
11461   freeAsmop (result, NULL, ic, TRUE);
11462   freeAsmop (right, NULL, ic, TRUE);
11463 }
11464
11465 /*-----------------------------------------------------------------*/
11466 /* genDjnz - generate decrement & jump if not zero instrucion      */
11467 /*-----------------------------------------------------------------*/
11468 static int
11469 genDjnz (iCode * ic, iCode * ifx)
11470 {
11471   symbol *lbl, *lbl1;
11472   if (!ifx)
11473     return 0;
11474
11475   /* if the if condition has a false label
11476      then we cannot save */
11477   if (IC_FALSE (ifx))
11478     return 0;
11479
11480   /* if the minus is not of the form a = a - 1 */
11481   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11482       !IS_OP_LITERAL (IC_RIGHT (ic)))
11483     return 0;
11484
11485   if (operandLitValue (IC_RIGHT (ic)) != 1)
11486     return 0;
11487
11488   /* if the size of this greater than one then no
11489      saving */
11490   if (getSize (operandType (IC_RESULT (ic))) > 1)
11491     return 0;
11492
11493   /* otherwise we can save BIG */
11494
11495   D (emitcode (";", "genDjnz"));
11496
11497   lbl = newiTempLabel (NULL);
11498   lbl1 = newiTempLabel (NULL);
11499
11500   aopOp (IC_RESULT (ic), ic, FALSE);
11501
11502   if (AOP_NEEDSACC(IC_RESULT(ic)))
11503   {
11504       /* If the result is accessed indirectly via
11505        * the accumulator, we must explicitly write
11506        * it back after the decrement.
11507        */
11508       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11509
11510       if (strcmp(rByte, "a"))
11511       {
11512            /* Something is hopelessly wrong */
11513            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11514                    __FILE__, __LINE__);
11515            /* We can just give up; the generated code will be inefficient,
11516             * but what the hey.
11517             */
11518            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11519            return 0;
11520       }
11521       emitcode ("dec", "%s", rByte);
11522       aopPut (IC_RESULT (ic), rByte, 0);
11523       emitcode ("jnz", "%05d$", lbl->key + 100);
11524   }
11525   else if (IS_AOP_PREG (IC_RESULT (ic)))
11526     {
11527       emitcode ("dec", "%s",
11528                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11529       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11530       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11531       ifx->generated = 1;
11532       emitcode ("jnz", "%05d$", lbl->key + 100);
11533     }
11534   else
11535     {
11536       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11537                 lbl->key + 100);
11538     }
11539   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11540   emitLabel (lbl);
11541   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11542   emitLabel (lbl1);
11543
11544   if (!ifx->generated)
11545       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11546   ifx->generated = 1;
11547   return 1;
11548 }
11549
11550 /*-----------------------------------------------------------------*/
11551 /* genReceive - generate code for a receive iCode                  */
11552 /*-----------------------------------------------------------------*/
11553 static void
11554 genReceive (iCode * ic)
11555 {
11556   int size = getSize (operandType (IC_RESULT (ic)));
11557   int offset = 0;
11558
11559   D (emitcode (";", "genReceive"));
11560
11561   if (ic->argreg == 1)
11562     { /* first parameter */
11563       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11564            isOperandInPagedSpace (IC_RESULT (ic))) &&
11565           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11566            IS_TRUE_SYMOP (IC_RESULT (ic))))
11567         {
11568           regs *tempRegs[4];
11569           int receivingA = 0;
11570           int roffset = 0;
11571
11572           for (offset = 0; offset<size; offset++)
11573             if (!strcmp (fReturn[offset], "a"))
11574               receivingA = 1;
11575
11576           if (!receivingA)
11577             {
11578               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11579                 {
11580                   for (offset = size-1; offset>0; offset--)
11581                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11582                   emitcode("mov","a,%s", fReturn[0]);
11583                   _G.accInUse++;
11584                   aopOp (IC_RESULT (ic), ic, FALSE);
11585                   _G.accInUse--;
11586                   aopPut (IC_RESULT (ic), "a", offset);
11587                   for (offset = 1; offset<size; offset++)
11588                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11589                   goto release;
11590                 }
11591             }
11592           else
11593             {
11594               if (getTempRegs(tempRegs, size, ic))
11595                 {
11596                   for (offset = 0; offset<size; offset++)
11597                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11598                   aopOp (IC_RESULT (ic), ic, FALSE);
11599                   for (offset = 0; offset<size; offset++)
11600                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11601                   goto release;
11602                 }
11603             }
11604
11605           offset = fReturnSizeMCS51 - size;
11606           while (size--)
11607             {
11608               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11609                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11610               offset++;
11611             }
11612           aopOp (IC_RESULT (ic), ic, FALSE);
11613           size = AOP_SIZE (IC_RESULT (ic));
11614           offset = 0;
11615           while (size--)
11616             {
11617               emitcode ("pop", "acc");
11618               aopPut (IC_RESULT (ic), "a", offset++);
11619             }
11620         }
11621       else
11622         {
11623           _G.accInUse++;
11624           aopOp (IC_RESULT (ic), ic, FALSE);
11625           _G.accInUse--;
11626           assignResultValue (IC_RESULT (ic), NULL);
11627         }
11628     }
11629   else if (ic->argreg > 12)
11630     { /* bit parameters */
11631       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11632
11633       BitBankUsed = 1;
11634       if (!reg || reg->rIdx != ic->argreg-5)
11635         {
11636           aopOp (IC_RESULT (ic), ic, FALSE);
11637           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11638           outBitC(IC_RESULT (ic));
11639         }
11640     }
11641   else
11642     { /* other parameters */
11643       int rb1off ;
11644       aopOp (IC_RESULT (ic), ic, FALSE);
11645       rb1off = ic->argreg;
11646       while (size--)
11647         {
11648           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11649         }
11650     }
11651
11652 release:
11653   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11654 }
11655
11656 /*-----------------------------------------------------------------*/
11657 /* genDummyRead - generate code for dummy read of volatiles        */
11658 /*-----------------------------------------------------------------*/
11659 static void
11660 genDummyRead (iCode * ic)
11661 {
11662   operand *op;
11663   int size, offset;
11664
11665   D (emitcode(";", "genDummyRead"));
11666
11667   op = IC_RIGHT (ic);
11668   if (op && IS_SYMOP (op))
11669     {
11670       aopOp (op, ic, FALSE);
11671
11672       /* if the result is a bit */
11673       if (AOP_TYPE (op) == AOP_CRY)
11674         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11675       else
11676         {
11677           /* bit variables done */
11678           /* general case */
11679           size = AOP_SIZE (op);
11680           offset = 0;
11681           while (size--)
11682           {
11683             MOVA (aopGet (op, offset, FALSE, FALSE));
11684             offset++;
11685           }
11686         }
11687
11688       freeAsmop (op, NULL, ic, TRUE);
11689     }
11690
11691   op = IC_LEFT (ic);
11692   if (op && IS_SYMOP (op))
11693     {
11694       aopOp (op, ic, FALSE);
11695
11696       /* if the result is a bit */
11697       if (AOP_TYPE (op) == AOP_CRY)
11698         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11699       else
11700         {
11701           /* bit variables done */
11702           /* general case */
11703           size = AOP_SIZE (op);
11704           offset = 0;
11705           while (size--)
11706           {
11707             MOVA (aopGet (op, offset, FALSE, FALSE));
11708             offset++;
11709           }
11710         }
11711
11712       freeAsmop (op, NULL, ic, TRUE);
11713     }
11714 }
11715
11716 /*-----------------------------------------------------------------*/
11717 /* genCritical - generate code for start of a critical sequence    */
11718 /*-----------------------------------------------------------------*/
11719 static void
11720 genCritical (iCode *ic)
11721 {
11722   symbol *tlbl = newiTempLabel (NULL);
11723
11724   D (emitcode(";", "genCritical"));
11725
11726   if (IC_RESULT (ic))
11727     {
11728       aopOp (IC_RESULT (ic), ic, TRUE);
11729       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11730       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11731       aopPut (IC_RESULT (ic), zero, 0);
11732       emitLabel (tlbl);
11733       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11734     }
11735   else
11736     {
11737       emitcode ("setb", "c");
11738       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11739       emitcode ("clr", "c");
11740       emitLabel (tlbl);
11741       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11742     }
11743 }
11744
11745 /*-----------------------------------------------------------------*/
11746 /* genEndCritical - generate code for end of a critical sequence   */
11747 /*-----------------------------------------------------------------*/
11748 static void
11749 genEndCritical (iCode *ic)
11750 {
11751   D(emitcode(";", "genEndCritical"));
11752
11753   if (IC_RIGHT (ic))
11754     {
11755       aopOp (IC_RIGHT (ic), ic, FALSE);
11756       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11757         {
11758           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11759           emitcode ("mov", "ea,c");
11760         }
11761       else
11762         {
11763           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11764             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11765           emitcode ("rrc", "a");
11766           emitcode ("mov", "ea,c");
11767         }
11768       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11769     }
11770   else
11771     {
11772       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11773       emitcode ("mov", "ea,c");
11774     }
11775 }
11776
11777 /*-----------------------------------------------------------------*/
11778 /* gen51Code - generate code for 8051 based controllers            */
11779 /*-----------------------------------------------------------------*/
11780 void
11781 gen51Code (iCode * lic)
11782 {
11783   iCode *ic;
11784   int cln = 0;
11785   /* int cseq = 0; */
11786
11787   _G.currentFunc = NULL;
11788   lineHead = lineCurr = NULL;
11789
11790   /* print the allocation information */
11791   if (allocInfo && currFunc)
11792     printAllocInfo (currFunc, codeOutBuf);
11793   /* if debug information required */
11794   if (options.debug && currFunc)
11795     {
11796       debugFile->writeFunction (currFunc, lic);
11797     }
11798   /* stack pointer name */
11799   if (options.useXstack)
11800     spname = "_spx";
11801   else
11802     spname = "sp";
11803
11804
11805   for (ic = lic; ic; ic = ic->next)
11806     {
11807       _G.current_iCode = ic;
11808
11809       if (ic->lineno && cln != ic->lineno)
11810         {
11811           if (options.debug)
11812             {
11813               debugFile->writeCLine (ic);
11814             }
11815           if (!options.noCcodeInAsm) {
11816             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11817                       printCLine(ic->filename, ic->lineno));
11818           }
11819           cln = ic->lineno;
11820         }
11821       #if 0
11822       if (ic->seqPoint && ic->seqPoint != cseq)
11823         {
11824           emitcode (";", "sequence point %d", ic->seqPoint);
11825           cseq = ic->seqPoint;
11826         }
11827       #endif
11828       if (options.iCodeInAsm) {
11829         char regsInUse[80];
11830         int i;
11831         char *iLine;
11832
11833         #if 0
11834         for (i=0; i<8; i++) {
11835           sprintf (&regsInUse[i],
11836                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11837         regsInUse[i]=0;
11838         #else
11839         strcpy (regsInUse, "--------");
11840         for (i=0; i < 8; i++) {
11841           if (bitVectBitValue (ic->rMask, i))
11842             {
11843               int offset = regs8051[i].offset;
11844               regsInUse[offset] = offset + '0'; /* show rMask */
11845             }
11846         #endif
11847         }
11848         iLine = printILine(ic);
11849         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11850         dbuf_free(iLine);
11851       }
11852       /* if the result is marked as
11853          spilt and rematerializable or code for
11854          this has already been generated then
11855          do nothing */
11856       if (resultRemat (ic) || ic->generated)
11857         continue;
11858
11859       /* depending on the operation */
11860       switch (ic->op)
11861         {
11862         case '!':
11863           genNot (ic);
11864           break;
11865
11866         case '~':
11867           genCpl (ic);
11868           break;
11869
11870         case UNARYMINUS:
11871           genUminus (ic);
11872           break;
11873
11874         case IPUSH:
11875           genIpush (ic);
11876           break;
11877
11878         case IPOP:
11879           /* IPOP happens only when trying to restore a
11880              spilt live range, if there is an ifx statement
11881              following this pop then the if statement might
11882              be using some of the registers being popped which
11883              would destory the contents of the register so
11884              we need to check for this condition and handle it */
11885           if (ic->next &&
11886               ic->next->op == IFX &&
11887               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11888             genIfx (ic->next, ic);
11889           else
11890             genIpop (ic);
11891           break;
11892
11893         case CALL:
11894           genCall (ic);
11895           break;
11896
11897         case PCALL:
11898           genPcall (ic);
11899           break;
11900
11901         case FUNCTION:
11902           genFunction (ic);
11903           break;
11904
11905         case ENDFUNCTION:
11906           genEndFunction (ic);
11907           break;
11908
11909         case RETURN:
11910           genRet (ic);
11911           break;
11912
11913         case LABEL:
11914           genLabel (ic);
11915           break;
11916
11917         case GOTO:
11918           genGoto (ic);
11919           break;
11920
11921         case '+':
11922           genPlus (ic);
11923           break;
11924
11925         case '-':
11926           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11927             genMinus (ic);
11928           break;
11929
11930         case '*':
11931           genMult (ic);
11932           break;
11933
11934         case '/':
11935           genDiv (ic);
11936           break;
11937
11938         case '%':
11939           genMod (ic);
11940           break;
11941
11942         case '>':
11943           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11944           break;
11945
11946         case '<':
11947           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11948           break;
11949
11950         case LE_OP:
11951         case GE_OP:
11952         case NE_OP:
11953
11954           /* note these two are xlated by algebraic equivalence
11955              in decorateType() in SDCCast.c */
11956           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11957                   "got '>=' or '<=' shouldn't have come here");
11958           break;
11959
11960         case EQ_OP:
11961           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11962           break;
11963
11964         case AND_OP:
11965           genAndOp (ic);
11966           break;
11967
11968         case OR_OP:
11969           genOrOp (ic);
11970           break;
11971
11972         case '^':
11973           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11974           break;
11975
11976         case '|':
11977           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11978           break;
11979
11980         case BITWISEAND:
11981           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11982           break;
11983
11984         case INLINEASM:
11985           genInline (ic);
11986           break;
11987
11988         case RRC:
11989           genRRC (ic);
11990           break;
11991
11992         case RLC:
11993           genRLC (ic);
11994           break;
11995
11996         case GETHBIT:
11997           genGetHbit (ic);
11998           break;
11999
12000         case GETABIT:
12001           genGetAbit (ic);
12002           break;
12003
12004         case GETBYTE:
12005           genGetByte (ic);
12006           break;
12007
12008         case GETWORD:
12009           genGetWord (ic);
12010           break;
12011
12012         case LEFT_OP:
12013           genLeftShift (ic);
12014           break;
12015
12016         case RIGHT_OP:
12017           genRightShift (ic);
12018           break;
12019
12020         case GET_VALUE_AT_ADDRESS:
12021           genPointerGet (ic,
12022                          hasInc (IC_LEFT (ic), ic,
12023                                  getSize (operandType (IC_RESULT (ic)))),
12024                          ifxForOp (IC_RESULT (ic), ic) );
12025           break;
12026
12027         case '=':
12028           if (POINTER_SET (ic))
12029             genPointerSet (ic,
12030                            hasInc (IC_RESULT (ic), ic,
12031                                    getSize (operandType (IC_RIGHT (ic)))));
12032           else
12033             genAssign (ic);
12034           break;
12035
12036         case IFX:
12037           genIfx (ic, NULL);
12038           break;
12039
12040         case ADDRESS_OF:
12041           genAddrOf (ic);
12042           break;
12043
12044         case JUMPTABLE:
12045           genJumpTab (ic);
12046           break;
12047
12048         case CAST:
12049           genCast (ic);
12050           break;
12051
12052         case RECEIVE:
12053           genReceive (ic);
12054           break;
12055
12056         case SEND:
12057           addSet (&_G.sendSet, ic);
12058           break;
12059
12060         case DUMMY_READ_VOLATILE:
12061           genDummyRead (ic);
12062           break;
12063
12064         case CRITICAL:
12065           genCritical (ic);
12066           break;
12067
12068         case ENDCRITICAL:
12069           genEndCritical (ic);
12070           break;
12071
12072         case SWAP:
12073           genSwap (ic);
12074           break;
12075
12076         default:
12077           ic = ic;
12078         }
12079     }
12080
12081   _G.current_iCode = NULL;
12082
12083   /* now we are ready to call the
12084      peep hole optimizer */
12085   if (!options.nopeep)
12086     peepHole (&lineHead);
12087
12088   /* now do the actual printing */
12089   printLine (lineHead, codeOutBuf);
12090   return;
12091 }