* src/mcs51/gen.c (outBitC): retry of optimization for dummy result
[fw/sdcc] / src / mcs51 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for 8051
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7
8   This program is free software; you can redistribute it and/or modify it
9   under the terms of the GNU General Public License as published by the
10   Free Software Foundation; either version 2, or (at your option) any
11   later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22   In other words, you are welcome to use, share and improve this program.
23   You are forbidden to forbid anyone else to use, share and improve
24   what you give them.   Help stamp out software-hoarding!
25
26   Notes:
27   000123 mlh  Moved aopLiteral to SDCCglue.c to help the split
28       Made everything static
29 -------------------------------------------------------------------------*/
30
31 #define D(x) do if (options.verboseAsm) {x;} while(0)
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include "SDCCglobl.h"
38 #include "newalloc.h"
39
40 #include "common.h"
41 #include "SDCCpeeph.h"
42 #include "ralloc.h"
43 #include "rtrack.h"
44 #include "gen.h"
45 #include "dbuf_string.h"
46
47 char *aopLiteral (value * val, int offset);
48 char *aopLiteralLong (value * val, int offset, int size);
49 extern int allocInfo;
50
51 /* this is the down and dirty file with all kinds of
52    kludgy & hacky stuff. This is what it is all about
53    CODE GENERATION for a specific MCU . some of the
54    routines may be reusable, will have to see */
55
56 static char *zero = "#0x00";
57 static char *one = "#0x01";
58 static char *spname;
59
60 char *fReturn8051[] =
61 {"dpl", "dph", "b", "a"};
62 unsigned fReturnSizeMCS51 = 4;  /* shared with ralloc.c */
63 char **fReturn = fReturn8051;
64 static char *accUse[] =
65 {"a", "b"};
66
67 static unsigned short rbank = -1;
68
69 #define REG_WITH_INDEX   mcs51_regWithIdx
70
71 #define AOP(op) op->aop
72 #define AOP_TYPE(op) AOP(op)->type
73 #define AOP_SIZE(op) AOP(op)->size
74 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
75                         AOP_TYPE(x) == AOP_R0))
76
77 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
78                          AOP_TYPE(x) == AOP_DPTR || \
79                          AOP(x)->paged))
80
81 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
82                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
83                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
84
85 #define SYM_BP(sym)   (SPEC_OCLS (sym->etype)->paged ? "_bpx" : "_bp")
86
87 #define R0INB   _G.bu.bs.r0InB
88 #define R1INB   _G.bu.bs.r1InB
89 #define OPINB   _G.bu.bs.OpInB
90 #define BINUSE  _G.bu.BInUse
91
92 static struct
93   {
94     short r0Pushed;
95     short r1Pushed;
96     union
97       {
98         struct
99           {
100             short r0InB : 2;//2 so we can see it overflow
101             short r1InB : 2;//2 so we can see it overflow
102             short OpInB : 2;//2 so we can see it overflow
103           } bs;
104         short BInUse;
105       } bu;
106     short accInUse;
107     short inLine;
108     short debugLine;
109     short nRegsSaved;
110     set *sendSet;
111     iCode *current_iCode;
112     symbol *currentFunc;
113   }
114 _G;
115
116 static char *rb1regs[] = {
117     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
118     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
119 };
120
121 extern struct dbuf_s *codeOutBuf;
122
123 #define RESULTONSTACK(x) \
124                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
125                          IC_RESULT(x)->aop->type == AOP_STK )
126
127 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
128 #define MOVB(x)  movb(x)
129
130 #define CLRC     emitcode("clr","c")
131 #define SETC     emitcode("setb","c")
132
133 static lineNode *lineHead = NULL;
134 static lineNode *lineCurr = NULL;
135
136 static unsigned char SLMask[] =
137 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
138  0xE0, 0xC0, 0x80, 0x00};
139 static unsigned char SRMask[] =
140 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
141  0x07, 0x03, 0x01, 0x00};
142
143 #define LSB     0
144 #define MSB16   1
145 #define MSB24   2
146 #define MSB32   3
147
148 /*-----------------------------------------------------------------*/
149 /* emitcode - writes the code into a file : for now it is simple    */
150 /*-----------------------------------------------------------------*/
151 void
152 emitcode (const char *inst, const char *fmt,...)
153 {
154   va_list ap;
155   struct dbuf_s dbuf;
156   const char *lbp, *lb;
157
158   dbuf_init (&dbuf, INITIAL_INLINEASM);
159
160   va_start (ap, fmt);
161
162   if (inst && *inst)
163     {
164       dbuf_append_str (&dbuf, inst);
165
166       if (fmt && *fmt)
167         {
168           dbuf_append_char (&dbuf, '\t');
169           dbuf_tvprintf (&dbuf, fmt, ap);
170         }
171     }
172   else
173     {
174       dbuf_tvprintf (&dbuf, fmt, ap);
175     }
176
177   lbp = lb = dbuf_c_str(&dbuf);
178
179   while (isspace ((unsigned char)*lbp))
180     {
181       lbp++;
182     }
183
184   if (lbp)
185     {
186       rtrackUpdate (lbp);
187
188       lineCurr = (lineCurr ?
189                   connectLine (lineCurr, newLineNode (lb)) :
190                   (lineHead = newLineNode (lb)));
191
192       lineCurr->isInline = _G.inLine;
193       lineCurr->isDebug = _G.debugLine;
194       lineCurr->ic = _G.current_iCode;
195       lineCurr->isComment = (*lbp==';');
196     }
197
198   va_end (ap);
199
200   dbuf_destroy(&dbuf);
201 }
202
203 static void
204 emitLabel (symbol *tlbl)
205 {
206   emitcode ("", "%05d$:", tlbl->key + 100);
207   lineCurr->isLabel = 1;
208 }
209
210 /*-----------------------------------------------------------------*/
211 /* mcs51_emitDebuggerSymbol - associate the current code location  */
212 /*   with a debugger symbol                                        */
213 /*-----------------------------------------------------------------*/
214 void
215 mcs51_emitDebuggerSymbol (char * debugSym)
216 {
217   _G.debugLine = 1;
218   emitcode ("", "%s ==.", debugSym);
219   _G.debugLine = 0;
220 }
221
222 /*-----------------------------------------------------------------*/
223 /* mova - moves specified value into accumulator                   */
224 /*-----------------------------------------------------------------*/
225 static void
226 mova (const char *x)
227 {
228   /* do some early peephole optimization */
229   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
230     return;
231
232   /* if it is a literal mov try to get it cheaper */
233   if (*x == '#' &&
234       rtrackMoveALit(x))
235     return;
236
237   emitcode("mov", "a,%s", x);
238 }
239
240 /*-----------------------------------------------------------------*/
241 /* movb - moves specified value into register b                    */
242 /*-----------------------------------------------------------------*/
243 static void
244 movb (const char *x)
245 {
246   /* do some early peephole optimization */
247   if (!strncmp(x, "b", 2))
248     return;
249
250   /* if it is a literal mov try to get it cheaper */
251   if (*x == '#')
252     {
253       emitcode("mov","b,%s", rtrackGetLit(x));
254       return;
255     }
256
257   emitcode("mov","b,%s", x);
258 }
259
260 /*-----------------------------------------------------------------*/
261 /* pushB - saves register B if necessary                           */
262 /*-----------------------------------------------------------------*/
263 static bool
264 pushB (void)
265 {
266   bool pushedB = FALSE;
267
268   if (BINUSE)
269     {
270       emitcode ("push", "b");
271 //    printf("B was in use !\n");
272       pushedB = TRUE;
273     }
274   else
275     {
276       OPINB++;
277     }
278   return pushedB;
279 }
280
281 /*-----------------------------------------------------------------*/
282 /* popB - restores value of register B if necessary                */
283 /*-----------------------------------------------------------------*/
284 static void
285 popB (bool pushedB)
286 {
287   if (pushedB)
288     {
289       emitcode ("pop", "b");
290     }
291   else
292     {
293       OPINB--;
294     }
295 }
296
297 /*-----------------------------------------------------------------*/
298 /* pushReg - saves register                                        */
299 /*-----------------------------------------------------------------*/
300 static bool
301 pushReg (int index, bool bits_pushed)
302 {
303   regs * reg = REG_WITH_INDEX (index);
304   if (reg->type == REG_BIT)
305     {
306       if (!bits_pushed)
307         emitcode ("push", "%s", reg->base);
308       return TRUE;
309     }
310   else
311     emitcode ("push", "%s", reg->dname);
312   return bits_pushed;
313 }
314
315 /*-----------------------------------------------------------------*/
316 /* popReg - restores register                                      */
317 /*-----------------------------------------------------------------*/
318 static bool
319 popReg (int index, bool bits_popped)
320 {
321   regs * reg = REG_WITH_INDEX (index);
322   if (reg->type == REG_BIT)
323     {
324       if (!bits_popped)
325         emitcode ("pop", "%s", reg->base);
326       return TRUE;
327     }
328   else
329     emitcode ("pop", "%s", reg->dname);
330   return bits_popped;
331 }
332
333 /*-----------------------------------------------------------------*/
334 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
335 /*-----------------------------------------------------------------*/
336 static regs *
337 getFreePtr (iCode * ic, asmop ** aopp, bool result)
338 {
339   bool r0iu, r1iu;
340   bool r0ou, r1ou;
341
342   /* the logic: if r0 & r1 used in the instruction
343      then we are in trouble otherwise */
344
345   /* first check if r0 & r1 are used by this
346      instruction, in which case we are in trouble */
347   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
348   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
349   if (r0iu && r1iu) {
350       goto endOfWorld;
351     }
352
353   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
354   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
355
356   /* if no usage of r0 then return it */
357   if (!r0iu && !r0ou)
358     {
359       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
360       (*aopp)->type = AOP_R0;
361
362       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
363     }
364
365   /* if no usage of r1 then return it */
366   if (!r1iu && !r1ou)
367     {
368       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
369       (*aopp)->type = AOP_R1;
370
371       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
372     }
373
374   /* now we know they both have usage */
375   /* if r0 not used in this instruction */
376   if (!r0iu)
377     {
378       /* push it if not already pushed */
379       if (ic->op == IPUSH)
380         {
381           MOVB (REG_WITH_INDEX (R0_IDX)->dname);
382           R0INB++;
383         }
384       else if (!_G.r0Pushed)
385         {
386           emitcode ("push", "%s",
387                     REG_WITH_INDEX (R0_IDX)->dname);
388           _G.r0Pushed++;
389         }
390
391       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
392       (*aopp)->type = AOP_R0;
393
394       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
395     }
396
397   /* if r1 not used then */
398
399   if (!r1iu)
400     {
401       /* push it if not already pushed */
402       if (ic->op == IPUSH)
403         {
404           MOVB (REG_WITH_INDEX (R1_IDX)->dname);
405           R1INB++;
406         }
407       else if (!_G.r1Pushed)
408         {
409           emitcode ("push", "%s",
410                     REG_WITH_INDEX (R1_IDX)->dname);
411           _G.r1Pushed++;
412         }
413
414       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
415       (*aopp)->type = AOP_R1;
416       return REG_WITH_INDEX (R1_IDX);
417     }
418
419 endOfWorld:
420   /* I said end of world, but not quite end of world yet */
421   /* if this is a result then we can push it on the stack */
422   if (result)
423     {
424       (*aopp)->type = AOP_STK;
425       return NULL;
426     }
427   /* in the case that result AND left AND right needs a pointer reg
428      we can safely use the result's */
429   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R0_IDX))
430     {
431       (*aopp)->type = AOP_R0;
432       return REG_WITH_INDEX (R0_IDX);
433     }
434   if (bitVectBitValue (mcs51_rUmaskForOp(IC_RESULT(ic)), R1_IDX))
435     {
436       (*aopp)->type = AOP_R1;
437       return REG_WITH_INDEX (R1_IDX);
438     }
439
440   /* now this is REALLY the end of the world */
441   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
442           "getFreePtr should never reach here");
443   exit (1);
444 }
445
446
447 /*-----------------------------------------------------------------*/
448 /* getTempRegs - initialize an array of pointers to GPR registers */
449 /*               that are not in use. Returns 1 if the requested   */
450 /*               number of registers were available, 0 otherwise.  */
451 /*-----------------------------------------------------------------*/
452 int
453 getTempRegs(regs **tempRegs, int size, iCode *ic)
454 {
455   bitVect * freeRegs;
456   int i;
457   int offset;
458
459   if (!ic)
460     ic = _G.current_iCode;
461   if (!ic)
462     return 0;
463   if (!_G.currentFunc)
464     return 0;
465
466   freeRegs = newBitVect(8);
467   bitVectSetBit (freeRegs, R2_IDX);
468   bitVectSetBit (freeRegs, R3_IDX);
469   bitVectSetBit (freeRegs, R4_IDX);
470   bitVectSetBit (freeRegs, R5_IDX);
471   bitVectSetBit (freeRegs, R6_IDX);
472   bitVectSetBit (freeRegs, R7_IDX);
473
474   if (IFFUNC_CALLEESAVES(_G.currentFunc->type))
475     {
476       bitVect * newfreeRegs;
477       newfreeRegs = bitVectIntersect (freeRegs, _G.currentFunc->regsUsed);
478       freeBitVect(freeRegs);
479       freeRegs = newfreeRegs;
480     }
481   freeRegs = bitVectCplAnd (freeRegs, ic->rMask);
482
483   offset = 0;
484   for (i=0; i<freeRegs->size; i++)
485     {
486       if (bitVectBitValue(freeRegs,i))
487         tempRegs[offset++] = REG_WITH_INDEX(i);
488       if (offset>=size)
489         {
490           freeBitVect(freeRegs);
491           return 1;
492         }
493     }
494
495   freeBitVect(freeRegs);
496   return 0;
497 }
498
499
500 /*-----------------------------------------------------------------*/
501 /* newAsmop - creates a new asmOp                                  */
502 /*-----------------------------------------------------------------*/
503 static asmop *
504 newAsmop (short type)
505 {
506   asmop *aop;
507
508   aop = Safe_calloc (1, sizeof (asmop));
509   aop->type = type;
510   aop->allocated = 1;
511   return aop;
512 }
513
514 /*-----------------------------------------------------------------*/
515 /* pointerCode - returns the code for a pointer type               */
516 /*-----------------------------------------------------------------*/
517 static int
518 pointerCode (sym_link * etype)
519 {
520
521   return PTR_TYPE (SPEC_OCLS (etype));
522
523 }
524
525 /*-----------------------------------------------------------------*/
526 /* leftRightUseAcc - returns size of accumulator use by operands   */
527 /*-----------------------------------------------------------------*/
528 static int
529 leftRightUseAcc(iCode *ic)
530 {
531   operand *op;
532   int size;
533   int accuseSize = 0;
534   int accuse = 0;
535
536   if (!ic)
537     {
538       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
539               "null iCode pointer");
540       return 0;
541     }
542
543   if (ic->op == IFX)
544     {
545       op = IC_COND (ic);
546       if (IS_OP_ACCUSE (op))
547         {
548           accuse = 1;
549           size = getSize (OP_SYMBOL (op)->type);
550           if (size>accuseSize)
551             accuseSize = size;
552         }
553     }
554   else if (ic->op == JUMPTABLE)
555     {
556       op = IC_JTCOND (ic);
557       if (IS_OP_ACCUSE (op))
558         {
559           accuse = 1;
560           size = getSize (OP_SYMBOL (op)->type);
561           if (size>accuseSize)
562             accuseSize = size;
563         }
564     }
565   else
566     {
567       op = IC_LEFT (ic);
568       if (IS_OP_ACCUSE (op))
569         {
570           accuse = 1;
571           size = getSize (OP_SYMBOL (op)->type);
572           if (size>accuseSize)
573             accuseSize = size;
574         }
575       op = IC_RIGHT (ic);
576       if (IS_OP_ACCUSE (op))
577         {
578           accuse = 1;
579           size = getSize (OP_SYMBOL (op)->type);
580           if (size>accuseSize)
581             accuseSize = size;
582         }
583     }
584
585   if (accuseSize)
586     return accuseSize;
587   else
588     return accuse;
589 }
590
591 /*-----------------------------------------------------------------*/
592 /* aopForSym - for a true symbol                                   */
593 /*-----------------------------------------------------------------*/
594 static asmop *
595 aopForSym (iCode * ic, symbol * sym, bool result)
596 {
597   asmop *aop;
598   memmap *space;
599   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
600
601   wassertl (ic != NULL, "Got a null iCode");
602   wassertl (sym != NULL, "Got a null symbol");
603
604   space = SPEC_OCLS (sym->etype);
605
606   /* if already has one */
607   if (sym->aop)
608     {
609       sym->aop->allocated++;
610       return sym->aop;
611     }
612
613   /* assign depending on the storage class */
614   /* if it is on the stack or indirectly addressable */
615   /* space we need to assign either r0 or r1 to it   */
616   if (sym->onStack || sym->iaccess)
617     {
618       sym->aop = aop = newAsmop (0);
619       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
620       aop->size = getSize (sym->type);
621
622       /* now assign the address of the variable to
623          the pointer register */
624       if (aop->type != AOP_STK)
625         {
626           if (sym->onStack)
627             {
628               signed char offset = ((sym->stack < 0) ?
629                          ((signed char) (sym->stack - _G.nRegsSaved)) :
630                          ((signed char) sym->stack)) & 0xff;
631
632               if ((abs(offset) <= 3) ||
633                   (accuse && (abs(offset) <= 7)))
634                 {
635                   emitcode ("mov", "%s,%s",
636                             aop->aopu.aop_ptr->name, SYM_BP (sym));
637                   while (offset < 0)
638                     {
639                       emitcode ("dec", aop->aopu.aop_ptr->name);
640                       offset++;
641                     }
642                   while (offset > 0)
643                     {
644                       emitcode ("inc", aop->aopu.aop_ptr->name);
645                       offset--;
646                     }
647                 }
648               else
649                 {
650                   if (accuse)
651                     emitcode ("push", "acc");
652                   emitcode ("mov", "a,%s", SYM_BP (sym));
653                   emitcode ("add", "a,#0x%02x", offset & 0xff);
654                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
655                   if (accuse)
656                     emitcode ("pop", "acc");
657                 }
658             }
659           else
660             {
661               emitcode ("mov", "%s,#%s",
662                         aop->aopu.aop_ptr->name,
663                         sym->rname);
664             }
665           aop->paged = space->paged;
666         }
667       else
668         aop->aopu.aop_stk = sym->stack;
669       return aop;
670     }
671
672   /* if in bit space */
673   if (IN_BITSPACE (space))
674     {
675       sym->aop = aop = newAsmop (AOP_CRY);
676       aop->aopu.aop_dir = sym->rname;
677       aop->size = getSize (sym->type);
678       return aop;
679     }
680   /* if it is in direct space */
681   if (IN_DIRSPACE (space))
682     {
683       //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
684       //printTypeChainRaw(sym->type, NULL);
685       //printf("space = %s\n", space ? space->sname : "NULL");
686       sym->aop = aop = newAsmop (AOP_DIR);
687       aop->aopu.aop_dir = sym->rname;
688       aop->size = getSize (sym->type);
689       return aop;
690     }
691
692   /* special case for a function */
693   if (IS_FUNC (sym->type))
694     {
695       sym->aop = aop = newAsmop (AOP_IMMD);
696       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
697       aop->size = getSize (sym->type);
698       return aop;
699     }
700
701   /* only remaining is far space */
702   /* in which case DPTR gets the address */
703   sym->aop = aop = newAsmop (AOP_DPTR);
704   emitcode ("mov", "dptr,#%s", sym->rname);
705   aop->size = getSize (sym->type);
706
707   /* if it is in code space */
708   if (IN_CODESPACE (space))
709     aop->code = 1;
710
711   return aop;
712 }
713
714 /*-----------------------------------------------------------------*/
715 /* aopForRemat - rematerializes an object                          */
716 /*-----------------------------------------------------------------*/
717 static asmop *
718 aopForRemat (symbol * sym)
719 {
720   iCode *ic = sym->rematiCode;
721   asmop *aop = newAsmop (AOP_IMMD);
722   int ptr_type = 0;
723   int val = 0;
724
725   for (;;)
726     {
727       if (ic->op == '+')
728         val += (int) operandLitValue (IC_RIGHT (ic));
729       else if (ic->op == '-')
730         val -= (int) operandLitValue (IC_RIGHT (ic));
731       else if (IS_CAST_ICODE(ic))
732         {
733           sym_link *from_type = operandType(IC_RIGHT(ic));
734           aop->aopu.aop_immd.from_cast_remat = 1;
735           ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
736           ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
737           continue;
738         }
739       else break;
740
741       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
742     }
743
744   if (val)
745     {
746       SNPRINTF (buffer, sizeof(buffer),
747                 "(%s %c 0x%04x)",
748                 OP_SYMBOL (IC_LEFT (ic))->rname,
749                 val >= 0 ? '+' : '-',
750                 abs (val) & 0xffff);
751     }
752   else
753     {
754       strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
755     }
756
757   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
758   /* set immd2 field if required */
759   if (aop->aopu.aop_immd.from_cast_remat)
760     {
761       SNPRINTF (buffer, sizeof(buffer), "#0x%02x", ptr_type);
762       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
763     }
764
765   return aop;
766 }
767
768 /*-----------------------------------------------------------------*/
769 /* regsInCommon - two operands have some registers in common       */
770 /*-----------------------------------------------------------------*/
771 static bool
772 regsInCommon (operand * op1, operand * op2)
773 {
774   symbol *sym1, *sym2;
775   int i;
776
777   /* if they have registers in common */
778   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
779     return FALSE;
780
781   sym1 = OP_SYMBOL (op1);
782   sym2 = OP_SYMBOL (op2);
783
784   if (sym1->nRegs == 0 || sym2->nRegs == 0)
785     return FALSE;
786
787   for (i = 0; i < sym1->nRegs; i++)
788     {
789       int j;
790       if (!sym1->regs[i])
791         continue;
792
793       for (j = 0; j < sym2->nRegs; j++)
794         {
795           if (!sym2->regs[j])
796             continue;
797
798           if (sym2->regs[j] == sym1->regs[i])
799             return TRUE;
800         }
801     }
802
803   return FALSE;
804 }
805
806 /*-----------------------------------------------------------------*/
807 /* operandsEqu - equivalent                                        */
808 /*-----------------------------------------------------------------*/
809 static bool
810 operandsEqu (operand * op1, operand * op2)
811 {
812   symbol *sym1, *sym2;
813
814   /* if they're not symbols */
815   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
816     return FALSE;
817
818   sym1 = OP_SYMBOL (op1);
819   sym2 = OP_SYMBOL (op2);
820
821   /* if both are itemps & one is spilt
822      and the other is not then false */
823   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
824       sym1->isspilt != sym2->isspilt)
825     return FALSE;
826
827   /* if they are the same */
828   if (sym1 == sym2)
829     return TRUE;
830
831   /* if they have the same rname */
832   if (sym1->rname[0] && sym2->rname[0] &&
833       strcmp (sym1->rname, sym2->rname) == 0 &&
834       !(IS_PARM (op2) && IS_ITEMP (op1)))
835     return TRUE;
836
837   /* if left is a tmp & right is not */
838   if (IS_ITEMP (op1) &&
839       !IS_ITEMP (op2) &&
840       sym1->isspilt &&
841       (sym1->usl.spillLoc == sym2))
842     return TRUE;
843
844   if (IS_ITEMP (op2) &&
845       !IS_ITEMP (op1) &&
846       sym2->isspilt &&
847       sym1->level > 0 &&
848       (sym2->usl.spillLoc == sym1))
849     return TRUE;
850
851   return FALSE;
852 }
853
854 /*-----------------------------------------------------------------*/
855 /* sameByte - two asmops have the same address at given offsets    */
856 /*-----------------------------------------------------------------*/
857 static bool
858 sameByte (asmop * aop1, int off1, asmop * aop2, int off2)
859 {
860   if (aop1 == aop2 && off1 == off2)
861     return TRUE;
862
863   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
864     return FALSE;
865
866   if (aop1->type != aop2->type)
867     return FALSE;
868
869   if (aop1->aopu.aop_reg[off1] != aop2->aopu.aop_reg[off2])
870     return FALSE;
871
872   return TRUE;
873 }
874
875 /*-----------------------------------------------------------------*/
876 /* sameRegs - two asmops have the same registers                   */
877 /*-----------------------------------------------------------------*/
878 static bool
879 sameRegs (asmop * aop1, asmop * aop2)
880 {
881   int i;
882
883   if (aop1 == aop2)
884     return TRUE;
885
886   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
887     return FALSE;
888
889   if (aop1->type != aop2->type)
890     return FALSE;
891
892   if (aop1->size != aop2->size)
893     return FALSE;
894
895   for (i = 0; i < aop1->size; i++)
896     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
897       return FALSE;
898
899   return TRUE;
900 }
901
902 /*-----------------------------------------------------------------*/
903 /* aopOp - allocates an asmop for an operand  :                    */
904 /*-----------------------------------------------------------------*/
905 static void
906 aopOp (operand * op, iCode * ic, bool result)
907 {
908   asmop *aop;
909   symbol *sym;
910   int i;
911
912   if (!op)
913     return;
914
915   /* if this a literal */
916   if (IS_OP_LITERAL (op))
917     {
918       op->aop = aop = newAsmop (AOP_LIT);
919       aop->aopu.aop_lit = op->operand.valOperand;
920       aop->size = getSize (operandType (op));
921       return;
922     }
923
924   /* if already has a asmop then continue */
925   if (op->aop)
926     {
927       op->aop->allocated++;
928       return;
929     }
930
931   /* if the underlying symbol has a aop */
932   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
933     {
934       op->aop = OP_SYMBOL (op)->aop;
935       op->aop->allocated++;
936       return;
937     }
938
939   /* if this is a true symbol */
940   if (IS_TRUE_SYMOP (op))
941     {
942       op->aop = aopForSym (ic, OP_SYMBOL (op), result);
943       return;
944     }
945
946   /* this is a temporary : this has
947      only five choices :
948      a) register
949      b) spillocation
950      c) rematerialize
951      d) conditional
952      e) can be a return use only */
953
954   sym = OP_SYMBOL (op);
955
956   /* if the type is a conditional */
957   if (sym->regType == REG_CND)
958     {
959       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
960       aop->size = sym->ruonly ? 1 : 0;
961       return;
962     }
963
964   /* if it is spilt then two situations
965      a) is rematerialize
966      b) has a spill location */
967   if (sym->isspilt || sym->nRegs == 0)
968     {
969
970       /* rematerialize it NOW */
971       if (sym->remat)
972         {
973           sym->aop = op->aop = aop = aopForRemat (sym);
974           aop->size = operandSize (op);
975           return;
976         }
977
978       if (sym->accuse)
979         {
980           int i;
981           sym->aop = op->aop = aop = newAsmop (AOP_ACC);
982           aop->size = getSize (sym->type);
983           for (i = 0; i < 2; i++)
984             aop->aopu.aop_str[i] = accUse[i];
985           return;
986         }
987
988       if (sym->ruonly)
989         {
990           unsigned i;
991
992           sym->aop = op->aop = aop = newAsmop (AOP_STR);
993           aop->size = getSize (sym->type);
994           for (i = 0; i < fReturnSizeMCS51; i++)
995             aop->aopu.aop_str[i] = fReturn[i];
996           return;
997         }
998
999       if (sym->usl.spillLoc)
1000         {
1001           asmop *oldAsmOp = NULL;
1002
1003           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1004             {
1005               /* force a new aop if sizes differ */
1006               oldAsmOp = sym->usl.spillLoc->aop;
1007               sym->usl.spillLoc->aop = NULL;
1008             }
1009           sym->aop = op->aop = aop =
1010                      aopForSym (ic, sym->usl.spillLoc, result);
1011           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1012             {
1013               /* Don't reuse the new aop, go with the last one */
1014               sym->usl.spillLoc->aop = oldAsmOp;
1015             }
1016           aop->size = getSize (sym->type);
1017           return;
1018         }
1019
1020       /* else must be a dummy iTemp */
1021       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1022       aop->size = getSize (sym->type);
1023       return;
1024     }
1025
1026   /* if the type is a bit register */
1027   if (sym->regType == REG_BIT)
1028     {
1029       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1030       aop->size = sym->nRegs;//1???
1031       aop->aopu.aop_reg[0] = sym->regs[0];
1032       aop->aopu.aop_dir = sym->regs[0]->name;
1033       return;
1034     }
1035
1036   /* must be in a register */
1037   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1038   aop->size = sym->nRegs;
1039   for (i = 0; i < sym->nRegs; i++)
1040     aop->aopu.aop_reg[i] = sym->regs[i];
1041 }
1042
1043 /*-----------------------------------------------------------------*/
1044 /* freeAsmop - free up the asmop given to an operand               */
1045 /*----------------------------------------------------------------*/
1046 static void
1047 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1048 {
1049   asmop *aop;
1050
1051   if (!op)
1052     aop = aaop;
1053   else
1054     aop = op->aop;
1055
1056   if (!aop)
1057     return;
1058
1059   aop->allocated--;
1060
1061   if (aop->allocated)
1062     goto dealloc;
1063
1064   /* depending on the asmop type only three cases need work
1065      AOP_R0, AOP_R1 & AOP_STK */
1066   switch (aop->type)
1067     {
1068     case AOP_R0:
1069       if (R0INB)
1070         {
1071           emitcode ("mov", "r0,b");
1072           R0INB--;
1073         }
1074       else if (_G.r0Pushed)
1075         {
1076           if (pop)
1077             {
1078               emitcode ("pop", "ar0");
1079               _G.r0Pushed--;
1080             }
1081         }
1082       bitVectUnSetBit (ic->rUsed, R0_IDX);
1083       break;
1084
1085     case AOP_R1:
1086       if (R1INB)
1087         {
1088           emitcode ("mov", "r1,b");
1089           R1INB--;
1090         }
1091       else if (_G.r1Pushed)
1092         {
1093           if (pop)
1094             {
1095               emitcode ("pop", "ar1");
1096               _G.r1Pushed--;
1097             }
1098         }
1099       bitVectUnSetBit (ic->rUsed, R1_IDX);
1100       break;
1101
1102     case AOP_STK:
1103       {
1104         int sz = aop->size;
1105         int stk = aop->aopu.aop_stk + aop->size - 1;
1106         bitVectUnSetBit (ic->rUsed, R0_IDX);
1107         bitVectUnSetBit (ic->rUsed, R1_IDX);
1108
1109         getFreePtr (ic, &aop, FALSE);
1110
1111         if (stk)
1112           {
1113             emitcode ("mov", "a,_bp");
1114             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1115             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1116           }
1117         else
1118           {
1119             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1120           }
1121
1122         while (sz--)
1123           {
1124             emitcode ("pop", "acc");
1125             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1126             if (!sz)
1127               break;
1128             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1129           }
1130         op->aop = aop;
1131         freeAsmop (op, NULL, ic, TRUE);
1132         if (_G.r1Pushed)
1133           {
1134             emitcode ("pop", "ar1");
1135             _G.r1Pushed--;
1136           }
1137         if (_G.r0Pushed)
1138           {
1139             emitcode ("pop", "ar0");
1140             _G.r0Pushed--;
1141           }
1142       }
1143       break;
1144     }
1145
1146 dealloc:
1147   /* all other cases just dealloc */
1148   if (op)
1149     {
1150       op->aop = NULL;
1151       if (IS_SYMOP (op))
1152         {
1153           OP_SYMBOL (op)->aop = NULL;
1154           /* if the symbol has a spill */
1155           if (SPIL_LOC (op))
1156             SPIL_LOC (op)->aop = NULL;
1157         }
1158     }
1159 }
1160
1161 /*------------------------------------------------------------------*/
1162 /* freeForBranchAsmop - partial free up of Asmop for a branch; just */
1163 /*                      pop r0 or r1 off stack if pushed            */
1164 /*------------------------------------------------------------------*/
1165 static void
1166 freeForBranchAsmop (operand * op)
1167 {
1168   asmop *aop;
1169
1170   if (!op)
1171     return;
1172
1173   aop = op->aop;
1174
1175   if (!aop)
1176     return;
1177
1178   if (!aop->allocated)
1179     return;
1180
1181   switch (aop->type)
1182     {
1183     case AOP_R0:
1184       if (R0INB)
1185         {
1186           emitcode ("mov", "r0,b");
1187         }
1188       else if (_G.r0Pushed)
1189         {
1190           emitcode ("pop", "ar0");
1191         }
1192       break;
1193
1194     case AOP_R1:
1195       if (R1INB)
1196         {
1197           emitcode ("mov", "r1,b");
1198         }
1199       else if (_G.r1Pushed)
1200         {
1201           emitcode ("pop", "ar1");
1202         }
1203       break;
1204
1205     case AOP_STK:
1206       {
1207         int sz = aop->size;
1208         int stk = aop->aopu.aop_stk + aop->size - 1;
1209
1210         emitcode ("mov", "b,r0");
1211         if (stk)
1212           {
1213             emitcode ("mov", "a,_bp");
1214             emitcode ("add", "a,#0x%02x", ((char) stk) & 0xff);
1215             emitcode ("mov", "r0,a");
1216           }
1217         else
1218           {
1219             emitcode ("mov", "r0,_bp");
1220           }
1221
1222         while (sz--)
1223           {
1224             emitcode ("pop", "acc");
1225             emitcode ("mov", "@r0,a");
1226             if (!sz)
1227               break;
1228             emitcode ("dec", "r0");
1229           }
1230         emitcode ("mov", "r0,b");
1231       }
1232     }
1233
1234 }
1235
1236 /*-----------------------------------------------------------------*/
1237 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1238 /*                 clobber the accumulator                         */
1239 /*-----------------------------------------------------------------*/
1240 static bool
1241 aopGetUsesAcc (operand * oper, int offset)
1242 {
1243   asmop * aop = AOP (oper);
1244
1245   if (offset > (aop->size - 1))
1246     return FALSE;
1247
1248   switch (aop->type)
1249     {
1250
1251     case AOP_R0:
1252     case AOP_R1:
1253       if (aop->paged)
1254         return TRUE;
1255       return FALSE;
1256     case AOP_DPTR:
1257       return TRUE;
1258     case AOP_IMMD:
1259       return FALSE;
1260     case AOP_DIR:
1261       return FALSE;
1262     case AOP_REG:
1263       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1264       return FALSE;
1265     case AOP_CRY:
1266       return TRUE;
1267     case AOP_ACC:
1268       if (offset)
1269         return FALSE;
1270       return TRUE;
1271     case AOP_LIT:
1272       return FALSE;
1273     case AOP_STR:
1274       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1275         return TRUE;
1276       return FALSE;
1277     case AOP_DUMMY:
1278       return FALSE;
1279     default:
1280       /* Error case --- will have been caught already */
1281       wassert(0);
1282       return FALSE;
1283     }
1284 }
1285
1286 /*-------------------------------------------------------------------*/
1287 /* aopGet - for fetching value of the aop                            */
1288 /*-------------------------------------------------------------------*/
1289 static char *
1290 aopGet (operand * oper, int offset, bool bit16, bool dname)
1291 {
1292   asmop * aop = AOP (oper);
1293
1294   /* offset is greater than
1295      size then zero */
1296   if (offset > (aop->size - 1) &&
1297       aop->type != AOP_LIT)
1298     return zero;
1299
1300   /* depending on type */
1301   switch (aop->type)
1302     {
1303     case AOP_DUMMY:
1304       return zero;
1305
1306     case AOP_R0:
1307     case AOP_R1:
1308       /* if we need to increment it */
1309       while (offset > aop->coff)
1310         {
1311           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1312           aop->coff++;
1313         }
1314
1315       while (offset < aop->coff)
1316         {
1317           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1318           aop->coff--;
1319         }
1320
1321       aop->coff = offset;
1322       if (aop->paged)
1323         {
1324           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1325           return (dname ? "acc" : "a");
1326         }
1327       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1328       return Safe_strdup(buffer);
1329
1330     case AOP_DPTR:
1331       if (aop->code && aop->coff==0 && offset>=1) {
1332         emitcode ("mov", "a,#0x%02x", offset);
1333         emitcode ("movc", "a,@a+dptr");
1334         return (dname ? "acc" : "a");
1335       }
1336
1337       while (offset > aop->coff)
1338         {
1339           emitcode ("inc", "dptr");
1340           aop->coff++;
1341         }
1342
1343       while (offset < aop->coff)
1344         {
1345           emitcode ("lcall", "__decdptr");
1346           aop->coff--;
1347         }
1348
1349       aop->coff = offset;
1350       if (aop->code)
1351         {
1352           emitcode ("clr", "a");
1353           emitcode ("movc", "a,@a+dptr");
1354         }
1355       else
1356         {
1357           emitcode ("movx", "a,@dptr");
1358         }
1359       return (dname ? "acc" : "a");
1360
1361     case AOP_IMMD:
1362       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1363         {
1364           SNPRINTF(buffer, sizeof(buffer),
1365                    "%s",aop->aopu.aop_immd.aop_immd2);
1366         }
1367       else if (bit16)
1368         {
1369           SNPRINTF(buffer, sizeof(buffer),
1370                    "#%s", aop->aopu.aop_immd.aop_immd1);
1371         }
1372       else if (offset)
1373         {
1374           SNPRINTF (buffer, sizeof(buffer),
1375                     "#(%s >> %d)",
1376                     aop->aopu.aop_immd.aop_immd1,
1377                     offset * 8);
1378         }
1379       else
1380         {
1381           SNPRINTF (buffer, sizeof(buffer),
1382                     "#%s",
1383                     aop->aopu.aop_immd.aop_immd1);
1384         }
1385       return Safe_strdup(buffer);
1386
1387     case AOP_DIR:
1388       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1389         {
1390           SNPRINTF (buffer, sizeof(buffer),
1391                     "(%s >> %d)",
1392                     aop->aopu.aop_dir, offset * 8);
1393         }
1394       else if (offset)
1395         {
1396           SNPRINTF (buffer, sizeof(buffer),
1397                     "(%s + %d)",
1398                     aop->aopu.aop_dir,
1399                     offset);
1400         }
1401       else
1402         {
1403           SNPRINTF (buffer, sizeof(buffer),
1404                     "%s",
1405                     aop->aopu.aop_dir);
1406         }
1407
1408       return Safe_strdup(buffer);
1409
1410     case AOP_REG:
1411       if (dname)
1412         return aop->aopu.aop_reg[offset]->dname;
1413       else
1414         return aop->aopu.aop_reg[offset]->name;
1415
1416     case AOP_CRY:
1417       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1418       emitcode ("clr", "a");
1419       emitcode ("rlc", "a");
1420       return (dname ? "acc" : "a");
1421
1422     case AOP_ACC:
1423       if (!offset && dname)
1424         return "acc";
1425       return aop->aopu.aop_str[offset];
1426
1427     case AOP_LIT:
1428       return aopLiteral (aop->aopu.aop_lit, offset);
1429
1430     case AOP_STR:
1431       aop->coff = offset;
1432       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1433           dname)
1434         return "acc";
1435
1436       return aop->aopu.aop_str[offset];
1437
1438     }
1439
1440   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1441           "aopget got unsupported aop->type");
1442   exit (1);
1443 }
1444
1445 /*-----------------------------------------------------------------*/
1446 /* aopPutUsesAcc - indicates ahead of time whether aopPut() will   */
1447 /*                 clobber the accumulator                         */
1448 /*-----------------------------------------------------------------*/
1449 static bool
1450 aopPutUsesAcc (operand * oper, const char *s, int offset)
1451 {
1452   asmop * aop = AOP (oper);
1453
1454   if (offset > (aop->size - 1))
1455     return FALSE;
1456
1457   switch (aop->type)
1458     {
1459     case AOP_DUMMY:
1460       return TRUE;
1461     case AOP_DIR:
1462       return FALSE;
1463     case AOP_REG:
1464       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1465       return FALSE;
1466     case AOP_DPTR:
1467       return TRUE;
1468     case AOP_R0:
1469     case AOP_R1:
1470       return ((aop->paged) || (*s == '@'));
1471     case AOP_STK:
1472       return (*s == '@');
1473     case AOP_CRY:
1474       return (!aop->aopu.aop_dir || strcmp(s, aop->aopu.aop_dir));
1475     case AOP_STR:
1476       return FALSE;
1477     case AOP_IMMD:
1478       return FALSE;
1479     case AOP_ACC:
1480       return FALSE;
1481     default:
1482       /* Error case --- will have been caught already */
1483       wassert(0);
1484       return FALSE;
1485     }
1486 }
1487
1488 /*-----------------------------------------------------------------*/
1489 /* aopPut - puts a string for a aop and indicates if acc is in use */
1490 /*-----------------------------------------------------------------*/
1491 static bool
1492 aopPut (operand * result, const char *s, int offset)
1493 {
1494   bool bvolatile = isOperandVolatile (result, FALSE);
1495   bool accuse = FALSE;
1496   asmop * aop = AOP (result);
1497   const char *d = NULL;
1498
1499   if (aop->size && offset > (aop->size - 1))
1500     {
1501       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1502               "aopPut got offset > aop->size");
1503       exit (1);
1504     }
1505
1506   /* will assign value to value */
1507   /* depending on where it is ofcourse */
1508   switch (aop->type)
1509     {
1510     case AOP_DUMMY:
1511       MOVA (s);         /* read s in case it was volatile */
1512       accuse = TRUE;
1513       break;
1514
1515     case AOP_DIR:
1516       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1517         {
1518           SNPRINTF (buffer, sizeof(buffer),
1519                     "(%s >> %d)",
1520                     aop->aopu.aop_dir, offset * 8);
1521         }
1522       else if (offset)
1523         {
1524           SNPRINTF (buffer, sizeof(buffer),
1525                     "(%s + %d)",
1526                     aop->aopu.aop_dir, offset);
1527         }
1528       else
1529         {
1530           SNPRINTF (buffer, sizeof(buffer),
1531                     "%s",
1532                     aop->aopu.aop_dir);
1533         }
1534
1535       if (strcmp (buffer, s) || bvolatile)
1536         {
1537           emitcode ("mov", "%s,%s", buffer, s);
1538         }
1539       if (!strcmp (buffer, "acc"))
1540         {
1541           accuse = TRUE;
1542         }
1543       break;
1544
1545     case AOP_REG:
1546       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1547           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1548         {
1549           if (*s == '@' ||
1550               strcmp (s, "r0") == 0 ||
1551               strcmp (s, "r1") == 0 ||
1552               strcmp (s, "r2") == 0 ||
1553               strcmp (s, "r3") == 0 ||
1554               strcmp (s, "r4") == 0 ||
1555               strcmp (s, "r5") == 0 ||
1556               strcmp (s, "r6") == 0 ||
1557               strcmp (s, "r7") == 0)
1558             {
1559               emitcode ("mov", "%s,%s",
1560                         aop->aopu.aop_reg[offset]->dname, s);
1561             }
1562           else
1563             {
1564               emitcode ("mov", "%s,%s",
1565                         aop->aopu.aop_reg[offset]->name, s);
1566             }
1567         }
1568       break;
1569
1570     case AOP_DPTR:
1571       if (aop->code)
1572         {
1573           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1574                   "aopPut writing to code space");
1575           exit (1);
1576         }
1577
1578       while (offset > aop->coff)
1579         {
1580           aop->coff++;
1581           emitcode ("inc", "dptr");
1582         }
1583
1584       while (offset < aop->coff)
1585         {
1586           aop->coff--;
1587           emitcode ("lcall", "__decdptr");
1588         }
1589
1590       aop->coff = offset;
1591
1592       /* if not in accumulator */
1593       MOVA (s);
1594
1595       emitcode ("movx", "@dptr,a");
1596       break;
1597
1598     case AOP_R0:
1599     case AOP_R1:
1600       while (offset > aop->coff)
1601         {
1602           aop->coff++;
1603           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1604         }
1605       while (offset < aop->coff)
1606         {
1607           aop->coff--;
1608           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1609         }
1610       aop->coff = offset;
1611
1612       if (aop->paged)
1613         {
1614           MOVA (s);
1615           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1616         }
1617       else if (*s == '@')
1618         {
1619           MOVA (s);
1620           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1621         }
1622       else if (strcmp (s, "r0") == 0 ||
1623                strcmp (s, "r1") == 0 ||
1624                strcmp (s, "r2") == 0 ||
1625                strcmp (s, "r3") == 0 ||
1626                strcmp (s, "r4") == 0 ||
1627                strcmp (s, "r5") == 0 ||
1628                strcmp (s, "r6") == 0 ||
1629                strcmp (s, "r7") == 0)
1630         {
1631           char buffer[10];
1632           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1633           emitcode ("mov", "@%s,%s",
1634                     aop->aopu.aop_ptr->name, buffer);
1635         }
1636       else
1637         {
1638           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1639         }
1640       break;
1641
1642     case AOP_STK:
1643       if (strcmp (s, "a") == 0)
1644         {
1645           emitcode ("push", "acc");
1646         }
1647       else if (*s=='@')
1648         {
1649           MOVA(s);
1650           emitcode ("push", "acc");
1651         }
1652       else if (strcmp (s, "r0") == 0 ||
1653                strcmp (s, "r1") == 0 ||
1654                strcmp (s, "r2") == 0 ||
1655                strcmp (s, "r3") == 0 ||
1656                strcmp (s, "r4") == 0 ||
1657                strcmp (s, "r5") == 0 ||
1658                strcmp (s, "r6") == 0 ||
1659                strcmp (s, "r7") == 0)
1660         {
1661           char buffer[10];
1662           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1663           emitcode ("push", buffer);
1664         }
1665       else
1666         {
1667           emitcode ("push", s);
1668         }
1669
1670       break;
1671
1672     case AOP_CRY:
1673       // destination is carry for return-use-only
1674       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1675       // source is no literal and not in carry
1676       if ((s != zero) && (s != one) && strcmp (s, "c"))
1677         {
1678           MOVA (s);
1679           /* set C, if a >= 1 */
1680           emitcode ("add", "a,#0xff");
1681           s = "c";
1682         }
1683       // now source is zero, one or carry
1684
1685       /* if result no bit variable */
1686       if (!d)
1687         {
1688           if (!strcmp (s, "c"))
1689             {
1690               /* inefficient: move carry into A and use jz/jnz */
1691               emitcode ("clr", "a");
1692               emitcode ("rlc", "a");
1693               accuse = TRUE;
1694             }
1695           else
1696             {
1697               MOVA (s);
1698               accuse = TRUE;
1699             }
1700         }
1701       else if (s == zero)
1702           emitcode ("clr", "%s", d);
1703       else if (s == one)
1704           emitcode ("setb", "%s", d);
1705       else if (strcmp (s, d))
1706           emitcode ("mov", "%s,c", d);
1707       break;
1708
1709     case AOP_STR:
1710       aop->coff = offset;
1711       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1712         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1713       break;
1714
1715     case AOP_ACC:
1716       accuse = TRUE;
1717       aop->coff = offset;
1718       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1719         break;
1720
1721       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1722         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1723       break;
1724
1725     default:
1726       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1727               "aopPut got unsupported aop->type");
1728       exit (1);
1729     }
1730
1731     return accuse;
1732 }
1733
1734
1735 #if 0
1736 /*-----------------------------------------------------------------*/
1737 /* pointToEnd :- points to the last byte of the operand            */
1738 /*-----------------------------------------------------------------*/
1739 static void
1740 pointToEnd (asmop * aop)
1741 {
1742   int count;
1743   if (!aop)
1744     return;
1745
1746   aop->coff = count = (aop->size - 1);
1747   switch (aop->type)
1748     {
1749     case AOP_R0:
1750     case AOP_R1:
1751       while (count--)
1752         emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1753       break;
1754     case AOP_DPTR:
1755       while (count--)
1756         emitcode ("inc", "dptr");
1757       break;
1758     }
1759
1760 }
1761 #endif
1762
1763 /*-----------------------------------------------------------------*/
1764 /* reAdjustPreg - points a register back to where it should        */
1765 /*-----------------------------------------------------------------*/
1766 static void
1767 reAdjustPreg (asmop * aop)
1768 {
1769   if ((aop->coff==0) || (aop->size <= 1))
1770     return;
1771
1772   switch (aop->type)
1773     {
1774     case AOP_R0:
1775     case AOP_R1:
1776       while (aop->coff--)
1777         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1778       break;
1779     case AOP_DPTR:
1780       while (aop->coff--)
1781         {
1782           emitcode ("lcall", "__decdptr");
1783         }
1784       break;
1785     }
1786   aop->coff = 0;
1787 }
1788
1789 /*-----------------------------------------------------------------*/
1790 /* opIsGptr: returns non-zero if the passed operand is       */
1791 /* a generic pointer type.             */
1792 /*-----------------------------------------------------------------*/
1793 static int
1794 opIsGptr (operand * op)
1795 {
1796   sym_link *type = operandType (op);
1797
1798   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1799     {
1800       return 1;
1801     }
1802   return 0;
1803 }
1804
1805 /*-----------------------------------------------------------------*/
1806 /* getDataSize - get the operand data size                         */
1807 /*-----------------------------------------------------------------*/
1808 static int
1809 getDataSize (operand * op)
1810 {
1811   int size;
1812   size = AOP_SIZE (op);
1813   if (size == GPTRSIZE)
1814     {
1815       sym_link *type = operandType (op);
1816       if (IS_GENPTR (type))
1817         {
1818           /* generic pointer; arithmetic operations
1819            * should ignore the high byte (pointer type).
1820            */
1821           size--;
1822         }
1823     }
1824   return size;
1825 }
1826
1827 /*-----------------------------------------------------------------*/
1828 /* outAcc - output Acc                                             */
1829 /*-----------------------------------------------------------------*/
1830 static void
1831 outAcc (operand * result)
1832 {
1833   int size, offset;
1834   size = getDataSize (result);
1835   if (size)
1836     {
1837       aopPut (result, "a", 0);
1838       size--;
1839       offset = 1;
1840       /* unsigned or positive */
1841       while (size--)
1842         {
1843           aopPut (result, zero, offset++);
1844         }
1845     }
1846 }
1847
1848 /*-----------------------------------------------------------------*/
1849 /* outBitC - output a bit C                                        */
1850 /*-----------------------------------------------------------------*/
1851 static void
1852 outBitC (operand * result)
1853 {
1854   /* if the result is bit */
1855   if (AOP_TYPE (result) == AOP_CRY)
1856     {
1857       if (!IS_OP_RUONLY (result))
1858         aopPut (result, "c", 0);
1859     }
1860   else if (AOP_TYPE (result) != AOP_DUMMY)
1861     {
1862       emitcode ("clr", "a");
1863       emitcode ("rlc", "a");
1864       outAcc (result);
1865     }
1866 }
1867
1868 /*-----------------------------------------------------------------*/
1869 /* toBoolean - emit code for orl a,operator(sizeop)                */
1870 /*-----------------------------------------------------------------*/
1871 static void
1872 toBoolean (operand * oper)
1873 {
1874   int size = AOP_SIZE (oper) - 1;
1875   int offset = 1;
1876   bool AccUsed = FALSE;
1877   bool pushedB;
1878
1879   while (!AccUsed && size--)
1880     {
1881       AccUsed |= aopGetUsesAcc(oper, offset++);
1882     }
1883
1884   size = AOP_SIZE (oper) - 1;
1885   offset = 1;
1886   MOVA (aopGet (oper, 0, FALSE, FALSE));
1887   if (size && AccUsed && (AOP (oper)->type != AOP_ACC))
1888     {
1889       pushedB = pushB ();
1890       emitcode("mov", "b,a");
1891       while (--size)
1892         {
1893           MOVA (aopGet (oper, offset++, FALSE, FALSE));
1894           emitcode ("orl", "b,a");
1895         }
1896       MOVA (aopGet (oper, offset++, FALSE, FALSE));
1897       emitcode ("orl", "a,b");
1898       popB (pushedB);
1899     }
1900   else
1901     {
1902       while (size--)
1903         {
1904           emitcode ("orl", "a,%s",
1905                     aopGet (oper, offset++, FALSE, FALSE));
1906         }
1907     }
1908 }
1909
1910 /*-----------------------------------------------------------------*/
1911 /* toCarry - make boolean and move into carry                      */
1912 /*-----------------------------------------------------------------*/
1913 static void
1914 toCarry (operand * oper)
1915 {
1916   /* if the operand is a literal then
1917      we know what the value is */
1918   if (AOP_TYPE (oper) == AOP_LIT)
1919     {
1920       if ((int) operandLitValue (oper))
1921         SETC;
1922       else
1923         CLRC;
1924     }
1925   else if (AOP_TYPE (oper) == AOP_CRY)
1926     {
1927       emitcode ("mov", "c,%s", oper->aop->aopu.aop_dir);
1928     }
1929   else
1930     {
1931       /* or the operand into a */
1932       toBoolean (oper);
1933       /* set C, if a >= 1 */
1934       emitcode ("add", "a,#0xff");
1935     }
1936 }
1937
1938 /*-----------------------------------------------------------------*/
1939 /* assignBit - assign operand to bit operand                       */
1940 /*-----------------------------------------------------------------*/
1941 static void
1942 assignBit (operand * result, operand * right)
1943 {
1944   /* if the right side is a literal then
1945      we know what the value is */
1946   if (AOP_TYPE (right) == AOP_LIT)
1947     {
1948       if ((int) operandLitValue (right))
1949         aopPut (result, one, 0);
1950       else
1951         aopPut (result, zero, 0);
1952     }
1953   else
1954     {
1955       toCarry (right);
1956       aopPut (result, "c", 0);
1957     }
1958 }
1959
1960
1961 /*-------------------------------------------------------------------*/
1962 /* xch_a_aopGet - for exchanging acc with value of the aop           */
1963 /*-------------------------------------------------------------------*/
1964 static char *
1965 xch_a_aopGet (operand * oper, int offset, bool bit16, bool dname)
1966 {
1967   char * l;
1968
1969   if (aopGetUsesAcc (oper, offset))
1970     {
1971       emitcode("mov", "b,a");
1972       MOVA (aopGet (oper, offset, bit16, dname));
1973       emitcode("xch", "a,b");
1974       aopPut (oper, "a", offset);
1975       emitcode("xch", "a,b");
1976       l = "b";
1977     }
1978   else
1979     {
1980       l = aopGet (oper, offset, bit16, dname);
1981       emitcode("xch", "a,%s", l);
1982     }
1983   return l;
1984 }
1985
1986
1987 /*-----------------------------------------------------------------*/
1988 /* genNot - generate code for ! operation                          */
1989 /*-----------------------------------------------------------------*/
1990 static void
1991 genNot (iCode * ic)
1992 {
1993   symbol *tlbl;
1994
1995   D (emitcode (";", "genNot"));
1996
1997   /* assign asmOps to operand & result */
1998   aopOp (IC_LEFT (ic), ic, FALSE);
1999   aopOp (IC_RESULT (ic), ic, TRUE);
2000
2001   /* if in bit space then a special case */
2002   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2003     {
2004       /* if left==result then cpl bit */
2005       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2006         {
2007           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2008         }
2009       else
2010         {
2011           toCarry (IC_LEFT (ic));
2012           emitcode ("cpl", "c");
2013           outBitC (IC_RESULT (ic));
2014         }
2015       goto release;
2016     }
2017
2018   toBoolean (IC_LEFT (ic));
2019
2020   /* set C, if a == 0 */
2021   tlbl = newiTempLabel (NULL);
2022   emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
2023   emitLabel (tlbl);
2024   outBitC (IC_RESULT (ic));
2025
2026 release:
2027   /* release the aops */
2028   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2029   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2030 }
2031
2032
2033 /*-----------------------------------------------------------------*/
2034 /* genCpl - generate code for complement                           */
2035 /*-----------------------------------------------------------------*/
2036 static void
2037 genCpl (iCode * ic)
2038 {
2039   int offset = 0;
2040   int size;
2041   symbol *tlbl;
2042   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2043
2044   D(emitcode (";", "genCpl"));
2045
2046   /* assign asmOps to operand & result */
2047   aopOp (IC_LEFT (ic), ic, FALSE);
2048   aopOp (IC_RESULT (ic), ic, TRUE);
2049
2050   /* special case if in bit space */
2051   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2052     {
2053       char *l;
2054
2055       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2056           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2057         {
2058           /* promotion rules are responsible for this strange result:
2059              bit -> int -> ~int -> bit
2060              uchar -> int -> ~int -> bit
2061           */
2062           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2063           goto release;
2064         }
2065
2066       tlbl=newiTempLabel(NULL);
2067       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE);
2068       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2069           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2070           IS_AOP_PREG (IC_LEFT (ic)))
2071         {
2072           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2073         }
2074       else
2075         {
2076           MOVA (l);
2077           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2078         }
2079       emitLabel (tlbl);
2080       outBitC (IC_RESULT(ic));
2081       goto release;
2082     }
2083
2084   size = AOP_SIZE (IC_RESULT (ic));
2085   while (size--)
2086     {
2087       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2088       MOVA (l);
2089       emitcode ("cpl", "a");
2090       aopPut (IC_RESULT (ic), "a", offset++);
2091     }
2092
2093
2094 release:
2095   /* release the aops */
2096   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2097   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2098 }
2099
2100 /*-----------------------------------------------------------------*/
2101 /* genUminusFloat - unary minus for floating points                */
2102 /*-----------------------------------------------------------------*/
2103 static void
2104 genUminusFloat (operand * op, operand * result)
2105 {
2106   int size, offset = 0;
2107   char *l;
2108
2109   D (emitcode (";", "genUminusFloat"));
2110
2111   /* for this we just copy and then flip the bit */
2112
2113   size = AOP_SIZE (op) - 1;
2114
2115   while (size--)
2116     {
2117       aopPut (result,
2118               aopGet (op, offset, FALSE, FALSE),
2119               offset);
2120       offset++;
2121     }
2122
2123   l = aopGet (op, offset, FALSE, FALSE);
2124   MOVA (l);
2125
2126   emitcode ("cpl", "acc.7");
2127   aopPut (result, "a", offset);
2128 }
2129
2130 /*-----------------------------------------------------------------*/
2131 /* genUminus - unary minus code generation                         */
2132 /*-----------------------------------------------------------------*/
2133 static void
2134 genUminus (iCode * ic)
2135 {
2136   int offset, size;
2137   sym_link *optype;
2138
2139   D (emitcode (";", "genUminus"));
2140
2141   /* assign asmops */
2142   aopOp (IC_LEFT (ic), ic, FALSE);
2143   aopOp (IC_RESULT (ic), ic, TRUE);
2144
2145   /* if both in bit space then special
2146      case */
2147   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2148       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2149     {
2150
2151       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2152       emitcode ("cpl", "c");
2153       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2154       goto release;
2155     }
2156
2157   optype = operandType (IC_LEFT (ic));
2158
2159   /* if float then do float stuff */
2160   if (IS_FLOAT (optype))
2161     {
2162       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2163       goto release;
2164     }
2165
2166   /* otherwise subtract from zero */
2167   size = AOP_SIZE (IC_LEFT (ic));
2168   offset = 0;
2169   while (size--)
2170     {
2171       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
2172       if (!strcmp (l, "a"))
2173         {
2174           if (offset == 0)
2175             SETC;
2176           emitcode ("cpl", "a");
2177           emitcode ("addc", "a,#0");
2178         }
2179       else
2180         {
2181           if (offset == 0)
2182             CLRC;
2183           emitcode ("clr", "a");
2184           emitcode ("subb", "a,%s", l);
2185         }
2186       aopPut (IC_RESULT (ic), "a", offset++);
2187     }
2188
2189   /* if any remaining bytes in the result */
2190   /* we just need to propagate the sign   */
2191   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2192     {
2193       emitcode ("rlc", "a");
2194       emitcode ("subb", "a,acc");
2195       while (size--)
2196         aopPut (IC_RESULT (ic), "a", offset++);
2197     }
2198
2199 release:
2200   /* release the aops */
2201   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2202   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2203 }
2204
2205 /*-----------------------------------------------------------------*/
2206 /* saveRegisters - will look for a call and save the registers     */
2207 /*-----------------------------------------------------------------*/
2208 static void
2209 saveRegisters (iCode * lic)
2210 {
2211   int i;
2212   iCode *ic;
2213   bitVect *rsave;
2214
2215   /* look for call */
2216   for (ic = lic; ic; ic = ic->next)
2217     if (ic->op == CALL || ic->op == PCALL)
2218       break;
2219
2220   if (!ic)
2221     {
2222       fprintf (stderr, "found parameter push with no function call\n");
2223       return;
2224     }
2225
2226   /* if the registers have been saved already or don't need to be then
2227      do nothing */
2228   if (ic->regsSaved)
2229     return;
2230   if (IS_SYMOP(IC_LEFT(ic)) &&
2231       (IFFUNC_CALLEESAVES (OP_SYMBOL (IC_LEFT (ic))->type) ||
2232        IFFUNC_ISNAKED (OP_SYM_TYPE (IC_LEFT (ic)))))
2233     return;
2234
2235   /* save the registers in use at this time but skip the
2236      ones for the result */
2237   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2238                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2239
2240   ic->regsSaved = 1;
2241   if (options.useXstack)
2242     {
2243       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2244       int nBits = bitVectnBitsOn (rsavebits);
2245       int count = bitVectnBitsOn (rsave);
2246
2247       if (nBits != 0)
2248         {
2249           count = count - nBits + 1;
2250           /* remove all but the first bits as they are pushed all at once */
2251           rsave = bitVectCplAnd (rsave, rsavebits);
2252           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2253         }
2254       freeBitVect (rsavebits);
2255
2256       if (count == 1)
2257         {
2258           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2259           if (reg->type == REG_BIT)
2260             {
2261               emitcode ("mov", "a,%s", reg->base);
2262             }
2263           else
2264             {
2265               emitcode ("mov", "a,%s", reg->name);
2266             }
2267           emitcode ("mov", "r0,%s", spname);
2268           emitcode ("inc", "%s", spname);// allocate before use
2269           emitcode ("movx", "@r0,a");
2270           if (bitVectBitValue (rsave, R0_IDX))
2271             emitcode ("mov", "r0,a");
2272         }
2273       else if (count != 0)
2274         {
2275           if (bitVectBitValue (rsave, R0_IDX))
2276             {
2277               emitcode ("push", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2278             }
2279           emitcode ("mov", "r0,%s", spname);
2280           MOVA ("r0");
2281           emitcode ("add", "a,#%d", count);
2282           emitcode ("mov", "%s,a", spname);
2283           for (i = 0; i < mcs51_nRegs; i++)
2284             {
2285               if (bitVectBitValue (rsave, i))
2286                 {
2287                   regs * reg = REG_WITH_INDEX (i);
2288                   if (i == R0_IDX)
2289                     {
2290                       emitcode ("pop", "acc");
2291                       emitcode ("push", "acc");
2292                     }
2293                   else if (reg->type == REG_BIT)
2294                     {
2295                       emitcode ("mov", "a,%s", reg->base);
2296                     }
2297                   else
2298                     {
2299                       emitcode ("mov", "a,%s", reg->name);
2300                     }
2301                   emitcode ("movx", "@r0,a");
2302                   if (--count)
2303                     {
2304                       emitcode ("inc", "r0");
2305                     }
2306                 }
2307             }
2308           if (bitVectBitValue (rsave, R0_IDX))
2309             {
2310               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
2311             }
2312         }
2313     }
2314   else
2315     {
2316       bool bits_pushed = FALSE;
2317       for (i = 0; i < mcs51_nRegs; i++)
2318         {
2319           if (bitVectBitValue (rsave, i))
2320             {
2321               bits_pushed = pushReg (i, bits_pushed);
2322             }
2323         }
2324     }
2325   freeBitVect (rsave);
2326 }
2327
2328 /*-----------------------------------------------------------------*/
2329 /* unsaveRegisters - pop the pushed registers                      */
2330 /*-----------------------------------------------------------------*/
2331 static void
2332 unsaveRegisters (iCode * ic)
2333 {
2334   int i;
2335   bitVect *rsave;
2336
2337   /* restore the registers in use at this time but skip the
2338      ones for the result */
2339   rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2340                          mcs51_rUmaskForOp (IC_RESULT(ic)));
2341
2342   if (options.useXstack)
2343     {
2344       bitVect *rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), rsave);
2345       int nBits = bitVectnBitsOn (rsavebits);
2346       int count = bitVectnBitsOn (rsave);
2347
2348       if (nBits != 0)
2349         {
2350           count = count - nBits + 1;
2351           /* remove all but the first bits as they are popped all at once */
2352           rsave = bitVectCplAnd (rsave, rsavebits);
2353           rsave = bitVectSetBit (rsave, bitVectFirstBit (rsavebits));
2354         }
2355       freeBitVect (rsavebits);
2356
2357       if (count == 1)
2358         {
2359           regs * reg = REG_WITH_INDEX (bitVectFirstBit (rsave));
2360           emitcode ("mov", "r0,%s", spname);
2361           emitcode ("dec", "r0");
2362           emitcode ("movx", "a,@r0");
2363           if (reg->type == REG_BIT)
2364             {
2365               emitcode ("mov", "%s,a", reg->base);
2366             }
2367           else
2368             {
2369               emitcode ("mov", "%s,a", reg->name);
2370             }
2371           emitcode ("dec", "%s", spname);
2372         }
2373       else if (count != 0)
2374         {
2375           emitcode ("mov", "r0,%s", spname);
2376           for (i = mcs51_nRegs; i >= 0; i--)
2377             {
2378               if (bitVectBitValue (rsave, i))
2379                 {
2380                   regs * reg = REG_WITH_INDEX (i);
2381                   emitcode ("dec", "r0");
2382                   emitcode ("movx", "a,@r0");
2383                   if (i == R0_IDX)
2384                     {
2385                       emitcode ("push", "acc");
2386                     }
2387                   else if (reg->type == REG_BIT)
2388                     {
2389                       emitcode ("mov", "%s,a", reg->base);
2390                     }
2391                   else
2392                     {
2393                       emitcode ("mov", "%s,a", reg->name);
2394                     }
2395                 }
2396             }
2397           emitcode ("mov", "%s,r0", spname);
2398           if (bitVectBitValue (rsave, R0_IDX))
2399             {
2400               emitcode ("pop", "ar0");
2401             }
2402         }
2403     }
2404   else
2405     {
2406       bool bits_popped = FALSE;
2407       for (i = mcs51_nRegs; i >= 0; i--)
2408         {
2409           if (bitVectBitValue (rsave, i))
2410             {
2411               bits_popped = popReg (i, bits_popped);
2412             }
2413         }
2414     }
2415   freeBitVect (rsave);
2416 }
2417
2418
2419 /*-----------------------------------------------------------------*/
2420 /* pushSide -                                                      */
2421 /*-----------------------------------------------------------------*/
2422 static void
2423 pushSide (operand * oper, int size)
2424 {
2425   int offset = 0;
2426   while (size--)
2427     {
2428       char *l = aopGet (oper, offset++, FALSE, TRUE);
2429       if (AOP_TYPE (oper) != AOP_REG &&
2430           AOP_TYPE (oper) != AOP_DIR &&
2431           strcmp (l, "a"))
2432         {
2433           MOVA (l);
2434           emitcode ("push", "acc");
2435         }
2436       else
2437         {
2438           emitcode ("push", "%s", l);
2439         }
2440     }
2441 }
2442
2443 /*-----------------------------------------------------------------*/
2444 /* assignResultValue - also indicates if acc is in use afterwards  */
2445 /*-----------------------------------------------------------------*/
2446 static bool
2447 assignResultValue (operand * oper, operand * func)
2448 {
2449   int offset = 0;
2450   int size = AOP_SIZE (oper);
2451   bool accuse = FALSE;
2452   bool pushedA = FALSE;
2453
2454   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2455     {
2456       outBitC (oper);
2457       return FALSE;
2458     }
2459
2460   if ((size > 3) && aopPutUsesAcc (oper, fReturn[offset], offset))
2461     {
2462       emitcode ("push", "acc");
2463       pushedA = TRUE;
2464     }
2465   while (size--)
2466     {
2467       if ((offset == 3) && pushedA)
2468         emitcode ("pop", "acc");
2469       accuse |= aopPut (oper, fReturn[offset], offset);
2470       offset++;
2471     }
2472   return accuse;
2473 }
2474
2475
2476 /*-----------------------------------------------------------------*/
2477 /* genXpush - pushes onto the external stack                       */
2478 /*-----------------------------------------------------------------*/
2479 static void
2480 genXpush (iCode * ic)
2481 {
2482   asmop *aop = newAsmop (0);
2483   regs *r;
2484   int size, offset = 0;
2485
2486   D (emitcode (";", "genXpush"));
2487
2488   aopOp (IC_LEFT (ic), ic, FALSE);
2489   r = getFreePtr (ic, &aop, FALSE);
2490
2491   size = AOP_SIZE (IC_LEFT (ic));
2492
2493   if (size == 1)
2494     {
2495       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
2496       emitcode ("mov", "%s,%s", r->name, spname);
2497       emitcode ("inc", "%s", spname); // allocate space first
2498       emitcode ("movx", "@%s,a", r->name);
2499     }
2500   else
2501     {
2502       // allocate space first
2503       emitcode ("mov", "%s,%s", r->name, spname);
2504       MOVA (r->name);
2505       emitcode ("add", "a,#%d", size);
2506       emitcode ("mov", "%s,a", spname);
2507
2508       while (size--)
2509         {
2510           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE));
2511           emitcode ("movx", "@%s,a", r->name);
2512           emitcode ("inc", "%s", r->name);
2513         }
2514     }
2515
2516   freeAsmop (NULL, aop, ic, TRUE);
2517   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2518 }
2519
2520 /*-----------------------------------------------------------------*/
2521 /* genIpush - generate code for pushing this gets a little complex */
2522 /*-----------------------------------------------------------------*/
2523 static void
2524 genIpush (iCode * ic)
2525 {
2526   int size, offset = 0;
2527   char *l;
2528   char *prev = "";
2529
2530   D (emitcode (";", "genIpush"));
2531
2532   /* if this is not a parm push : ie. it is spill push
2533      and spill push is always done on the local stack */
2534   if (!ic->parmPush)
2535     {
2536
2537       /* and the item is spilt then do nothing */
2538       if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2539         return;
2540
2541       aopOp (IC_LEFT (ic), ic, FALSE);
2542       size = AOP_SIZE (IC_LEFT (ic));
2543       /* push it on the stack */
2544       while (size--)
2545         {
2546           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2547           if (*l == '#')
2548             {
2549               MOVA (l);
2550               l = "acc";
2551             }
2552           emitcode ("push", "%s", l);
2553         }
2554       return;
2555     }
2556
2557   /* this is a parameter push: in this case we call
2558      the routine to find the call and save those
2559      registers that need to be saved */
2560   saveRegisters (ic);
2561
2562   /* if use external stack then call the external
2563      stack pushing routine */
2564   if (options.useXstack)
2565     {
2566       genXpush (ic);
2567       return;
2568     }
2569
2570   /* then do the push */
2571   aopOp (IC_LEFT (ic), ic, FALSE);
2572
2573   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2574   size = AOP_SIZE (IC_LEFT (ic));
2575
2576   while (size--)
2577     {
2578       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
2579       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2580           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR)
2581         {
2582           if (strcmp (l, prev) || *l == '@')
2583             MOVA (l);
2584           emitcode ("push", "acc");
2585         }
2586       else
2587         {
2588           emitcode ("push", "%s", l);
2589         }
2590       prev = l;
2591     }
2592
2593   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2594 }
2595
2596 /*-----------------------------------------------------------------*/
2597 /* genIpop - recover the registers: can happen only for spilling   */
2598 /*-----------------------------------------------------------------*/
2599 static void
2600 genIpop (iCode * ic)
2601 {
2602   int size, offset;
2603
2604   D (emitcode (";", "genIpop"));
2605
2606   /* if the temp was not pushed then */
2607   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2608     return;
2609
2610   aopOp (IC_LEFT (ic), ic, FALSE);
2611   size = AOP_SIZE (IC_LEFT (ic));
2612   offset = (size - 1);
2613   while (size--)
2614     {
2615       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2616                                      FALSE, TRUE));
2617     }
2618
2619   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2620 }
2621
2622 /*-----------------------------------------------------------------*/
2623 /* saveRBank - saves an entire register bank on the stack          */
2624 /*-----------------------------------------------------------------*/
2625 static void
2626 saveRBank (int bank, iCode * ic, bool pushPsw)
2627 {
2628   int i;
2629   int count = 8 + (pushPsw ? 1 : 0);
2630   asmop *aop = NULL;
2631   regs *r = NULL;
2632
2633   if (options.useXstack)
2634     {
2635       if (!ic)
2636         {
2637           /* Assume r0 is available for use. */
2638           r = REG_WITH_INDEX (R0_IDX);
2639         }
2640       else
2641         {
2642           aop = newAsmop (0);
2643           r = getFreePtr (ic, &aop, FALSE);
2644         }
2645       // allocate space first
2646       emitcode ("mov", "%s,%s", r->name, spname);
2647       MOVA (r->name);
2648       emitcode ("add", "a,#%d", count);
2649       emitcode ("mov", "%s,a", spname);
2650     }
2651
2652   for (i = 0; i < 8; i++)
2653     {
2654       if (options.useXstack)
2655         {
2656           emitcode ("mov", "a,(%s+%d)",
2657                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2658           emitcode ("movx", "@%s,a", r->name);
2659           if (--count)
2660             emitcode ("inc", "%s", r->name);
2661         }
2662       else
2663         emitcode ("push", "(%s+%d)",
2664                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2665     }
2666
2667   if (pushPsw)
2668     {
2669       if (options.useXstack)
2670         {
2671           emitcode ("mov", "a,psw");
2672           emitcode ("movx", "@%s,a", r->name);
2673         }
2674       else
2675         {
2676           emitcode ("push", "psw");
2677         }
2678
2679       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
2680     }
2681
2682   if (aop)
2683     {
2684       freeAsmop (NULL, aop, ic, TRUE);
2685     }
2686
2687   if (ic)
2688     {
2689       ic->bankSaved = 1;
2690     }
2691 }
2692
2693 /*-----------------------------------------------------------------*/
2694 /* unsaveRBank - restores the register bank from stack             */
2695 /*-----------------------------------------------------------------*/
2696 static void
2697 unsaveRBank (int bank, iCode * ic, bool popPsw)
2698 {
2699   int i;
2700   asmop *aop = NULL;
2701   regs *r = NULL;
2702
2703   if (options.useXstack)
2704     {
2705       if (!ic)
2706         {
2707           /* Assume r0 is available for use. */
2708           r = REG_WITH_INDEX (R0_IDX);;
2709         }
2710       else
2711         {
2712           aop = newAsmop (0);
2713           r = getFreePtr (ic, &aop, FALSE);
2714         }
2715       emitcode ("mov", "%s,%s", r->name, spname);
2716     }
2717
2718   if (popPsw)
2719     {
2720       if (options.useXstack)
2721         {
2722           emitcode ("dec", "%s", r->name);
2723           emitcode ("movx", "a,@%s", r->name);
2724           emitcode ("mov", "psw,a");
2725         }
2726       else
2727         {
2728           emitcode ("pop", "psw");
2729         }
2730     }
2731
2732   for (i = 7; i >= 0; i--)
2733     {
2734       if (options.useXstack)
2735         {
2736           emitcode ("dec", "%s", r->name);
2737           emitcode ("movx", "a,@%s", r->name);
2738           emitcode ("mov", "(%s+%d),a",
2739                     regs8051[i].base, 8 * bank + regs8051[i].offset);
2740         }
2741       else
2742         {
2743           emitcode ("pop", "(%s+%d)",
2744                   regs8051[i].base, 8 * bank + regs8051[i].offset);
2745         }
2746     }
2747
2748   if (options.useXstack)
2749     {
2750       emitcode ("mov", "%s,%s", spname, r->name);
2751     }
2752
2753   if (aop)
2754     {
2755       freeAsmop (NULL, aop, ic, TRUE);
2756     }
2757 }
2758
2759 /*-----------------------------------------------------------------*/
2760 /* genSend - gen code for SEND                                     */
2761 /*-----------------------------------------------------------------*/
2762 static void genSend(set *sendSet)
2763 {
2764   iCode *sic;
2765   int bit_count = 0;
2766
2767   /* first we do all bit parameters */
2768   for (sic = setFirstItem (sendSet); sic;
2769        sic = setNextItem (sendSet))
2770     {
2771       if (sic->argreg > 12)
2772         {
2773           int bit = sic->argreg-13;
2774
2775           aopOp (IC_LEFT (sic), sic, FALSE);
2776
2777           /* if left is a literal then
2778              we know what the value is */
2779           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2780             {
2781               if (((int) operandLitValue (IC_LEFT (sic))))
2782                   emitcode ("setb", "b[%d]", bit);
2783               else
2784                   emitcode ("clr", "b[%d]", bit);
2785             }
2786           else
2787             {
2788               /* we need to or */
2789               toCarry (IC_LEFT (sic));
2790               emitcode ("mov", "b[%d],c", bit);
2791             }
2792           bit_count++;
2793           BitBankUsed = 1;
2794
2795           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2796         }
2797     }
2798
2799   if (bit_count)
2800     {
2801       saveRegisters (setFirstItem (sendSet));
2802       emitcode ("mov", "bits,b");
2803     }
2804
2805   /* then we do all other parameters */
2806   for (sic = setFirstItem (sendSet); sic;
2807        sic = setNextItem (sendSet))
2808     {
2809       if (sic->argreg <= 12)
2810         {
2811           int size, offset = 0;
2812           aopOp (IC_LEFT (sic), sic, FALSE);
2813           size = AOP_SIZE (IC_LEFT (sic));
2814
2815           if (sic->argreg == 1)
2816             {
2817               while (size--)
2818                 {
2819                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE);
2820                   if (strcmp (l, fReturn[offset]))
2821                     {
2822                       emitcode ("mov", "%s,%s", fReturn[offset], l);
2823                     }
2824                   offset++;
2825                 }
2826             }
2827           else
2828             {
2829               while (size--)
2830                 {
2831                   emitcode ("mov","%s,%s", rb1regs[sic->argreg+offset-5],
2832                             aopGet (IC_LEFT (sic), offset,FALSE, FALSE));
2833                   offset++;
2834                 }
2835             }
2836           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2837         }
2838     }
2839 }
2840
2841 /*-----------------------------------------------------------------*/
2842 /* selectRegBank - emit code to select the register bank           */
2843 /*-----------------------------------------------------------------*/
2844 static void
2845 selectRegBank (short bank, bool keepFlags)
2846 {
2847   /* if f.e. result is in carry */
2848   if (keepFlags)
2849     {
2850       emitcode ("anl", "psw,#0xE7");
2851       if (bank)
2852         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2853     }
2854   else
2855     {
2856       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2857     }
2858 }
2859
2860 /*-----------------------------------------------------------------*/
2861 /* genCall - generates a call statement                            */
2862 /*-----------------------------------------------------------------*/
2863 static void
2864 genCall (iCode * ic)
2865 {
2866   sym_link *dtype;
2867   sym_link *etype;
2868 //  bool restoreBank = FALSE;
2869   bool swapBanks = FALSE;
2870   bool accuse = FALSE;
2871   bool accPushed = FALSE;
2872   bool resultInF0 = FALSE;
2873   bool assignResultGenerated = FALSE;
2874
2875   D (emitcode (";", "genCall"));
2876
2877   dtype = operandType (IC_LEFT (ic));
2878   etype = getSpec(dtype);
2879   /* if send set is not empty then assign */
2880   if (_G.sendSet)
2881     {
2882         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2883             genSend(reverseSet(_G.sendSet));
2884         } else {
2885             genSend(_G.sendSet);
2886         }
2887       _G.sendSet = NULL;
2888     }
2889
2890   /* if we are calling a not _naked function that is not using
2891      the same register bank then we need to save the
2892      destination registers on the stack */
2893   if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
2894       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2895        !IFFUNC_ISISR (dtype))
2896     {
2897       swapBanks = TRUE;
2898     }
2899
2900   /* if caller saves & we have not saved then */
2901   if (!ic->regsSaved)
2902       saveRegisters (ic);
2903
2904   if (swapBanks)
2905     {
2906         emitcode ("mov", "psw,#0x%02x",
2907            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2908     }
2909
2910   /* make the call */
2911   if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2912     {
2913       if (IFFUNC_CALLEESAVES(dtype))
2914         {
2915           werror (E_BANKED_WITH_CALLEESAVES);
2916         }
2917       else
2918         {
2919           char *l = (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2920                      OP_SYMBOL (IC_LEFT (ic))->rname :
2921                      OP_SYMBOL (IC_LEFT (ic))->name);
2922
2923           emitcode ("mov", "r0,#%s", l);
2924           emitcode ("mov", "r1,#(%s >> 8)", l);
2925           emitcode ("mov", "r2,#(%s >> 16)", l);
2926           emitcode ("lcall", "__sdcc_banked_call");
2927         }
2928     }
2929   else
2930     {
2931       emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2932                                 OP_SYMBOL (IC_LEFT (ic))->rname :
2933                                 OP_SYMBOL (IC_LEFT (ic))->name));
2934     }
2935
2936   if (swapBanks)
2937     {
2938       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
2939     }
2940
2941   /* if we need assign a result value */
2942   if ((IS_ITEMP (IC_RESULT (ic)) &&
2943        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2944        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2945         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2946         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2947       IS_TRUE_SYMOP (IC_RESULT (ic)))
2948     {
2949
2950       _G.accInUse++;
2951       aopOp (IC_RESULT (ic), ic, FALSE);
2952       _G.accInUse--;
2953
2954       accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
2955       assignResultGenerated = TRUE;
2956
2957       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2958     }
2959
2960   /* adjust the stack for parameters if required */
2961   if (ic->parmBytes)
2962     {
2963       int i;
2964       if (ic->parmBytes > 3)
2965         {
2966           if (accuse)
2967             {
2968               emitcode ("push", "acc");
2969               accPushed = TRUE;
2970             }
2971           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
2972               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
2973               !assignResultGenerated)
2974             {
2975               emitcode ("mov", "F0,c");
2976               resultInF0 = TRUE;
2977             }
2978
2979           emitcode ("mov", "a,%s", spname);
2980           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
2981           emitcode ("mov", "%s,a", spname);
2982
2983           /* unsaveRegisters from xstack needs acc, but */
2984           /* unsaveRegisters from stack needs this popped */
2985           if (accPushed && !options.useXstack)
2986             {
2987               emitcode ("pop", "acc");
2988               accPushed = FALSE;
2989             }
2990         }
2991       else
2992         for (i = 0; i < ic->parmBytes; i++)
2993           emitcode ("dec", "%s", spname);
2994     }
2995
2996   /* if we had saved some registers then unsave them */
2997   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
2998     {
2999       if (accuse && !accPushed && options.useXstack)
3000         {
3001           /* xstack needs acc, but doesn't touch normal stack */
3002           emitcode ("push", "acc");
3003           accPushed = TRUE;
3004         }
3005       unsaveRegisters (ic);
3006     }
3007
3008 //  /* if register bank was saved then pop them */
3009 //  if (restoreBank)
3010 //    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3011
3012   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3013     {
3014       if (resultInF0)
3015           emitcode ("mov", "c,F0");
3016
3017       aopOp (IC_RESULT (ic), ic, FALSE);
3018       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3019       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3020     }
3021
3022   if (accPushed)
3023     emitcode ("pop", "acc");
3024 }
3025
3026 /*-----------------------------------------------------------------*/
3027 /* genPcall - generates a call by pointer statement                */
3028 /*-----------------------------------------------------------------*/
3029 static void
3030 genPcall (iCode * ic)
3031 {
3032   sym_link *dtype;
3033   sym_link *etype;
3034   symbol *rlbl = newiTempLabel (NULL);
3035 //  bool restoreBank=FALSE;
3036   bool swapBanks = FALSE;
3037   bool resultInF0 = FALSE;
3038
3039   D (emitcode (";", "genPcall"));
3040
3041   dtype = operandType (IC_LEFT (ic))->next;
3042   etype = getSpec(dtype);
3043   /* if caller saves & we have not saved then */
3044   if (!ic->regsSaved)
3045     saveRegisters (ic);
3046
3047   /* if we are calling a not _naked function that is not using
3048      the same register bank then we need to save the
3049      destination registers on the stack */
3050   if (currFunc && dtype && !IFFUNC_ISNAKED (dtype) &&
3051       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3052       !IFFUNC_ISISR (dtype))
3053     {
3054 //    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3055 //    restoreBank=TRUE;
3056       swapBanks = TRUE;
3057       // need caution message to user here
3058     }
3059
3060   if (IS_LITERAL (etype))
3061     {
3062       /* if send set is not empty then assign */
3063       if (_G.sendSet)
3064         {
3065           genSend(reverseSet(_G.sendSet));
3066           _G.sendSet = NULL;
3067         }
3068
3069       if (swapBanks)
3070         {
3071           emitcode ("mov", "psw,#0x%02x",
3072            ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3073         }
3074
3075       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3076         {
3077           if (IFFUNC_CALLEESAVES (dtype))
3078             {
3079               werror (E_BANKED_WITH_CALLEESAVES);
3080             }
3081           else
3082             {
3083               char *l = aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2);
3084
3085               emitcode ("mov", "r0,#%s", l);
3086               emitcode ("mov", "r1,#(%s >> 8)", l);
3087               emitcode ("mov", "r2,#(%s >> 16)", l);
3088               emitcode ("lcall", "__sdcc_banked_call");
3089             }
3090         }
3091       else
3092         {
3093           emitcode ("lcall", "%s", aopLiteralLong (OP_VALUE (IC_LEFT (ic)), 0, 2));
3094         }
3095     }
3096   else
3097     {
3098       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT (getSpec(dtype)))
3099         {
3100           if (IFFUNC_CALLEESAVES (dtype))
3101             {
3102               werror (E_BANKED_WITH_CALLEESAVES);
3103             }
3104           else
3105             {
3106               aopOp (IC_LEFT (ic), ic, FALSE);
3107
3108               if (!swapBanks)
3109                 {
3110                   /* what if aopGet needs r0 or r1 ??? */
3111                   emitcode ("mov", "ar0,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3112                   emitcode ("mov", "ar1,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3113                   emitcode ("mov", "ar2,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3114                 }
3115               else
3116                 {
3117                   int reg = ((FUNC_REGBANK(dtype)) << 3) & 0xff;
3118                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 0, FALSE, FALSE));
3119                   emitcode ("mov", "0x%02x,%s", reg++, aopGet(IC_LEFT (ic), 1, FALSE, FALSE));
3120                   emitcode ("mov", "0x%02x,%s", reg,   aopGet(IC_LEFT (ic), 2, FALSE, FALSE));
3121                 }
3122
3123               freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3124
3125               /* if send set is not empty then assign */
3126               if (_G.sendSet)
3127                 {
3128                   genSend(reverseSet(_G.sendSet));
3129                   _G.sendSet = NULL;
3130                 }
3131
3132               if (swapBanks)
3133                 {
3134                   emitcode ("mov", "psw,#0x%02x",
3135                    ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3136                 }
3137
3138               /* make the call */
3139               emitcode ("lcall", "__sdcc_banked_call");
3140             }
3141         }
3142       else if (_G.sendSet)
3143         {
3144           /* push the return address on to the stack */
3145           emitcode ("mov", "a,#%05d$", (rlbl->key + 100));
3146           emitcode ("push", "acc");
3147           emitcode ("mov", "a,#(%05d$ >> 8)", (rlbl->key + 100));
3148           emitcode ("push", "acc");
3149
3150           /* now push the calling address */
3151           aopOp (IC_LEFT (ic), ic, FALSE);
3152
3153           pushSide (IC_LEFT (ic), FPTRSIZE);
3154
3155           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3156
3157           /* if send set is not empty the assign */
3158           if (_G.sendSet)
3159             {
3160               genSend(reverseSet(_G.sendSet));
3161               _G.sendSet = NULL;
3162             }
3163
3164           if (swapBanks)
3165             {
3166               emitcode ("mov", "psw,#0x%02x",
3167                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3168             }
3169
3170           /* make the call */
3171           emitcode ("ret", "");
3172           emitLabel (rlbl);
3173         }
3174       else /* the send set is empty */
3175         {
3176           char *l;
3177           /* now get the calling address into dptr */
3178           aopOp (IC_LEFT (ic), ic, FALSE);
3179
3180           l = aopGet (IC_LEFT (ic), 0, FALSE, FALSE);
3181           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3182             {
3183               emitcode ("mov", "r0,%s", l);
3184               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3185               emitcode ("mov", "dph,%s", l);
3186               emitcode ("mov", "dpl,r0");
3187             }
3188           else
3189             {
3190               emitcode ("mov", "dpl,%s", l);
3191               l = aopGet (IC_LEFT (ic), 1, FALSE, FALSE);
3192               emitcode ("mov", "dph,%s", l);
3193             }
3194
3195           freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3196
3197           if (swapBanks)
3198             {
3199               emitcode ("mov", "psw,#0x%02x",
3200                ((FUNC_REGBANK (dtype)) << 3) & 0xff);
3201             }
3202
3203           /* make the call */
3204           emitcode ("lcall", "__sdcc_call_dptr");
3205         }
3206     }
3207   if (swapBanks)
3208     {
3209       selectRegBank (FUNC_REGBANK (currFunc->type), IS_BIT (etype));
3210     }
3211
3212   /* if we need assign a result value */
3213   if ((IS_ITEMP (IC_RESULT (ic)) &&
3214        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3215        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3216         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3217       IS_TRUE_SYMOP (IC_RESULT (ic)))
3218     {
3219
3220       _G.accInUse++;
3221       aopOp (IC_RESULT (ic), ic, FALSE);
3222       _G.accInUse--;
3223
3224       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3225
3226       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3227     }
3228
3229   /* adjust the stack for parameters if required */
3230   if (ic->parmBytes)
3231     {
3232       int i;
3233       if (ic->parmBytes > 3)
3234         {
3235           if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3236               IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3237             {
3238               emitcode ("mov", "F0,c");
3239               resultInF0 = TRUE;
3240             }
3241
3242           emitcode ("mov", "a,%s", spname);
3243           emitcode ("add", "a,#0x%02x", (-ic->parmBytes) & 0xff);
3244           emitcode ("mov", "%s,a", spname);
3245         }
3246       else
3247         for (i = 0; i < ic->parmBytes; i++)
3248           emitcode ("dec", "%s", spname);
3249     }
3250
3251 //  /* if register bank was saved then unsave them */
3252 //  if (restoreBank)
3253 //    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3254
3255   /* if we had saved some registers then unsave them */
3256   if (ic->regsSaved && !IFFUNC_CALLEESAVES (dtype))
3257     unsaveRegisters (ic);
3258
3259   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3260     {
3261       if (resultInF0)
3262           emitcode ("mov", "c,F0");
3263
3264       aopOp (IC_RESULT (ic), ic, FALSE);
3265       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3266       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3267     }
3268 }
3269
3270 /*-----------------------------------------------------------------*/
3271 /* resultRemat - result  is rematerializable                       */
3272 /*-----------------------------------------------------------------*/
3273 static int
3274 resultRemat (iCode * ic)
3275 {
3276   if (SKIP_IC (ic) || ic->op == IFX)
3277     return 0;
3278
3279   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3280     {
3281       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3282       if (sym->remat && !POINTER_SET (ic))
3283         return 1;
3284     }
3285
3286   return 0;
3287 }
3288
3289 /*-----------------------------------------------------------------*/
3290 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3291 /*-----------------------------------------------------------------*/
3292 static int
3293 regsCmp(void *p1, void *p2)
3294 {
3295   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3296 }
3297
3298 static bool
3299 inExcludeList (char *s)
3300 {
3301   const char *p = setFirstItem(options.excludeRegsSet);
3302
3303   if (p == NULL || STRCASECMP(p, "none") == 0)
3304     return FALSE;
3305
3306
3307   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3308 }
3309
3310 /*-----------------------------------------------------------------*/
3311 /* genFunction - generated code for function entry                 */
3312 /*-----------------------------------------------------------------*/
3313 static void
3314 genFunction (iCode * ic)
3315 {
3316   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3317   sym_link *ftype;
3318   bool     switchedPSW = FALSE;
3319   int      calleesaves_saved_register = -1;
3320   int      stackAdjust = sym->stack;
3321   int      accIsFree = sym->recvSize < 4;
3322   iCode    *ric = (ic->next && ic->next->op == RECEIVE) ? ic->next : NULL;
3323   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3324
3325   _G.nRegsSaved = 0;
3326   /* create the function header */
3327   emitcode (";", "-----------------------------------------");
3328   emitcode (";", " function %s", sym->name);
3329   emitcode (";", "-----------------------------------------");
3330
3331   emitcode ("", "%s:", sym->rname);
3332   lineCurr->isLabel = 1;
3333   ftype = operandType (IC_LEFT (ic));
3334   _G.currentFunc = sym;
3335
3336   if (IFFUNC_ISNAKED(ftype))
3337   {
3338       emitcode(";", "naked function: no prologue.");
3339       return;
3340   }
3341
3342   /* here we need to generate the equates for the
3343      register bank if required */
3344   if (FUNC_REGBANK (ftype) != rbank)
3345     {
3346       int i;
3347
3348       rbank = FUNC_REGBANK (ftype);
3349       for (i = 0; i < mcs51_nRegs; i++)
3350         {
3351           if (regs8051[i].type != REG_BIT)
3352             {
3353               if (strcmp (regs8051[i].base, "0") == 0)
3354                 emitcode ("", "%s = 0x%02x",
3355                           regs8051[i].dname,
3356                           8 * rbank + regs8051[i].offset);
3357               else
3358                 emitcode ("", "%s = %s + 0x%02x",
3359                           regs8051[i].dname,
3360                           regs8051[i].base,
3361                           8 * rbank + regs8051[i].offset);
3362             }
3363         }
3364     }
3365
3366   /* if this is an interrupt service routine then
3367      save acc, b, dpl, dph  */
3368   if (IFFUNC_ISISR (sym->type))
3369     {
3370       bitVect *rsavebits;
3371
3372       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3373       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3374         {
3375           emitcode ("push", "bits");
3376           BitBankUsed = 1;
3377         }
3378       freeBitVect (rsavebits);
3379
3380       if (!inExcludeList ("acc"))
3381         emitcode ("push", "acc");
3382       if (!inExcludeList ("b"))
3383         emitcode ("push", "b");
3384       if (!inExcludeList ("dpl"))
3385         emitcode ("push", "dpl");
3386       if (!inExcludeList ("dph"))
3387         emitcode ("push", "dph");
3388       /* if this isr has no bank i.e. is going to
3389          run with bank 0 , then we need to save more
3390          registers :-) */
3391       if (!FUNC_REGBANK (sym->type))
3392         {
3393           int i;
3394
3395           /* if this function does not call any other
3396              function then we can be economical and
3397              save only those registers that are used */
3398           if (!IFFUNC_HASFCALL(sym->type))
3399             {
3400               /* if any registers used */
3401               if (sym->regsUsed)
3402                 {
3403                   /* save the registers used */
3404                   for (i = 0; i < sym->regsUsed->size; i++)
3405                     {
3406                       if (bitVectBitValue (sym->regsUsed, i))
3407                         pushReg (i, TRUE);
3408                     }
3409                 }
3410             }
3411           else
3412             {
3413               /* this function has a function call. We cannot
3414                  determine register usage so we will have to push the
3415                  entire bank */
3416                 saveRBank (0, ic, FALSE);
3417                 if (options.parms_in_bank1) {
3418                     for (i=0; i < 8 ; i++ ) {
3419                         emitcode ("push","%s",rb1regs[i]);
3420                     }
3421                 }
3422             }
3423         }
3424       else
3425         {
3426             /* This ISR uses a non-zero bank.
3427              *
3428              * We assume that the bank is available for our
3429              * exclusive use.
3430              *
3431              * However, if this ISR calls a function which uses some
3432              * other bank, we must save that bank entirely.
3433              */
3434             unsigned long banksToSave = 0;
3435
3436             if (IFFUNC_HASFCALL(sym->type))
3437             {
3438
3439 #define MAX_REGISTER_BANKS 4
3440
3441                 iCode *i;
3442                 int ix;
3443
3444                 for (i = ic; i; i = i->next)
3445                 {
3446                     if (i->op == ENDFUNCTION)
3447                     {
3448                         /* we got to the end OK. */
3449                         break;
3450                     }
3451
3452                     if (i->op == CALL)
3453                     {
3454                         sym_link *dtype;
3455
3456                         dtype = operandType (IC_LEFT(i));
3457                         if (dtype
3458                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3459                         {
3460                              /* Mark this bank for saving. */
3461                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3462                              {
3463                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3464                              }
3465                              else
3466                              {
3467                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3468                              }
3469
3470                              /* And note that we don't need to do it in
3471                               * genCall.
3472                               */
3473                              i->bankSaved = 1;
3474                         }
3475                     }
3476                     if (i->op == PCALL)
3477                     {
3478                         /* This is a mess; we have no idea what
3479                          * register bank the called function might
3480                          * use.
3481                          *
3482                          * The only thing I can think of to do is
3483                          * throw a warning and hope.
3484                          */
3485                         werror(W_FUNCPTR_IN_USING_ISR);
3486                     }
3487                 }
3488
3489                 if (banksToSave && options.useXstack)
3490                 {
3491                     /* Since we aren't passing it an ic,
3492                      * saveRBank will assume r0 is available to abuse.
3493                      *
3494                      * So switch to our (trashable) bank now, so
3495                      * the caller's R0 isn't trashed.
3496                      */
3497                     emitcode ("push", "psw");
3498                     emitcode ("mov", "psw,#0x%02x",
3499                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3500                     switchedPSW = TRUE;
3501                 }
3502
3503                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3504                 {
3505                      if (banksToSave & (1 << ix))
3506                      {
3507                          saveRBank(ix, NULL, FALSE);
3508                      }
3509                 }
3510             }
3511             // TODO: this needs a closer look
3512             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3513         }
3514
3515       /* Set the register bank to the desired value if nothing else */
3516       /* has done so yet. */
3517       if (!switchedPSW)
3518         {
3519           emitcode ("push", "psw");
3520           emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3521         }
3522     }
3523   else
3524     {
3525       /* This is a non-ISR function. The caller has already switched register */
3526       /* banks, if necessary, so just handle the callee-saves option. */
3527
3528       /* if callee-save to be used for this function
3529          then save the registers being used in this function */
3530       if (IFFUNC_CALLEESAVES(sym->type))
3531         {
3532           int i;
3533
3534           /* if any registers used */
3535           if (sym->regsUsed)
3536             {
3537               bool bits_pushed = FALSE;
3538               /* save the registers used */
3539               for (i = 0; i < sym->regsUsed->size; i++)
3540                 {
3541                   if (bitVectBitValue (sym->regsUsed, i))
3542                     {
3543                       /* remember one saved register for later usage */
3544                       if (calleesaves_saved_register < 0)
3545                         calleesaves_saved_register = i;
3546                       bits_pushed = pushReg (i, bits_pushed);
3547                       _G.nRegsSaved++;
3548                     }
3549                 }
3550             }
3551         }
3552     }
3553
3554   if (fReentrant)
3555     {
3556       if (options.useXstack)
3557         {
3558           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3559             {
3560               emitcode ("mov", "r0,%s", spname);
3561               emitcode ("inc", "%s", spname);
3562               emitcode ("xch", "a,_bpx");
3563               emitcode ("movx", "@r0,a");
3564               emitcode ("inc", "r0");
3565               emitcode ("mov", "a,r0");
3566               emitcode ("xch", "a,_bpx");
3567             }
3568           if (sym->stack)
3569             {
3570               emitcode ("push", "_bp");     /* save the callers stack  */
3571               emitcode ("mov", "_bp,sp");
3572             }
3573         }
3574       else
3575         {
3576           if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3577             {
3578               /* set up the stack */
3579               emitcode ("push", "_bp");     /* save the callers stack  */
3580               emitcode ("mov", "_bp,sp");
3581             }
3582         }
3583     }
3584
3585   /* For some cases it is worthwhile to perform a RECEIVE iCode */
3586   /* before setting up the stack frame completely. */
3587   if (ric && ric->argreg == 1 && IC_RESULT (ric))
3588     {
3589       symbol * rsym = OP_SYMBOL (IC_RESULT (ric));
3590
3591       if (rsym->isitmp)
3592         {
3593           if (rsym && rsym->regType == REG_CND)
3594             rsym = NULL;
3595           if (rsym && (rsym->accuse || rsym->ruonly))
3596             rsym = NULL;
3597           if (rsym && (rsym->isspilt || rsym->nRegs == 0) && rsym->usl.spillLoc)
3598             rsym = rsym->usl.spillLoc;
3599         }
3600
3601       /* If the RECEIVE operand immediately spills to the first entry on the */
3602       /* stack, we can push it directly (since sp = _bp + 1 at this point) */
3603       /* rather than the usual @r0/r1 machinations. */
3604       if (!options.useXstack && rsym && rsym->onStack && rsym->stack == 1)
3605         {
3606           int ofs;
3607
3608           _G.current_iCode = ric;
3609           D(emitcode (";", "genReceive"));
3610           for (ofs=0; ofs < sym->recvSize; ofs++)
3611             {
3612               if (!strcmp (fReturn[ofs], "a"))
3613                 emitcode ("push", "acc");
3614               else
3615                 emitcode ("push", fReturn[ofs]);
3616             }
3617           stackAdjust -= sym->recvSize;
3618           if (stackAdjust<0)
3619             {
3620               assert (stackAdjust>=0);
3621               stackAdjust = 0;
3622             }
3623           _G.current_iCode = ic;
3624           ric->generated = 1;
3625           accIsFree = 1;
3626         }
3627       /* If the RECEIVE operand is 4 registers, we can do the moves now */
3628       /* to free up the accumulator. */
3629       else if (rsym && rsym->nRegs && sym->recvSize == 4)
3630         {
3631           int ofs;
3632
3633           _G.current_iCode = ric;
3634           D(emitcode (";", "genReceive"));
3635           for (ofs=0; ofs < sym->recvSize; ofs++)
3636             {
3637               emitcode ("mov", "%s,%s", rsym->regs[ofs]->name, fReturn[ofs]);
3638             }
3639           _G.current_iCode = ic;
3640           ric->generated = 1;
3641           accIsFree = 1;
3642         }
3643     }
3644
3645   /* adjust the stack for the function */
3646   if (stackAdjust)
3647     {
3648       int i = stackAdjust;
3649       if (i > 256)
3650         werror (W_STACK_OVERFLOW, sym->name);
3651
3652       if (i > 3 && accIsFree)
3653         {
3654           emitcode ("mov", "a,sp");
3655           emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3656           emitcode ("mov", "sp,a");
3657         }
3658       else if (i > 5)
3659         {
3660           /* The accumulator is not free, so we will need another register */
3661           /* to clobber. No need to worry about a possible conflict with */
3662           /* the above early RECEIVE optimizations since they would have */
3663           /* freed the accumulator if they were generated. */
3664
3665           if (IFFUNC_CALLEESAVES(sym->type))
3666             {
3667               /* if it's a callee-saves function we need a saved register */
3668               if (calleesaves_saved_register >= 0)
3669                 {
3670                   emitcode ("mov", "%s,a", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3671                   emitcode ("mov", "a,sp");
3672                   emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3673                   emitcode ("mov", "sp,a");
3674                   emitcode ("mov", "a,%s", REG_WITH_INDEX (calleesaves_saved_register)->dname);
3675                 }
3676               else
3677                 /* do it the hard way */
3678                 while (i--)
3679                   emitcode ("inc", "sp");
3680             }
3681           else
3682             {
3683               /* not callee-saves, we can clobber r0 */
3684               emitcode ("mov", "r0,a");
3685               emitcode ("mov", "a,sp");
3686               emitcode ("add", "a,#0x%02x", ((char) sym->stack & 0xff));
3687               emitcode ("mov", "sp,a");
3688               emitcode ("mov", "a,r0");
3689             }
3690         }
3691       else
3692         while (i--)
3693           emitcode ("inc", "sp");
3694     }
3695
3696   if (sym->xstack)
3697     {
3698       char i = ((char) sym->xstack & 0xff);
3699
3700       if (i > 3 && accIsFree)
3701         {
3702           emitcode ("mov", "a,_spx");
3703           emitcode ("add", "a,#0x%02x", i & 0xff);
3704           emitcode ("mov", "_spx,a");
3705         }
3706       else if (i > 5)
3707         {
3708           emitcode ("push", "acc");
3709           emitcode ("mov", "a,_spx");
3710           emitcode ("add", "a,#0x%02x", i & 0xff);
3711           emitcode ("mov", "_spx,a");
3712           emitcode ("pop", "acc");
3713         }
3714       else
3715         {
3716           while (i--)
3717             emitcode ("inc", "_spx");
3718         }
3719     }
3720
3721   /* if critical function then turn interrupts off */
3722   if (IFFUNC_ISCRITICAL (ftype))
3723     {
3724       symbol *tlbl = newiTempLabel (NULL);
3725       emitcode ("setb", "c");
3726       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3727       emitcode ("clr", "c");
3728       emitLabel (tlbl);
3729       emitcode ("push", "psw"); /* save old ea via c in psw */
3730     }
3731 }
3732
3733 /*-----------------------------------------------------------------*/
3734 /* genEndFunction - generates epilogue for functions               */
3735 /*-----------------------------------------------------------------*/
3736 static void
3737 genEndFunction (iCode * ic)
3738 {
3739   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3740   lineNode *lnp = lineCurr;
3741   bitVect  *regsUsed;
3742   bitVect  *regsUsedPrologue;
3743   bitVect  *regsUnneeded;
3744   int      idx;
3745
3746   _G.currentFunc = NULL;
3747   if (IFFUNC_ISNAKED(sym->type))
3748   {
3749       emitcode(";", "naked function: no epilogue.");
3750       if (options.debug && currFunc)
3751         debugFile->writeEndFunction (currFunc, ic, 0);
3752       return;
3753   }
3754
3755   if (IFFUNC_ISCRITICAL (sym->type))
3756     {
3757       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3758         {
3759           emitcode ("rlc", "a");   /* save c in a */
3760           emitcode ("pop", "psw"); /* restore ea via c in psw */
3761           emitcode ("mov", "ea,c");
3762           emitcode ("rrc", "a");   /* restore c from a */
3763         }
3764       else
3765         {
3766           emitcode ("pop", "psw"); /* restore ea via c in psw */
3767           emitcode ("mov", "ea,c");
3768         }
3769     }
3770
3771   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
3772     {
3773       if (options.useXstack)
3774         {
3775           if (sym->stack)
3776             {
3777               emitcode ("mov", "sp,_bp");
3778               emitcode ("pop", "_bp");
3779             }
3780           if (sym->xstack || FUNC_HASSTACKPARM(sym->type))
3781             {
3782               emitcode ("xch", "a,_bpx");
3783               emitcode ("mov", "r0,a");
3784               emitcode ("dec", "r0");
3785               emitcode ("movx", "a,@r0");
3786               emitcode ("xch", "a,_bpx");
3787               emitcode ("mov", "%s,r0", spname); //read before freeing stack space (interrupts)
3788             }
3789         }
3790       else if (sym->stack || FUNC_HASSTACKPARM(sym->type))
3791         {
3792           if (sym->stack)
3793             emitcode ("mov", "sp,_bp");
3794           emitcode ("pop", "_bp");
3795         }
3796     }
3797
3798   /* restore the register bank  */
3799   if ( /* FUNC_REGBANK (sym->type) || */ IFFUNC_ISISR (sym->type))
3800   {
3801     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3802      || !options.useXstack)
3803     {
3804         /* Special case of ISR using non-zero bank with useXstack
3805          * is handled below.
3806          */
3807         emitcode ("pop", "psw");
3808     }
3809   }
3810
3811   if (IFFUNC_ISISR (sym->type))
3812     {
3813       bitVect *rsavebits;
3814
3815       /* now we need to restore the registers */
3816       /* if this isr has no bank i.e. is going to
3817          run with bank 0 , then we need to save more
3818          registers :-) */
3819       if (!FUNC_REGBANK (sym->type))
3820         {
3821           int i;
3822           /* if this function does not call any other
3823              function then we can be economical and
3824              save only those registers that are used */
3825           if (!IFFUNC_HASFCALL(sym->type))
3826             {
3827               /* if any registers used */
3828               if (sym->regsUsed)
3829                 {
3830                   /* save the registers used */
3831                   for (i = sym->regsUsed->size; i >= 0; i--)
3832                     {
3833                       if (bitVectBitValue (sym->regsUsed, i))
3834                         popReg (i, TRUE);
3835                     }
3836                 }
3837             }
3838           else
3839             {
3840               if (options.parms_in_bank1) {
3841                   for (i = 7 ; i >= 0 ; i-- ) {
3842                       emitcode ("pop","%s",rb1regs[i]);
3843                   }
3844               }
3845               /* this function has a function call. We cannot
3846                  determine register usage so we will have to pop the
3847                  entire bank */
3848               unsaveRBank (0, ic, FALSE);
3849             }
3850         }
3851         else
3852         {
3853             /* This ISR uses a non-zero bank.
3854              *
3855              * Restore any register banks saved by genFunction
3856              * in reverse order.
3857              */
3858             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3859             int ix;
3860
3861             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3862             {
3863                 if (savedBanks & (1 << ix))
3864                 {
3865                     unsaveRBank(ix, NULL, FALSE);
3866                 }
3867             }
3868
3869             if (options.useXstack)
3870             {
3871                 /* Restore bank AFTER calling unsaveRBank,
3872                  * since it can trash r0.
3873                  */
3874                 emitcode ("pop", "psw");
3875             }
3876         }
3877
3878       if (!inExcludeList ("dph"))
3879         emitcode ("pop", "dph");
3880       if (!inExcludeList ("dpl"))
3881         emitcode ("pop", "dpl");
3882       if (!inExcludeList ("b"))
3883         emitcode ("pop", "b");
3884       if (!inExcludeList ("acc"))
3885         emitcode ("pop", "acc");
3886
3887       rsavebits = bitVectIntersect (bitVectCopy (mcs51_allBitregs ()), sym->regsUsed);
3888       if (IFFUNC_HASFCALL(sym->type) || !bitVectIsZero (rsavebits))
3889         emitcode ("pop", "bits");
3890       freeBitVect (rsavebits);
3891
3892       /* if debug then send end of function */
3893       if (options.debug && currFunc)
3894         {
3895           debugFile->writeEndFunction (currFunc, ic, 1);
3896         }
3897
3898       emitcode ("reti", "");
3899     }
3900   else
3901     {
3902       if (IFFUNC_CALLEESAVES(sym->type))
3903         {
3904           int i;
3905
3906           /* if any registers used */
3907           if (sym->regsUsed)
3908             {
3909               /* save the registers used */
3910               for (i = sym->regsUsed->size; i >= 0; i--)
3911                 {
3912                   if (bitVectBitValue (sym->regsUsed, i) ||
3913                       (mcs51_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
3914                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3915                 }
3916             }
3917           else if (mcs51_ptrRegReq)
3918             {
3919               emitcode ("pop", "%s", REG_WITH_INDEX (R1_IDX)->dname);
3920               emitcode ("pop", "%s", REG_WITH_INDEX (R0_IDX)->dname);
3921             }
3922
3923         }
3924
3925       /* if debug then send end of function */
3926       if (options.debug && currFunc)
3927         {
3928           debugFile->writeEndFunction (currFunc, ic, 1);
3929         }
3930
3931       if (IFFUNC_ISBANKEDCALL (sym->type) && !SPEC_STAT(getSpec(sym->type)))
3932         {
3933           emitcode ("ljmp", "__sdcc_banked_ret");
3934         }
3935       else
3936         {
3937           emitcode ("ret", "");
3938         }
3939     }
3940
3941   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3942     return;
3943
3944   /* If this was an interrupt handler using bank 0 that called another */
3945   /* function, then all registers must be saved; nothing to optimized. */
3946   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3947       && !FUNC_REGBANK(sym->type))
3948     return;
3949
3950   /* There are no push/pops to optimize if not callee-saves or ISR */
3951   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3952     return;
3953
3954   /* If there were stack parameters, we cannot optimize without also    */
3955   /* fixing all of the stack offsets; this is too dificult to consider. */
3956   if (FUNC_HASSTACKPARM(sym->type))
3957     return;
3958
3959   /* Compute the registers actually used */
3960   regsUsed = newBitVect (mcs51_nRegs);
3961   regsUsedPrologue = newBitVect (mcs51_nRegs);
3962   while (lnp)
3963     {
3964       if (lnp->ic && lnp->ic->op == FUNCTION)
3965         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3966       else
3967         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3968
3969       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3970           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3971         break;
3972       if (!lnp->prev)
3973         break;
3974       lnp = lnp->prev;
3975     }
3976
3977   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3978       && !bitVectBitValue (regsUsed, CND_IDX))
3979     {
3980       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3981       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3982           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3983         bitVectUnSetBit (regsUsed, CND_IDX);
3984     }
3985   else
3986     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3987
3988   /* If this was an interrupt handler that called another function */
3989   /* function, then assume A, B, DPH, & DPL may be modified by it. */
3990   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3991     {
3992       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3993       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3995       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3996       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3997     }
3998
3999   /* Remove the unneeded push/pops */
4000   regsUnneeded = newBitVect (mcs51_nRegs);
4001   while (lnp)
4002     {
4003       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4004         {
4005           if (!strncmp(lnp->line, "push", 4))
4006             {
4007               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4008               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4009                 {
4010                   connectLine (lnp->prev, lnp->next);
4011                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4012                 }
4013             }
4014           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4015             {
4016               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4017               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4018                 {
4019                   connectLine (lnp->prev, lnp->next);
4020                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4021                 }
4022             }
4023         }
4024       lnp = lnp->next;
4025     }
4026
4027   for (idx = 0; idx < regsUnneeded->size; idx++)
4028     if (bitVectBitValue (regsUnneeded, idx))
4029       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4030
4031   freeBitVect (regsUnneeded);
4032   freeBitVect (regsUsed);
4033   freeBitVect (regsUsedPrologue);
4034 }
4035
4036 /*-----------------------------------------------------------------*/
4037 /* genRet - generate code for return statement                     */
4038 /*-----------------------------------------------------------------*/
4039 static void
4040 genRet (iCode * ic)
4041 {
4042   int size, offset = 0, pushed = 0;
4043
4044   D (emitcode (";", "genRet"));
4045
4046   /* if we have no return value then
4047      just generate the "ret" */
4048   if (!IC_LEFT (ic))
4049     goto jumpret;
4050
4051   /* we have something to return then
4052      move the return value into place */
4053   aopOp (IC_LEFT (ic), ic, FALSE);
4054   size = AOP_SIZE (IC_LEFT (ic));
4055
4056   if (IS_BIT(_G.currentFunc->etype))
4057     {
4058       if (!IS_OP_RUONLY (IC_LEFT (ic)))
4059         toCarry (IC_LEFT (ic));
4060     }
4061   else
4062     {
4063       while (size--)
4064         {
4065           char *l;
4066           if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4067             {
4068               /* #NOCHANGE */
4069               l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE);
4070               emitcode ("push", "%s", l);
4071               pushed++;
4072             }
4073           else
4074             {
4075               l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE);
4076               if (strcmp (fReturn[offset], l))
4077                 emitcode ("mov", "%s,%s", fReturn[offset++], l);
4078             }
4079         }
4080
4081       while (pushed)
4082         {
4083           pushed--;
4084           if (strcmp (fReturn[pushed], "a"))
4085             emitcode ("pop", fReturn[pushed]);
4086           else
4087             emitcode ("pop", "acc");
4088         }
4089     }
4090   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4091
4092 jumpret:
4093   /* generate a jump to the return label
4094      if the next is not the return statement */
4095   if (!(ic->next && ic->next->op == LABEL &&
4096         IC_LABEL (ic->next) == returnLabel))
4097
4098     emitcode ("ljmp", "%05d$", (returnLabel->key + 100));
4099
4100 }
4101
4102 /*-----------------------------------------------------------------*/
4103 /* genLabel - generates a label                                    */
4104 /*-----------------------------------------------------------------*/
4105 static void
4106 genLabel (iCode * ic)
4107 {
4108   /* special case never generate */
4109   if (IC_LABEL (ic) == entryLabel)
4110     return;
4111
4112   emitLabel (IC_LABEL (ic));
4113 }
4114
4115 /*-----------------------------------------------------------------*/
4116 /* genGoto - generates a ljmp                                      */
4117 /*-----------------------------------------------------------------*/
4118 static void
4119 genGoto (iCode * ic)
4120 {
4121   emitcode ("ljmp", "%05d$", (IC_LABEL (ic)->key + 100));
4122 }
4123
4124 /*-----------------------------------------------------------------*/
4125 /* findLabelBackwards: walks back through the iCode chain looking  */
4126 /* for the given label. Returns number of iCode instructions     */
4127 /* between that label and given ic.          */
4128 /* Returns zero if label not found.          */
4129 /*-----------------------------------------------------------------*/
4130 static int
4131 findLabelBackwards (iCode * ic, int key)
4132 {
4133   int count = 0;
4134
4135   while (ic->prev)
4136     {
4137       ic = ic->prev;
4138       count++;
4139
4140       /* If we have any pushes or pops, we cannot predict the distance.
4141          I don't like this at all, this should be dealt with in the
4142          back-end */
4143       if (ic->op == IPUSH || ic->op == IPOP) {
4144         return 0;
4145       }
4146
4147       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4148         {
4149           return count;
4150         }
4151     }
4152
4153   return 0;
4154 }
4155
4156 /*-----------------------------------------------------------------*/
4157 /* genPlusIncr :- does addition with increment if possible         */
4158 /*-----------------------------------------------------------------*/
4159 static bool
4160 genPlusIncr (iCode * ic)
4161 {
4162   unsigned int icount;
4163   unsigned int size = getDataSize (IC_RESULT (ic));
4164
4165   /* will try to generate an increment */
4166   /* if the right side is not a literal
4167      we cannot */
4168   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4169     return FALSE;
4170
4171   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4172
4173   D(emitcode (";","genPlusIncr"));
4174
4175   /* if increment >=16 bits in register or direct space */
4176   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4177         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4178         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4179       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4180       !isOperandVolatile (IC_RESULT (ic), FALSE) &&
4181       (size > 1) &&
4182       (icount == 1))
4183     {
4184       symbol *tlbl;
4185       int emitTlbl;
4186       int labelRange;
4187
4188       /* If the next instruction is a goto and the goto target
4189        * is < 10 instructions previous to this, we can generate
4190        * jumps straight to that target.
4191        */
4192       if (ic->next && ic->next->op == GOTO
4193           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4194           && labelRange <= 10)
4195         {
4196           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4197           tlbl = IC_LABEL (ic->next);
4198           emitTlbl = 0;
4199         }
4200       else
4201         {
4202           tlbl = newiTempLabel (NULL);
4203           emitTlbl = 1;
4204         }
4205       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4206       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4207           IS_AOP_PREG (IC_RESULT (ic)))
4208         emitcode ("cjne", "%s,#0x00,%05d$",
4209                   aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4210                   tlbl->key + 100);
4211       else
4212         {
4213           emitcode ("clr", "a");
4214           emitcode ("cjne", "a,%s,%05d$",
4215                     aopGet (IC_RESULT (ic), LSB, FALSE, FALSE),
4216                     tlbl->key + 100);
4217         }
4218
4219       emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4220       if (size > 2)
4221         {
4222           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4223               IS_AOP_PREG (IC_RESULT (ic)))
4224             emitcode ("cjne", "%s,#0x00,%05d$",
4225                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4226                       tlbl->key + 100);
4227           else
4228             emitcode ("cjne", "a,%s,%05d$",
4229                       aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE),
4230                       tlbl->key + 100);
4231
4232           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4233         }
4234       if (size > 3)
4235         {
4236           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4237               IS_AOP_PREG (IC_RESULT (ic)))
4238             emitcode ("cjne", "%s,#0x00,%05d$",
4239                       aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4240                       tlbl->key + 100);
4241           else
4242             {
4243               emitcode ("cjne", "a,%s,%05d$",
4244                         aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE),
4245                         tlbl->key + 100);
4246             }
4247           emitcode ("inc", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4248         }
4249
4250       if (emitTlbl)
4251         {
4252           emitLabel (tlbl);
4253         }
4254       return TRUE;
4255     }
4256
4257   /* if result is dptr */
4258   if ((AOP_TYPE (IC_RESULT (ic)) == AOP_STR) &&
4259       (AOP_SIZE (IC_RESULT (ic)) == 2) &&
4260       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[0], "dpl", 4) &&
4261       !strncmp(AOP (IC_RESULT (ic))->aopu.aop_str[1], "dph", 4))
4262     {
4263       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4264         return FALSE;
4265
4266       if (icount > 9)
4267         return FALSE;
4268
4269       if ((AOP_TYPE (IC_LEFT (ic)) != AOP_DIR) && (icount > 5))
4270         return FALSE;
4271
4272       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 0, FALSE, FALSE), 0);
4273       aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), 1, FALSE, FALSE), 1);
4274       while (icount--)
4275         emitcode ("inc", "dptr");
4276
4277       return TRUE;
4278     }
4279
4280   /* if the literal value of the right hand side
4281      is greater than 4 then it is not worth it */
4282   if (icount > 4)
4283     return FALSE;
4284
4285   /* if the sizes are greater than 1 then we cannot */
4286   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4287       AOP_SIZE (IC_LEFT (ic)) > 1)
4288     return FALSE;
4289
4290   /* we can if the aops of the left & result match or
4291      if they are in registers and the registers are the
4292      same */
4293   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4294     {
4295       if (icount > 3)
4296         {
4297           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4298           emitcode ("add", "a,#0x%02x", ((char) icount) & 0xff);
4299           aopPut (IC_RESULT (ic), "a", 0);
4300         }
4301       else
4302         {
4303           while (icount--)
4304             {
4305               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4306             }
4307         }
4308
4309       return TRUE;
4310     }
4311
4312   if (icount == 1)
4313     {
4314       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4315       emitcode ("inc", "a");
4316       aopPut (IC_RESULT (ic), "a", 0);
4317       return TRUE;
4318     }
4319
4320   return FALSE;
4321 }
4322
4323 /*-----------------------------------------------------------------*/
4324 /* outBitAcc - output a bit in acc                                 */
4325 /*-----------------------------------------------------------------*/
4326 static void
4327 outBitAcc (operand * result)
4328 {
4329   symbol *tlbl = newiTempLabel (NULL);
4330   /* if the result is a bit */
4331   if (AOP_TYPE (result) == AOP_CRY)
4332     {
4333       aopPut (result, "a", 0);
4334     }
4335   else
4336     {
4337       emitcode ("jz", "%05d$", tlbl->key + 100);
4338       emitcode ("mov", "a,%s", one);
4339       emitLabel (tlbl);
4340       outAcc (result);
4341     }
4342 }
4343
4344 /*-----------------------------------------------------------------*/
4345 /* genPlusBits - generates code for addition of two bits           */
4346 /*-----------------------------------------------------------------*/
4347 static void
4348 genPlusBits (iCode * ic)
4349 {
4350   D (emitcode (";", "genPlusBits"));
4351
4352   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4353   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4354     {
4355       symbol *lbl = newiTempLabel (NULL);
4356       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4357       emitcode ("cpl", "c");
4358       emitLabel (lbl);
4359       outBitC (IC_RESULT (ic));
4360     }
4361   else
4362     {
4363       emitcode ("clr", "a");
4364       emitcode ("rlc", "a");
4365       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4366       emitcode ("addc", "a,%s", zero);
4367       outAcc (IC_RESULT (ic));
4368     }
4369 }
4370
4371 #if 0
4372 /* This is the original version of this code.
4373
4374  * This is being kept around for reference,
4375  * because I am not entirely sure I got it right...
4376  */
4377 static void
4378 adjustArithmeticResult (iCode * ic)
4379 {
4380   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4381       AOP_SIZE (IC_LEFT (ic)) == 3 &&
4382       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4383     aopPut (IC_RESULT (ic),
4384             aopGet (IC_LEFT (ic)), 2, FALSE, FALSE),
4385             2);
4386
4387   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4388       AOP_SIZE (IC_RIGHT (ic)) == 3 &&
4389       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4390     aopPut (IC_RESULT (ic),
4391             aopGet (IC_RIGHT (ic)), 2, FALSE, FALSE),
4392             2);
4393
4394   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
4395       AOP_SIZE (IC_LEFT (ic)) < 3 &&
4396       AOP_SIZE (IC_RIGHT (ic)) < 3 &&
4397       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4398       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4399     {
4400       char buffer[5];
4401       sprintf (buffer, "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4402       aopPut (IC_RESULT (ic), buffer, 2);
4403     }
4404 }
4405 #else
4406 /* This is the pure and virtuous version of this code.
4407  * I'm pretty certain it's right, but not enough to toss the old
4408  * code just yet...
4409  */
4410 static void
4411 adjustArithmeticResult (iCode * ic)
4412 {
4413   if (opIsGptr (IC_RESULT (ic)) &&
4414       opIsGptr (IC_LEFT (ic)) &&
4415       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4416     {
4417       aopPut (IC_RESULT (ic),
4418               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE),
4419               GPTRSIZE - 1);
4420     }
4421
4422   if (opIsGptr (IC_RESULT (ic)) &&
4423       opIsGptr (IC_RIGHT (ic)) &&
4424       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4425     {
4426       aopPut (IC_RESULT (ic),
4427               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE),
4428               GPTRSIZE - 1);
4429     }
4430
4431   if (opIsGptr (IC_RESULT (ic)) &&
4432       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4433       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4434       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4435       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4436     {
4437       char buffer[5];
4438       SNPRINTF (buffer, sizeof(buffer),
4439                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4440       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4441     }
4442 }
4443 #endif
4444
4445 /*-----------------------------------------------------------------*/
4446 /* genPlus - generates code for addition                           */
4447 /*-----------------------------------------------------------------*/
4448 static void
4449 genPlus (iCode * ic)
4450 {
4451   int size, offset = 0;
4452   int skip_bytes = 0;
4453   char *add = "add";
4454   bool swappedLR = FALSE;
4455   operand *leftOp, *rightOp;
4456   operand * op;
4457
4458   D (emitcode (";", "genPlus"));
4459
4460   /* special cases :- */
4461
4462   aopOp (IC_LEFT (ic), ic, FALSE);
4463   aopOp (IC_RIGHT (ic), ic, FALSE);
4464   aopOp (IC_RESULT (ic), ic, TRUE);
4465
4466   /* if literal, literal on the right or
4467      if left requires ACC or right is already
4468      in ACC */
4469   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4470       (AOP_NEEDSACC (IC_LEFT (ic))) ||
4471       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4472     {
4473       operand *t = IC_RIGHT (ic);
4474       IC_RIGHT (ic) = IC_LEFT (ic);
4475       IC_LEFT (ic) = t;
4476       swappedLR = TRUE;
4477     }
4478
4479   /* if both left & right are in bit
4480      space */
4481   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4482       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4483     {
4484       genPlusBits (ic);
4485       goto release;
4486     }
4487
4488   /* if left in bit space & right literal */
4489   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4490       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4491     {
4492       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4493       /* if result in bit space */
4494       if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4495         {
4496           if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4497             emitcode ("cpl", "c");
4498           outBitC (IC_RESULT (ic));
4499         }
4500       else
4501         {
4502           size = getDataSize (IC_RESULT (ic));
4503           while (size--)
4504             {
4505               MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE));
4506               emitcode ("addc", "a,%s", zero);
4507               aopPut (IC_RESULT (ic), "a", offset++);
4508             }
4509         }
4510       goto release;
4511     }
4512
4513   /* if I can do an increment instead
4514      of add then GOOD for ME */
4515   if (genPlusIncr (ic) == TRUE)
4516     goto release;
4517
4518   size = getDataSize (IC_RESULT (ic));
4519   leftOp = IC_LEFT(ic);
4520   rightOp = IC_RIGHT(ic);
4521   op = IC_LEFT(ic);
4522
4523   /* if this is an add for an array access
4524      at a 256 byte boundary */
4525   if ( 2 == size
4526        && AOP_TYPE (op) == AOP_IMMD
4527        && IS_SYMOP (op)
4528        && IS_SPEC (OP_SYM_ETYPE (op))
4529        && SPEC_ABSA (OP_SYM_ETYPE (op))
4530        && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
4531      )
4532     {
4533       D(emitcode (";", "genPlus aligned array"));
4534       aopPut (IC_RESULT (ic),
4535               aopGet (rightOp, 0, FALSE, FALSE),
4536               0);
4537
4538       if( 1 == getDataSize (IC_RIGHT (ic)) )
4539         {
4540           aopPut (IC_RESULT (ic),
4541                   aopGet (leftOp, 1, FALSE, FALSE),
4542                   1);
4543         }
4544       else
4545         {
4546           MOVA (aopGet (IC_LEFT (ic), 1, FALSE, FALSE));
4547           emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
4548           aopPut (IC_RESULT (ic), "a", 1);
4549         }
4550       goto release;
4551     }
4552
4553   /* if the lower bytes of a literal are zero skip the addition */
4554   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
4555     {
4556        while ((0 == ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
4557               (skip_bytes+1 < size))
4558          {
4559            skip_bytes++;
4560          }
4561        if (skip_bytes)
4562          D(emitcode (";", "genPlus shortcut"));
4563     }
4564
4565   while (size--)
4566     {
4567       if( offset >= skip_bytes )
4568         {
4569           if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
4570             {
4571               bool pushedB;
4572               MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
4573               pushedB = pushB ();
4574               emitcode("xch", "a,b");
4575               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4576               emitcode (add, "a,b");
4577               popB (pushedB);
4578             }
4579           else if (aopGetUsesAcc (leftOp, offset))
4580             {
4581               MOVA (aopGet (leftOp, offset, FALSE, TRUE));
4582               emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
4583             }
4584           else
4585             {
4586               MOVA (aopGet (rightOp, offset, FALSE, TRUE));
4587               emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
4588             }
4589           aopPut (IC_RESULT (ic), "a", offset);
4590           add = "addc";  /* further adds must propagate carry */
4591         }
4592       else
4593         {
4594           if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) ||
4595               isOperandVolatile (IC_RESULT (ic), FALSE))
4596             {
4597               /* just move */
4598               aopPut (IC_RESULT (ic),
4599                       aopGet (leftOp, offset, FALSE, FALSE),
4600                       offset);
4601             }
4602         }
4603       offset++;
4604     }
4605
4606   adjustArithmeticResult (ic);
4607
4608 release:
4609   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4610   if (!swappedLR)
4611     {
4612       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4613       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4614     }
4615   else
4616     {
4617       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4618       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4619     }
4620 }
4621
4622 /*-----------------------------------------------------------------*/
4623 /* genMinusDec :- does subtraction with decrement if possible      */
4624 /*-----------------------------------------------------------------*/
4625 static bool
4626 genMinusDec (iCode * ic)
4627 {
4628   unsigned int icount;
4629   unsigned int size = getDataSize (IC_RESULT (ic));
4630
4631   /* will try to generate an increment */
4632   /* if the right side is not a literal
4633      we cannot */
4634   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4635     return FALSE;
4636
4637   /* if the literal value of the right hand side
4638      is greater than 4 then it is not worth it */
4639   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4640     return FALSE;
4641
4642   D (emitcode (";", "genMinusDec"));
4643
4644   /* if decrement >=16 bits in register or direct space */
4645   if (( AOP_TYPE(IC_LEFT(ic)) == AOP_REG ||
4646         AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ||
4647         (IS_AOP_PREG (IC_LEFT(ic)) && !AOP_NEEDSACC (IC_LEFT(ic))) ) &&
4648       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4649       (size > 1) &&
4650       (icount == 1))
4651     {
4652       symbol *tlbl;
4653       int emitTlbl;
4654       int labelRange;
4655
4656       /* If the next instruction is a goto and the goto target
4657        * is <= 10 instructions previous to this, we can generate
4658        * jumps straight to that target.
4659        */
4660       if (ic->next && ic->next->op == GOTO
4661           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4662           && labelRange <= 10)
4663         {
4664           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4665           tlbl = IC_LABEL (ic->next);
4666           emitTlbl = 0;
4667         }
4668       else
4669         {
4670           tlbl = newiTempLabel (NULL);
4671           emitTlbl = 1;
4672         }
4673
4674       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
4675       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4676           IS_AOP_PREG (IC_RESULT (ic)))
4677         emitcode ("cjne", "%s,#0xff,%05d$"
4678                   ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4679                   ,tlbl->key + 100);
4680       else
4681         {
4682           emitcode ("mov", "a,#0xff");
4683           emitcode ("cjne", "a,%s,%05d$"
4684                     ,aopGet (IC_RESULT (ic), LSB, FALSE, FALSE)
4685                     ,tlbl->key + 100);
4686         }
4687       emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE));
4688       if (size > 2)
4689         {
4690           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4691               IS_AOP_PREG (IC_RESULT (ic)))
4692             emitcode ("cjne", "%s,#0xff,%05d$"
4693                       ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4694                       ,tlbl->key + 100);
4695           else
4696             {
4697               emitcode ("cjne", "a,%s,%05d$"
4698                         ,aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE)
4699                         ,tlbl->key + 100);
4700             }
4701           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE));
4702         }
4703       if (size > 3)
4704         {
4705           if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4706               IS_AOP_PREG (IC_RESULT (ic)))
4707             emitcode ("cjne", "%s,#0xff,%05d$"
4708                       ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4709                       ,tlbl->key + 100);
4710           else
4711             {
4712               emitcode ("cjne", "a,%s,%05d$"
4713                         ,aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE)
4714                         ,tlbl->key + 100);
4715             }
4716           emitcode ("dec", "%s", aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE));
4717         }
4718       if (emitTlbl)
4719         {
4720           emitLabel (tlbl);
4721         }
4722       return TRUE;
4723     }
4724
4725   /* if the sizes are greater than 1 then we cannot */
4726   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4727       AOP_SIZE (IC_LEFT (ic)) > 1)
4728     return FALSE;
4729
4730   /* we can if the aops of the left & result match or
4731      if they are in registers and the registers are the
4732      same */
4733   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4734     {
4735       char *l;
4736
4737       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4738         {
4739           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
4740           l = "a";
4741         }
4742       else
4743         {
4744           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE);
4745         }
4746
4747       while (icount--)
4748         {
4749           emitcode ("dec", "%s", l);
4750         }
4751
4752       if (AOP_NEEDSACC (IC_RESULT (ic)))
4753         aopPut (IC_RESULT (ic), "a", 0);
4754
4755       return TRUE;
4756     }
4757
4758   if (icount == 1)
4759     {
4760       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE));
4761       emitcode ("dec", "a");
4762       aopPut (IC_RESULT (ic), "a", 0);
4763       return TRUE;
4764     }
4765
4766   return FALSE;
4767 }
4768
4769 /*-----------------------------------------------------------------*/
4770 /* addSign - complete with sign                                    */
4771 /*-----------------------------------------------------------------*/
4772 static void
4773 addSign (operand * result, int offset, int sign)
4774 {
4775   int size = (getDataSize (result) - offset);
4776   if (size > 0)
4777     {
4778       if (sign)
4779         {
4780           emitcode ("rlc", "a");
4781           emitcode ("subb", "a,acc");
4782           while (size--)
4783             {
4784               aopPut (result, "a", offset++);
4785             }
4786         }
4787       else
4788         {
4789           while (size--)
4790             {
4791               aopPut (result, zero, offset++);
4792             }
4793         }
4794     }
4795 }
4796
4797 /*-----------------------------------------------------------------*/
4798 /* genMinusBits - generates code for subtraction  of two bits      */
4799 /*-----------------------------------------------------------------*/
4800 static void
4801 genMinusBits (iCode * ic)
4802 {
4803   symbol *lbl = newiTempLabel (NULL);
4804
4805   D (emitcode (";", "genMinusBits"));
4806
4807   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4808     {
4809       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4810       emitcode ("jnb", "%s,%05d$", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4811       emitcode ("cpl", "c");
4812       emitLabel (lbl);
4813       outBitC (IC_RESULT (ic));
4814     }
4815   else
4816     {
4817       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4818       emitcode ("subb", "a,acc");
4819       emitcode ("jnb", "%s,%05d$", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4820       emitcode ("inc", "a");
4821       emitLabel (lbl);
4822       aopPut (IC_RESULT (ic), "a", 0);
4823       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4824     }
4825 }
4826
4827 /*-----------------------------------------------------------------*/
4828 /* genMinus - generates code for subtraction                       */
4829 /*-----------------------------------------------------------------*/
4830 static void
4831 genMinus (iCode * ic)
4832 {
4833   int size, offset = 0;
4834
4835   D (emitcode (";", "genMinus"));
4836
4837   aopOp (IC_LEFT (ic), ic, FALSE);
4838   aopOp (IC_RIGHT (ic), ic, FALSE);
4839   aopOp (IC_RESULT (ic), ic, TRUE);
4840
4841   /* special cases :- */
4842   /* if both left & right are in bit space */
4843   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4844       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4845     {
4846       genMinusBits (ic);
4847       goto release;
4848     }
4849
4850   /* if I can do an decrement instead
4851      of subtract then GOOD for ME */
4852   if (genMinusDec (ic) == TRUE)
4853     goto release;
4854
4855   size = getDataSize (IC_RESULT (ic));
4856
4857   /* if literal, add a,#-lit, else normal subb */
4858   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4859     {
4860       unsigned long lit = 0L;
4861       bool useCarry = FALSE;
4862
4863       lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4864       lit = -(long) lit;
4865
4866       while (size--)
4867         {
4868           if (useCarry || ((lit >> (offset * 8)) & 0x0FFL))
4869             {
4870               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE));
4871               if (!offset && !size && lit== (unsigned long) -1)
4872                 {
4873                   emitcode ("dec", "a");
4874                 }
4875               else if (!useCarry)
4876                 {
4877                   /* first add without previous c */
4878                   emitcode ("add", "a,#0x%02x",
4879                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4880                   useCarry = TRUE;
4881                 }
4882               else
4883                 {
4884                   emitcode ("addc", "a,#0x%02x",
4885                             (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4886                 }
4887               aopPut (IC_RESULT (ic), "a", offset++);
4888             }
4889           else
4890             {
4891               /* no need to add zeroes */
4892               if (!sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4893                 {
4894                   aopPut (IC_RESULT (ic), aopGet (IC_LEFT (ic), offset, FALSE, FALSE),
4895                           offset);
4896                 }
4897               offset++;
4898             }
4899         }
4900     }
4901   else
4902     {
4903       operand *leftOp, *rightOp;
4904
4905       leftOp = IC_LEFT(ic);
4906       rightOp = IC_RIGHT(ic);
4907
4908       while (size--)
4909         {
4910           if (aopGetUsesAcc(rightOp, offset)) {
4911             if (aopGetUsesAcc(leftOp, offset)) {
4912               bool pushedB;
4913
4914               MOVA (aopGet (rightOp, offset, FALSE, FALSE));
4915               pushedB = pushB ();
4916               emitcode ("mov", "b,a");
4917               if (offset == 0)
4918                 CLRC;
4919               MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4920               emitcode ("subb", "a,b");
4921               popB (pushedB);
4922             } else {
4923               /* reverse subtraction with 2's complement */
4924               if (offset == 0)
4925                 emitcode( "setb", "c");
4926               else
4927                 emitcode( "cpl", "c");
4928               wassertl(!aopGetUsesAcc(leftOp, offset), "accumulator clash");
4929               MOVA (aopGet(rightOp, offset, FALSE, TRUE));
4930               emitcode("subb", "a,%s", aopGet(leftOp, offset, FALSE, TRUE));
4931               emitcode("cpl", "a");
4932               if (size) /* skip if last byte */
4933                 emitcode( "cpl", "c");
4934             }
4935           } else {
4936             MOVA (aopGet (leftOp, offset, FALSE, FALSE));
4937             if (offset == 0)
4938               CLRC;
4939             emitcode ("subb", "a,%s",
4940                       aopGet(rightOp, offset, FALSE, TRUE));
4941           }
4942
4943           aopPut (IC_RESULT (ic), "a", offset++);
4944         }
4945     }
4946
4947   adjustArithmeticResult (ic);
4948
4949 release:
4950   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4951   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4952   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4953 }
4954
4955
4956 /*-----------------------------------------------------------------*/
4957 /* genMultbits :- multiplication of bits                           */
4958 /*-----------------------------------------------------------------*/
4959 static void
4960 genMultbits (operand * left,
4961              operand * right,
4962              operand * result)
4963 {
4964   D (emitcode (";", "genMultbits"));
4965
4966   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4967   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4968   outBitC (result);
4969 }
4970
4971 /*-----------------------------------------------------------------*/
4972 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4973 /*-----------------------------------------------------------------*/
4974 static void
4975 genMultOneByte (operand * left,
4976                 operand * right,
4977                 operand * result)
4978 {
4979   symbol *lbl;
4980   int size = AOP_SIZE (result);
4981   bool runtimeSign, compiletimeSign;
4982   bool lUnsigned, rUnsigned, pushedB;
4983
4984   D (emitcode (";", "genMultOneByte"));
4985
4986   if (size < 1 || size > 2)
4987     {
4988       /* this should never happen */
4989       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4990                AOP_SIZE(result), __FILE__, lineno);
4991       exit (1);
4992     }
4993
4994   /* (if two literals: the value is computed before) */
4995   /* if one literal, literal on the right */
4996   if (AOP_TYPE (left) == AOP_LIT)
4997     {
4998       operand *t = right;
4999       right = left;
5000       left = t;
5001       /* emitcode (";", "swapped left and right"); */
5002     }
5003   /* if no literal, unsigned on the right: shorter code */
5004   if (   AOP_TYPE (right) != AOP_LIT
5005       && SPEC_USIGN (getSpec (operandType (left))))
5006     {
5007       operand *t = right;
5008       right = left;
5009       left = t;
5010     }
5011
5012   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5013   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5014
5015   pushedB = pushB ();
5016
5017   if (size == 1 /* no, this is not a bug; with a 1 byte result there's
5018                    no need to take care about the signedness! */
5019       || (lUnsigned && rUnsigned))
5020     {
5021       /* just an unsigned 8 * 8 = 8 multiply
5022          or 8u * 8u = 16u */
5023       /* emitcode (";","unsigned"); */
5024       /* TODO: check for accumulator clash between left & right aops? */
5025
5026       if (AOP_TYPE (right) == AOP_LIT)
5027         {
5028           /* moving to accumulator first helps peepholes */
5029           MOVA (aopGet (left, 0, FALSE, FALSE));
5030           MOVB (aopGet (right, 0, FALSE, FALSE));
5031         }
5032       else
5033         {
5034           emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5035           MOVA (aopGet (left, 0, FALSE, FALSE));
5036         }
5037
5038       emitcode ("mul", "ab");
5039       aopPut (result, "a", 0);
5040       if (size == 2)
5041         aopPut (result, "b", 1);
5042
5043       popB (pushedB);
5044       return;
5045     }
5046
5047   /* we have to do a signed multiply */
5048   /* emitcode (";", "signed"); */
5049
5050   /* now sign adjust for both left & right */
5051
5052   /* let's see what's needed: */
5053   /* apply negative sign during runtime */
5054   runtimeSign = FALSE;
5055   /* negative sign from literals */
5056   compiletimeSign = FALSE;
5057
5058   if (!lUnsigned)
5059     {
5060       if (AOP_TYPE(left) == AOP_LIT)
5061         {
5062           /* signed literal */
5063           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5064           if (val < 0)
5065             compiletimeSign = TRUE;
5066         }
5067       else
5068         /* signed but not literal */
5069         runtimeSign = TRUE;
5070     }
5071
5072   if (!rUnsigned)
5073     {
5074       if (AOP_TYPE(right) == AOP_LIT)
5075         {
5076           /* signed literal */
5077           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5078           if (val < 0)
5079             compiletimeSign ^= TRUE;
5080         }
5081       else
5082         /* signed but not literal */
5083         runtimeSign = TRUE;
5084     }
5085
5086   /* initialize F0, which stores the runtime sign */
5087   if (runtimeSign)
5088     {
5089       if (compiletimeSign)
5090         emitcode ("setb", "F0"); /* set sign flag */
5091       else
5092         emitcode ("clr", "F0"); /* reset sign flag */
5093     }
5094
5095   /* save the signs of the operands */
5096   if (AOP_TYPE(right) == AOP_LIT)
5097     {
5098       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5099
5100       if (!rUnsigned && val < 0)
5101         emitcode ("mov", "b,#0x%02x", -val);
5102       else
5103         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5104     }
5105   else /* ! literal */
5106     {
5107       if (rUnsigned)  /* emitcode (";", "signed"); */
5108         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5109       else
5110         {
5111           MOVA (aopGet (right, 0, FALSE, FALSE));
5112           lbl = newiTempLabel (NULL);
5113           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5114           emitcode ("cpl", "F0"); /* complement sign flag */
5115           emitcode ("cpl", "a");  /* 2's complement */
5116           emitcode ("inc", "a");
5117           emitLabel (lbl);
5118           emitcode ("mov", "b,a");
5119         }
5120     }
5121
5122   if (AOP_TYPE(left) == AOP_LIT)
5123     {
5124       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5125
5126       if (!lUnsigned && val < 0)
5127         emitcode ("mov", "a,#0x%02x", -val);
5128       else
5129         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5130     }
5131   else /* ! literal */
5132     {
5133       MOVA (aopGet (left, 0, FALSE, FALSE));
5134
5135       if (!lUnsigned)
5136         {
5137           lbl = newiTempLabel (NULL);
5138           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5139           emitcode ("cpl", "F0"); /* complement sign flag */
5140           emitcode ("cpl", "a"); /* 2's complement */
5141           emitcode ("inc", "a");
5142           emitLabel (lbl);
5143         }
5144     }
5145
5146   /* now the multiplication */
5147   emitcode ("mul", "ab");
5148   if (runtimeSign || compiletimeSign)
5149     {
5150       lbl = newiTempLabel (NULL);
5151       if (runtimeSign)
5152         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5153       emitcode ("cpl", "a"); /* lsb 2's complement */
5154       if (size != 2)
5155         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5156       else
5157         {
5158           emitcode ("add", "a,#1"); /* this sets carry flag */
5159           emitcode ("xch", "a,b");
5160           emitcode ("cpl", "a"); /* msb 2's complement */
5161           emitcode ("addc", "a,#0");
5162           emitcode ("xch", "a,b");
5163         }
5164       emitLabel (lbl);
5165     }
5166   aopPut (result, "a", 0);
5167   if (size == 2)
5168     aopPut (result, "b", 1);
5169
5170   popB (pushedB);
5171 }
5172
5173 /*-----------------------------------------------------------------*/
5174 /* genMult - generates code for multiplication                     */
5175 /*-----------------------------------------------------------------*/
5176 static void
5177 genMult (iCode * ic)
5178 {
5179   operand *left = IC_LEFT (ic);
5180   operand *right = IC_RIGHT (ic);
5181   operand *result = IC_RESULT (ic);
5182
5183   D (emitcode (";", "genMult"));
5184
5185   /* assign the asmops */
5186   aopOp (left, ic, FALSE);
5187   aopOp (right, ic, FALSE);
5188   aopOp (result, ic, TRUE);
5189
5190   /* special cases first */
5191   /* both are bits */
5192   if (AOP_TYPE (left) == AOP_CRY &&
5193       AOP_TYPE (right) == AOP_CRY)
5194     {
5195       genMultbits (left, right, result);
5196       goto release;
5197     }
5198
5199   /* if both are of size == 1 */
5200 #if 0 // one of them can be a sloc shared with the result
5201     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
5202 #else
5203   if (getSize(operandType(left)) == 1 &&
5204       getSize(operandType(right)) == 1)
5205 #endif
5206     {
5207       genMultOneByte (left, right, result);
5208       goto release;
5209     }
5210
5211   /* should have been converted to function call */
5212     fprintf (stderr, "left: %d right: %d\n", getSize(OP_SYMBOL(left)->type),
5213              getSize(OP_SYMBOL(right)->type));
5214   assert (0);
5215
5216 release:
5217   freeAsmop (result, NULL, ic, TRUE);
5218   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5219   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5220 }
5221
5222 /*-----------------------------------------------------------------*/
5223 /* genDivbits :- division of bits                                  */
5224 /*-----------------------------------------------------------------*/
5225 static void
5226 genDivbits (operand * left,
5227             operand * right,
5228             operand * result)
5229 {
5230   char *l;
5231   bool pushedB;
5232
5233   D(emitcode (";", "genDivbits"));
5234
5235   pushedB = pushB ();
5236
5237   /* the result must be bit */
5238   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5239   l = aopGet (left, 0, FALSE, FALSE);
5240
5241   MOVA (l);
5242
5243   emitcode ("div", "ab");
5244   emitcode ("rrc", "a");
5245
5246   popB (pushedB);
5247
5248   aopPut (result, "c", 0);
5249 }
5250
5251 /*-----------------------------------------------------------------*/
5252 /* genDivOneByte : 8 bit division                                  */
5253 /*-----------------------------------------------------------------*/
5254 static void
5255 genDivOneByte (operand * left,
5256                operand * right,
5257                operand * result)
5258 {
5259   bool lUnsigned, rUnsigned, pushedB;
5260   bool runtimeSign, compiletimeSign;
5261   bool accuse = FALSE;
5262   bool pushedA = FALSE;
5263   symbol *lbl;
5264   int size, offset;
5265
5266   D(emitcode (";", "genDivOneByte"));
5267
5268   /* Why is it necessary that genDivOneByte() can return an int result?
5269      Have a look at:
5270
5271         volatile unsigned char uc;
5272         volatile signed char sc1, sc2;
5273         volatile int i;
5274
5275         uc  = 255;
5276         sc1 = -1;
5277         i = uc / sc1;
5278
5279      Or:
5280
5281         sc1 = -128;
5282         sc2 = -1;
5283         i = sc1 / sc2;
5284
5285      In all cases a one byte result would overflow, the following cast to int
5286      would return the wrong result.
5287
5288      Two possible solution:
5289         a) cast operands to int, if ((unsigned) / (signed)) or
5290            ((signed) / (signed))
5291         b) return an 16 bit signed int; this is what we're doing here!
5292   */
5293
5294   size = AOP_SIZE (result) - 1;
5295   offset = 1;
5296   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5297   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5298
5299   pushedB = pushB ();
5300
5301   /* signed or unsigned */
5302   if (lUnsigned && rUnsigned)
5303     {
5304       /* unsigned is easy */
5305       MOVB (aopGet (right, 0, FALSE, FALSE));
5306       MOVA (aopGet (left, 0, FALSE, FALSE));
5307       emitcode ("div", "ab");
5308       aopPut (result, "a", 0);
5309       while (size--)
5310         aopPut (result, zero, offset++);
5311
5312       popB (pushedB);
5313       return;
5314     }
5315
5316   /* signed is a little bit more difficult */
5317
5318   /* now sign adjust for both left & right */
5319
5320   /* let's see what's needed: */
5321   /* apply negative sign during runtime */
5322   runtimeSign = FALSE;
5323   /* negative sign from literals */
5324   compiletimeSign = FALSE;
5325
5326   if (!lUnsigned)
5327     {
5328       if (AOP_TYPE(left) == AOP_LIT)
5329         {
5330           /* signed literal */
5331           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5332           if (val < 0)
5333             compiletimeSign = TRUE;
5334         }
5335       else
5336         /* signed but not literal */
5337         runtimeSign = TRUE;
5338     }
5339
5340   if (!rUnsigned)
5341     {
5342       if (AOP_TYPE(right) == AOP_LIT)
5343         {
5344           /* signed literal */
5345           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5346           if (val < 0)
5347             compiletimeSign ^= TRUE;
5348         }
5349       else
5350         /* signed but not literal */
5351         runtimeSign = TRUE;
5352     }
5353
5354   /* initialize F0, which stores the runtime sign */
5355   if (runtimeSign)
5356     {
5357       if (compiletimeSign)
5358         emitcode ("setb", "F0"); /* set sign flag */
5359       else
5360         emitcode ("clr", "F0"); /* reset sign flag */
5361     }
5362
5363   /* save the signs of the operands */
5364   if (AOP_TYPE(right) == AOP_LIT)
5365     {
5366       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5367
5368       if (!rUnsigned && val < 0)
5369         emitcode ("mov", "b,#0x%02x", -val);
5370       else
5371         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5372     }
5373   else /* ! literal */
5374     {
5375       if (rUnsigned)
5376         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5377       else
5378         {
5379           MOVA (aopGet (right, 0, FALSE, FALSE));
5380           lbl = newiTempLabel (NULL);
5381           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5382           emitcode ("cpl", "F0"); /* complement sign flag */
5383           emitcode ("cpl", "a");  /* 2's complement */
5384           emitcode ("inc", "a");
5385           emitLabel (lbl);
5386           emitcode ("mov", "b,a");
5387         }
5388     }
5389
5390   if (AOP_TYPE(left) == AOP_LIT)
5391     {
5392       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5393
5394       if (!lUnsigned && val < 0)
5395         emitcode ("mov", "a,#0x%02x", -val);
5396       else
5397         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5398     }
5399   else /* ! literal */
5400     {
5401       MOVA (aopGet (left, 0, FALSE, FALSE));
5402
5403       if (!lUnsigned)
5404         {
5405           lbl = newiTempLabel (NULL);
5406           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5407           emitcode ("cpl", "F0"); /* complement sign flag */
5408           emitcode ("cpl", "a");  /* 2's complement */
5409           emitcode ("inc", "a");
5410           emitLabel (lbl);
5411         }
5412     }
5413
5414   /* now the division */
5415   emitcode ("div", "ab");
5416
5417   if (runtimeSign || compiletimeSign)
5418     {
5419       lbl = newiTempLabel (NULL);
5420       if (runtimeSign)
5421         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5422       emitcode ("cpl", "a"); /* lsb 2's complement */
5423       emitcode ("inc", "a");
5424       emitLabel (lbl);
5425
5426       accuse = aopPut (result, "a", 0);
5427       if (size > 0)
5428         {
5429           /* msb is 0x00 or 0xff depending on the sign */
5430           if (runtimeSign)
5431             {
5432               if (accuse)
5433                 {
5434                   emitcode ("push", "acc");
5435                   pushedA = TRUE;
5436                 }
5437               emitcode ("mov", "c,F0");
5438               emitcode ("subb", "a,acc");
5439               while (size--)
5440                 aopPut (result, "a", offset++);
5441             }
5442           else /* compiletimeSign */
5443             {
5444               if (aopPutUsesAcc (result, "#0xFF", offset))
5445                 {
5446                   emitcode ("push", "acc");
5447                   pushedA = TRUE;
5448                 }
5449               while (size--)
5450                 aopPut (result, "#0xff", offset++);
5451             }
5452         }
5453     }
5454   else
5455     {
5456       aopPut (result, "a", 0);
5457       while (size--)
5458         aopPut (result, zero, offset++);
5459     }
5460
5461   if (pushedA)
5462     emitcode ("pop", "acc");
5463   popB (pushedB);
5464 }
5465
5466 /*-----------------------------------------------------------------*/
5467 /* genDiv - generates code for division                            */
5468 /*-----------------------------------------------------------------*/
5469 static void
5470 genDiv (iCode * ic)
5471 {
5472   operand *left = IC_LEFT (ic);
5473   operand *right = IC_RIGHT (ic);
5474   operand *result = IC_RESULT (ic);
5475
5476   D (emitcode (";", "genDiv"));
5477
5478   /* assign the asmops */
5479   aopOp (left, ic, FALSE);
5480   aopOp (right, ic, FALSE);
5481   aopOp (result, ic, TRUE);
5482
5483   /* special cases first */
5484   /* both are bits */
5485   if (AOP_TYPE (left) == AOP_CRY &&
5486       AOP_TYPE (right) == AOP_CRY)
5487     {
5488       genDivbits (left, right, result);
5489       goto release;
5490     }
5491
5492   /* if both are of size == 1 */
5493   if (AOP_SIZE (left) == 1 &&
5494       AOP_SIZE (right) == 1)
5495     {
5496       genDivOneByte (left, right, result);
5497       goto release;
5498     }
5499
5500   /* should have been converted to function call */
5501   assert (0);
5502 release:
5503   freeAsmop (result, NULL, ic, TRUE);
5504   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5505   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5506 }
5507
5508 /*-----------------------------------------------------------------*/
5509 /* genModbits :- modulus of bits                                   */
5510 /*-----------------------------------------------------------------*/
5511 static void
5512 genModbits (operand * left,
5513             operand * right,
5514             operand * result)
5515 {
5516   char *l;
5517   bool pushedB;
5518
5519   D (emitcode (";", "genModbits"));
5520
5521   pushedB = pushB ();
5522
5523   /* the result must be bit */
5524   emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5525   l = aopGet (left, 0, FALSE, FALSE);
5526
5527   MOVA (l);
5528
5529   emitcode ("div", "ab");
5530   emitcode ("mov", "a,b");
5531   emitcode ("rrc", "a");
5532
5533   popB (pushedB);
5534
5535   aopPut (result, "c", 0);
5536 }
5537
5538 /*-----------------------------------------------------------------*/
5539 /* genModOneByte : 8 bit modulus                                   */
5540 /*-----------------------------------------------------------------*/
5541 static void
5542 genModOneByte (operand * left,
5543                operand * right,
5544                operand * result)
5545 {
5546   bool lUnsigned, rUnsigned, pushedB;
5547   bool runtimeSign, compiletimeSign;
5548   symbol *lbl;
5549   int size, offset;
5550
5551   D (emitcode (";", "genModOneByte"));
5552
5553   size = AOP_SIZE (result) - 1;
5554   offset = 1;
5555   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5556   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5557
5558   /* if right is a literal, check it for 2^n */
5559   if (AOP_TYPE(right) == AOP_LIT)
5560     {
5561       unsigned char val = abs((int) operandLitValue(right));
5562       symbol *lbl2 = NULL;
5563
5564       switch (val)
5565         {
5566           case 1: /* sometimes it makes sense (on tricky code and hardware)... */
5567           case 2:
5568           case 4:
5569           case 8:
5570           case 16:
5571           case 32:
5572           case 64:
5573           case 128:
5574             if (lUnsigned)
5575               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
5576                       "modulus of unsigned char by 2^n literal shouldn't be processed here");
5577               /* because iCode should have been changed to genAnd  */
5578               /* see file "SDCCopt.c", function "convertToFcall()" */
5579
5580             MOVA (aopGet (left, 0, FALSE, FALSE));
5581             emitcode ("mov", "c,acc.7");
5582             emitcode ("anl", "a,#0x%02x", val - 1);
5583             lbl = newiTempLabel (NULL);
5584             emitcode ("jz", "%05d$", (lbl->key + 100));
5585             emitcode ("jnc", "%05d$", (lbl->key + 100));
5586             emitcode ("orl", "a,#0x%02x", 0xff ^ (val - 1));
5587             if (size)
5588               {
5589                 int size2 = size;
5590                 int offs2 = offset;
5591
5592                 aopPut (result, "a", 0);
5593                 while (size2--)
5594                   aopPut (result, "#0xff", offs2++);
5595                 lbl2 = newiTempLabel (NULL);
5596                 emitcode ("sjmp", "%05d$", (lbl2->key + 100));
5597               }
5598             emitLabel (lbl);
5599             aopPut (result, "a", 0);
5600             while (size--)
5601               aopPut (result, zero, offset++);
5602             if (lbl2)
5603               {
5604                 emitLabel (lbl2);
5605               }
5606             return;
5607
5608           default:
5609             break;
5610         }
5611     }
5612
5613   pushedB = pushB ();
5614
5615   /* signed or unsigned */
5616   if (lUnsigned && rUnsigned)
5617     {
5618       /* unsigned is easy */
5619       MOVB (aopGet (right, 0, FALSE, FALSE));
5620       MOVA (aopGet (left, 0, FALSE, FALSE));
5621       emitcode ("div", "ab");
5622       aopPut (result, "b", 0);
5623       while (size--)
5624         aopPut (result, zero, offset++);
5625
5626       popB (pushedB);
5627       return;
5628     }
5629
5630   /* signed is a little bit more difficult */
5631
5632   /* now sign adjust for both left & right */
5633
5634   /* modulus: sign of the right operand has no influence on the result! */
5635   if (AOP_TYPE(right) == AOP_LIT)
5636     {
5637       signed char val = (char) operandLitValue(right);
5638
5639       if (!rUnsigned && val < 0)
5640         emitcode ("mov", "b,#0x%02x", -val);
5641       else
5642         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5643     }
5644   else /* not literal */
5645     {
5646       if (rUnsigned)
5647         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE));
5648       else
5649         {
5650           MOVA (aopGet (right, 0, FALSE, FALSE));
5651           lbl = newiTempLabel (NULL);
5652           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5653           emitcode ("cpl", "a"); /* 2's complement */
5654           emitcode ("inc", "a");
5655           emitLabel (lbl);
5656           emitcode ("mov", "b,a");
5657         }
5658     }
5659
5660   /* let's see what's needed: */
5661   /* apply negative sign during runtime */
5662   runtimeSign = FALSE;
5663   /* negative sign from literals */
5664   compiletimeSign = FALSE;
5665
5666   /* sign adjust left side */
5667   if (AOP_TYPE(left) == AOP_LIT)
5668     {
5669       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5670
5671       if (!lUnsigned && val < 0)
5672         {
5673           compiletimeSign = TRUE; /* set sign flag */
5674           emitcode ("mov", "a,#0x%02x", -val);
5675         }
5676       else
5677         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5678     }
5679   else /* ! literal */
5680     {
5681       MOVA (aopGet (left, 0, FALSE, FALSE));
5682
5683       if (!lUnsigned)
5684         {
5685           runtimeSign = TRUE;
5686           emitcode ("clr", "F0"); /* clear sign flag */
5687
5688           lbl = newiTempLabel (NULL);
5689           emitcode ("jnb", "acc.7,%05d$", (lbl->key + 100));
5690           emitcode ("setb", "F0"); /* set sign flag */
5691           emitcode ("cpl", "a");   /* 2's complement */
5692           emitcode ("inc", "a");
5693           emitLabel (lbl);
5694         }
5695     }
5696
5697   /* now the modulus */
5698   emitcode ("div", "ab");
5699
5700   if (runtimeSign || compiletimeSign)
5701     {
5702       emitcode ("mov", "a,b");
5703       lbl = newiTempLabel (NULL);
5704       if (runtimeSign)
5705         emitcode ("jnb", "F0,%05d$", (lbl->key + 100));
5706       emitcode ("cpl", "a"); /* 2's complement */
5707       emitcode ("inc", "a");
5708       emitLabel (lbl);
5709
5710       aopPut (result, "a", 0);
5711       if (size > 0)
5712         {
5713           /* msb is 0x00 or 0xff depending on the sign */
5714           if (runtimeSign)
5715             {
5716               emitcode ("mov", "c,F0");
5717               emitcode ("subb", "a,acc");
5718               while (size--)
5719                 aopPut (result, "a", offset++);
5720             }
5721           else /* compiletimeSign */
5722             while (size--)
5723               aopPut (result, "#0xff", offset++);
5724         }
5725     }
5726   else
5727     {
5728       aopPut (result, "b", 0);
5729       while (size--)
5730         aopPut (result, zero, offset++);
5731     }
5732
5733   popB (pushedB);
5734 }
5735
5736 /*-----------------------------------------------------------------*/
5737 /* genMod - generates code for division                            */
5738 /*-----------------------------------------------------------------*/
5739 static void
5740 genMod (iCode * ic)
5741 {
5742   operand *left = IC_LEFT (ic);
5743   operand *right = IC_RIGHT (ic);
5744   operand *result = IC_RESULT (ic);
5745
5746   D (emitcode (";", "genMod"));
5747
5748   /* assign the asmops */
5749   aopOp (left, ic, FALSE);
5750   aopOp (right, ic, FALSE);
5751   aopOp (result, ic, TRUE);
5752
5753   /* special cases first */
5754   /* both are bits */
5755   if (AOP_TYPE (left) == AOP_CRY &&
5756       AOP_TYPE (right) == AOP_CRY)
5757     {
5758       genModbits (left, right, result);
5759       goto release;
5760     }
5761
5762   /* if both are of size == 1 */
5763   if (AOP_SIZE (left) == 1 &&
5764       AOP_SIZE (right) == 1)
5765     {
5766       genModOneByte (left, right, result);
5767       goto release;
5768     }
5769
5770   /* should have been converted to function call */
5771   assert (0);
5772
5773 release:
5774   freeAsmop (result, NULL, ic, TRUE);
5775   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5776   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5777 }
5778
5779 /*-----------------------------------------------------------------*/
5780 /* genIfxJump :- will create a jump depending on the ifx           */
5781 /*-----------------------------------------------------------------*/
5782 static void
5783 genIfxJump (iCode * ic, char *jval, operand *left, operand *right, operand *result)
5784 {
5785   symbol *jlbl;
5786   symbol *tlbl = newiTempLabel (NULL);
5787   char *inst;
5788
5789   D (emitcode (";", "genIfxJump"));
5790
5791   /* if true label then we jump if condition
5792      supplied is true */
5793   if (IC_TRUE (ic))
5794     {
5795       jlbl = IC_TRUE (ic);
5796       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5797                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5798     }
5799   else
5800     {
5801       /* false label is present */
5802       jlbl = IC_FALSE (ic);
5803       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5804                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5805     }
5806   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5807     emitcode (inst, "%s,%05d$", jval, (tlbl->key + 100));
5808   else
5809     emitcode (inst, "%05d$", tlbl->key + 100);
5810   freeForBranchAsmop (result);
5811   freeForBranchAsmop (right);
5812   freeForBranchAsmop (left);
5813   emitcode ("ljmp", "%05d$", jlbl->key + 100);
5814   emitLabel (tlbl);
5815
5816   /* mark the icode as generated */
5817   ic->generated = 1;
5818 }
5819
5820 /*-----------------------------------------------------------------*/
5821 /* genCmp :- greater or less than comparison                       */
5822 /*-----------------------------------------------------------------*/
5823 static void
5824 genCmp (operand * left, operand * right,
5825         operand * result, iCode * ifx, int sign, iCode *ic)
5826 {
5827   int size, offset = 0;
5828   unsigned long lit = 0L;
5829   bool rightInB;
5830
5831   D (emitcode (";", "genCmp"));
5832
5833   /* if left & right are bit variables */
5834   if (AOP_TYPE (left) == AOP_CRY &&
5835       AOP_TYPE (right) == AOP_CRY)
5836     {
5837       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5838       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5839     }
5840   else
5841     {
5842       /* subtract right from left if at the
5843          end the carry flag is set then we know that
5844          left is greater than right */
5845       size = max (AOP_SIZE (left), AOP_SIZE (right));
5846
5847       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5848       if ((size == 1) && !sign &&
5849           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
5850         {
5851           symbol *lbl = newiTempLabel (NULL);
5852           emitcode ("cjne", "%s,%s,%05d$",
5853                     aopGet (left, offset, FALSE, FALSE),
5854                     aopGet (right, offset, FALSE, FALSE),
5855                     lbl->key + 100);
5856           emitLabel (lbl);
5857         }
5858       else
5859         {
5860           if (AOP_TYPE (right) == AOP_LIT)
5861             {
5862               lit = ulFromVal (AOP (right)->aopu.aop_lit);
5863               /* optimize if(x < 0) or if(x >= 0) */
5864               if (lit == 0L)
5865                 {
5866                   if (!sign)
5867                     {
5868                       CLRC;
5869                     }
5870                   else
5871                     {
5872                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
5873                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5874                         {
5875                           genIfxJump (ifx, "acc.7", left, right, result);
5876                           freeAsmop (right, NULL, ic, TRUE);
5877                           freeAsmop (left, NULL, ic, TRUE);
5878
5879                           return;
5880                         }
5881                       else
5882                         {
5883                           emitcode ("rlc", "a");
5884                         }
5885                     }
5886                   goto release;
5887                 }
5888               else
5889                 {//nonzero literal
5890                   int bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5891                   while (size && (bytelit == 0))
5892                     {
5893                       offset++;
5894                       bytelit = ((lit >> (offset * 8)) & 0x0FFL);
5895                       size--;
5896                     }
5897                   CLRC;
5898                   while (size--)
5899                     {
5900                       MOVA (aopGet (left, offset, FALSE, FALSE));
5901                       if (sign && size == 0)
5902                         {
5903                           emitcode ("xrl", "a,#0x80");
5904                           emitcode ("subb", "a,#0x%02x",
5905                                     0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5906                         }
5907                       else
5908                         {
5909                           emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5910                         }
5911                       offset++;
5912                     }
5913                   goto release;
5914                 }
5915             }
5916           CLRC;
5917           while (size--)
5918             {
5919               bool pushedB = FALSE;
5920               rightInB = aopGetUsesAcc(right, offset);
5921               if (rightInB)
5922                 {
5923                   pushedB = pushB ();
5924                   emitcode ("mov", "b,%s", aopGet (right, offset, FALSE, FALSE));
5925                 }
5926               MOVA (aopGet (left, offset, FALSE, FALSE));
5927               if (sign && size == 0)
5928                 {
5929                   emitcode ("xrl", "a,#0x80");
5930                   if (!rightInB)
5931                     {
5932                       pushedB = pushB ();
5933                       rightInB++;
5934                       MOVB (aopGet (right, offset, FALSE, FALSE));
5935                     }
5936                   emitcode ("xrl", "b,#0x80");
5937                   emitcode ("subb", "a,b");
5938                 }
5939               else
5940                 {
5941                   if (rightInB)
5942                     emitcode ("subb", "a,b");
5943                   else
5944                     emitcode ("subb", "a,%s", aopGet (right, offset, FALSE, FALSE));
5945                 }
5946               if (rightInB)
5947                 popB (pushedB);
5948               offset++;
5949             }
5950         }
5951     }
5952
5953 release:
5954   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5955   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5956   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5957     {
5958       outBitC (result);
5959     }
5960   else
5961     {
5962       /* if the result is used in the next
5963          ifx conditional branch then generate
5964          code a little differently */
5965       if (ifx)
5966         {
5967           genIfxJump (ifx, "c", NULL, NULL, result);
5968         }
5969       else
5970         {
5971           outBitC (result);
5972         }
5973       /* leave the result in acc */
5974     }
5975 }
5976
5977 /*-----------------------------------------------------------------*/
5978 /* genCmpGt :- greater than comparison                             */
5979 /*-----------------------------------------------------------------*/
5980 static void
5981 genCmpGt (iCode * ic, iCode * ifx)
5982 {
5983   operand *left, *right, *result;
5984   sym_link *letype, *retype;
5985   int sign;
5986
5987   D (emitcode (";", "genCmpGt"));
5988
5989   left = IC_LEFT (ic);
5990   right = IC_RIGHT (ic);
5991   result = IC_RESULT (ic);
5992
5993   letype = getSpec (operandType (left));
5994   retype = getSpec (operandType (right));
5995   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
5996            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
5997   /* assign the asmops */
5998   aopOp (result, ic, TRUE);
5999   aopOp (left, ic, FALSE);
6000   aopOp (right, ic, FALSE);
6001
6002   genCmp (right, left, result, ifx, sign, ic);
6003
6004   freeAsmop (result, NULL, ic, TRUE);
6005 }
6006
6007 /*-----------------------------------------------------------------*/
6008 /* genCmpLt - less than comparisons                                */
6009 /*-----------------------------------------------------------------*/
6010 static void
6011 genCmpLt (iCode * ic, iCode * ifx)
6012 {
6013   operand *left, *right, *result;
6014   sym_link *letype, *retype;
6015   int sign;
6016
6017   D (emitcode (";", "genCmpLt"));
6018
6019   left = IC_LEFT (ic);
6020   right = IC_RIGHT (ic);
6021   result = IC_RESULT (ic);
6022
6023   letype = getSpec (operandType (left));
6024   retype = getSpec (operandType (right));
6025   sign = !((SPEC_USIGN (letype) && !(IS_CHAR (letype) && IS_LITERAL (letype))) ||
6026            (SPEC_USIGN (retype) && !(IS_CHAR (retype) && IS_LITERAL (retype))));
6027   /* assign the asmops */
6028   aopOp (result, ic, TRUE);
6029   aopOp (left, ic, FALSE);
6030   aopOp (right, ic, FALSE);
6031
6032   genCmp (left, right, result, ifx, sign, ic);
6033
6034   freeAsmop (result, NULL, ic, TRUE);
6035 }
6036
6037 /*-----------------------------------------------------------------*/
6038 /* gencjneshort - compare and jump if not equal                    */
6039 /*-----------------------------------------------------------------*/
6040 static void
6041 gencjneshort (operand * left, operand * right, symbol * lbl)
6042 {
6043   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6044   int offset = 0;
6045   unsigned long lit = 0L;
6046
6047   D (emitcode (";", "gencjneshort"));
6048
6049   /* if the left side is a literal or
6050      if the right is in a pointer register and left
6051      is not */
6052   if ((AOP_TYPE (left) == AOP_LIT)  ||
6053       (AOP_TYPE (left) == AOP_IMMD) ||
6054       (AOP_TYPE (left) == AOP_DIR)  ||
6055       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6056     {
6057       operand *t = right;
6058       right = left;
6059       left = t;
6060     }
6061
6062   if (AOP_TYPE (right) == AOP_LIT)
6063     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6064
6065   /* if the right side is a literal then anything goes */
6066   if (AOP_TYPE (right) == AOP_LIT &&
6067       AOP_TYPE (left) != AOP_DIR  &&
6068       AOP_TYPE (left) != AOP_IMMD)
6069     {
6070       while (size--)
6071         {
6072           emitcode ("cjne", "%s,%s,%05d$",
6073                     aopGet (left, offset, FALSE, FALSE),
6074                     aopGet (right, offset, FALSE, FALSE),
6075                     lbl->key + 100);
6076           offset++;
6077         }
6078     }
6079
6080   /* if the right side is in a register or in direct space or
6081      if the left is a pointer register & right is not */
6082   else if (AOP_TYPE (right) == AOP_REG ||
6083            AOP_TYPE (right) == AOP_DIR ||
6084            AOP_TYPE (right) == AOP_LIT ||
6085            AOP_TYPE (right) == AOP_IMMD ||
6086            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6087            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6088     {
6089       while (size--)
6090         {
6091           MOVA (aopGet (left, offset, FALSE, FALSE));
6092           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6093               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6094             emitcode ("jnz", "%05d$", lbl->key + 100);
6095           else
6096             emitcode ("cjne", "a,%s,%05d$",
6097                       aopGet (right, offset, FALSE, TRUE),
6098                       lbl->key + 100);
6099           offset++;
6100         }
6101     }
6102   else
6103     {
6104       /* right is a pointer reg need both a & b */
6105       while (size--)
6106         {
6107           //if B in use: push B; mov B,left; mov A,right; clrc; subb A,B; pop B; jnz
6108           wassertl(!BINUSE, "B was in use");
6109           MOVB (aopGet (left, offset, FALSE, FALSE));
6110           MOVA (aopGet (right, offset, FALSE, FALSE));
6111           emitcode ("cjne", "a,b,%05d$", lbl->key + 100);
6112           offset++;
6113         }
6114     }
6115 }
6116
6117 /*-----------------------------------------------------------------*/
6118 /* gencjne - compare and jump if not equal                         */
6119 /*-----------------------------------------------------------------*/
6120 static void
6121 gencjne (operand * left, operand * right, symbol * lbl, bool useCarry)
6122 {
6123   symbol *tlbl = newiTempLabel (NULL);
6124
6125   D (emitcode (";", "gencjne"));
6126
6127   gencjneshort (left, right, lbl);
6128
6129   if (useCarry)
6130       SETC;
6131   else
6132       MOVA (one);
6133   emitcode ("sjmp", "%05d$", tlbl->key + 100);
6134   emitLabel (lbl);
6135   if (useCarry)
6136       CLRC;
6137   else
6138       MOVA (zero);
6139   emitLabel (tlbl);
6140 }
6141
6142 /*-----------------------------------------------------------------*/
6143 /* genCmpEq - generates code for equal to                          */
6144 /*-----------------------------------------------------------------*/
6145 static void
6146 genCmpEq (iCode * ic, iCode * ifx)
6147 {
6148   bool swappedLR = FALSE;
6149   operand *left, *right, *result;
6150
6151   D (emitcode (";", "genCmpEq"));
6152
6153   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6154   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6155   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6156
6157   /* if literal, literal on the right or
6158      if the right is in a pointer register and left
6159      is not */
6160   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6161       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6162     {
6163       operand *t = IC_RIGHT (ic);
6164       IC_RIGHT (ic) = IC_LEFT (ic);
6165       IC_LEFT (ic) = t;
6166       swappedLR = TRUE;
6167     }
6168
6169   if (ifx && !AOP_SIZE (result))
6170     {
6171       symbol *tlbl;
6172       /* if they are both bit variables */
6173       if (AOP_TYPE (left) == AOP_CRY &&
6174           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6175         {
6176           if (AOP_TYPE (right) == AOP_LIT)
6177             {
6178               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6179               if (lit == 0L)
6180                 {
6181                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6182                   emitcode ("cpl", "c");
6183                 }
6184               else if (lit == 1L)
6185                 {
6186                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6187                 }
6188               else
6189                 {
6190                   emitcode ("clr", "c");
6191                 }
6192               /* AOP_TYPE(right) == AOP_CRY */
6193             }
6194           else
6195             {
6196               symbol *lbl = newiTempLabel (NULL);
6197               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6198               emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6199               emitcode ("cpl", "c");
6200               emitLabel (lbl);
6201             }
6202           /* if true label then we jump if condition
6203              supplied is true */
6204           tlbl = newiTempLabel (NULL);
6205           if (IC_TRUE (ifx))
6206             {
6207               emitcode ("jnc", "%05d$", tlbl->key + 100);
6208               freeForBranchAsmop (result);
6209               freeForBranchAsmop (right);
6210               freeForBranchAsmop (left);
6211               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6212             }
6213           else
6214             {
6215               emitcode ("jc", "%05d$", tlbl->key + 100);
6216               freeForBranchAsmop (result);
6217               freeForBranchAsmop (right);
6218               freeForBranchAsmop (left);
6219               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6220             }
6221           emitLabel (tlbl);
6222         }
6223       else
6224         {
6225           tlbl = newiTempLabel (NULL);
6226           gencjneshort (left, right, tlbl);
6227           if (IC_TRUE (ifx))
6228             {
6229               freeForBranchAsmop (result);
6230               freeForBranchAsmop (right);
6231               freeForBranchAsmop (left);
6232               emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
6233               emitLabel (tlbl);
6234             }
6235           else
6236             {
6237               symbol *lbl = newiTempLabel (NULL);
6238               emitcode ("sjmp", "%05d$", lbl->key + 100);
6239               emitLabel (tlbl);
6240               freeForBranchAsmop (result);
6241               freeForBranchAsmop (right);
6242               freeForBranchAsmop (left);
6243               emitcode ("ljmp", "%05d$", IC_FALSE (ifx)->key + 100);
6244               emitLabel (lbl);
6245             }
6246         }
6247       /* mark the icode as generated */
6248       ifx->generated = 1;
6249       goto release;
6250     }
6251
6252   /* if they are both bit variables */
6253   if (AOP_TYPE (left) == AOP_CRY &&
6254       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6255     {
6256       if (AOP_TYPE (right) == AOP_LIT)
6257         {
6258           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6259           if (lit == 0L)
6260             {
6261               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6262               emitcode ("cpl", "c");
6263             }
6264           else if (lit == 1L)
6265             {
6266               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6267             }
6268           else
6269             {
6270               emitcode ("clr", "c");
6271             }
6272           /* AOP_TYPE(right) == AOP_CRY */
6273         }
6274       else
6275         {
6276           symbol *lbl = newiTempLabel (NULL);
6277           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6278           emitcode ("jb", "%s,%05d$", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6279           emitcode ("cpl", "c");
6280           emitLabel (lbl);
6281         }
6282       /* c = 1 if egal */
6283       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6284         {
6285           outBitC (result);
6286           goto release;
6287         }
6288       if (ifx)
6289         {
6290           genIfxJump (ifx, "c", left, right, result);
6291           goto release;
6292         }
6293       /* if the result is used in an arithmetic operation
6294          then put the result in place */
6295       outBitC (result);
6296     }
6297   else
6298     {
6299       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6300         {
6301           gencjne (left, right, newiTempLabel (NULL), TRUE);
6302           aopPut (result, "c", 0);
6303           goto release;
6304         }
6305       gencjne (left, right, newiTempLabel (NULL), FALSE);
6306       if (ifx)
6307         {
6308           genIfxJump (ifx, "a", left, right, result);
6309           goto release;
6310         }
6311       /* if the result is used in an arithmetic operation
6312          then put the result in place */
6313       if (AOP_TYPE (result) != AOP_CRY)
6314         outAcc (result);
6315       /* leave the result in acc */
6316     }
6317
6318 release:
6319   freeAsmop (result, NULL, ic, TRUE);
6320   if (!swappedLR)
6321     {
6322       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6323       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6324     }
6325   else
6326     {
6327       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6328       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6329     }
6330 }
6331
6332 /*-----------------------------------------------------------------*/
6333 /* ifxForOp - returns the icode containing the ifx for operand     */
6334 /*-----------------------------------------------------------------*/
6335 static iCode *
6336 ifxForOp (operand * op, iCode * ic)
6337 {
6338   /* if true symbol then needs to be assigned */
6339   if (IS_TRUE_SYMOP (op))
6340     return NULL;
6341
6342   /* if this has register type condition and
6343      the next instruction is ifx with the same operand
6344      and live to of the operand is upto the ifx only then */
6345   if (ic->next &&
6346       ic->next->op == IFX &&
6347       IC_COND (ic->next)->key == op->key &&
6348       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6349     return ic->next;
6350
6351   return NULL;
6352 }
6353
6354 /*-----------------------------------------------------------------*/
6355 /* hasInc - operand is incremented before any other use            */
6356 /*-----------------------------------------------------------------*/
6357 static iCode *
6358 hasInc (operand *op, iCode *ic, int osize)
6359 {
6360   sym_link *type = operandType(op);
6361   sym_link *retype = getSpec (type);
6362   iCode *lic = ic->next;
6363   int isize ;
6364
6365   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6366   if (!IS_SYMOP(op)) return NULL;
6367
6368   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6369   if (IS_AGGREGATE(type->next)) return NULL;
6370   if (osize != (isize = getSize(type->next))) return NULL;
6371
6372   while (lic) {
6373     /* if operand of the form op = op + <sizeof *op> */
6374     if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6375         isOperandEqual(IC_RESULT(lic),op) &&
6376         isOperandLiteral(IC_RIGHT(lic)) &&
6377         operandLitValue(IC_RIGHT(lic)) == isize) {
6378       return lic;
6379     }
6380     /* if the operand used or deffed */
6381     if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6382       return NULL;
6383     }
6384     /* if GOTO or IFX */
6385     if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6386     lic = lic->next;
6387   }
6388   return NULL;
6389 }
6390
6391 /*-----------------------------------------------------------------*/
6392 /* genAndOp - for && operation                                     */
6393 /*-----------------------------------------------------------------*/
6394 static void
6395 genAndOp (iCode * ic)
6396 {
6397   operand *left, *right, *result;
6398   symbol *tlbl;
6399
6400   D (emitcode (";", "genAndOp"));
6401
6402   /* note here that && operations that are in an
6403      if statement are taken away by backPatchLabels
6404      only those used in arthmetic operations remain */
6405   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6406   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6407   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6408
6409   /* if both are bit variables */
6410   if (AOP_TYPE (left) == AOP_CRY &&
6411       AOP_TYPE (right) == AOP_CRY)
6412     {
6413       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6414       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6415       outBitC (result);
6416     }
6417   else
6418     {
6419       tlbl = newiTempLabel (NULL);
6420       toBoolean (left);
6421       emitcode ("jz", "%05d$", tlbl->key + 100);
6422       toBoolean (right);
6423       emitLabel (tlbl);
6424       outBitAcc (result);
6425     }
6426
6427   freeAsmop (result, NULL, ic, TRUE);
6428   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6429   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6430 }
6431
6432
6433 /*-----------------------------------------------------------------*/
6434 /* genOrOp - for || operation                                      */
6435 /*-----------------------------------------------------------------*/
6436 static void
6437 genOrOp (iCode * ic)
6438 {
6439   operand *left, *right, *result;
6440   symbol *tlbl;
6441
6442   D (emitcode (";", "genOrOp"));
6443
6444   /* note here that || operations that are in an
6445      if statement are taken away by backPatchLabels
6446      only those used in arthmetic operations remain */
6447   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6448   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6449   aopOp ((result = IC_RESULT (ic)), ic, FALSE);
6450
6451   /* if both are bit variables */
6452   if (AOP_TYPE (left) == AOP_CRY &&
6453       AOP_TYPE (right) == AOP_CRY)
6454     {
6455       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6456       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6457       outBitC (result);
6458     }
6459   else
6460     {
6461       tlbl = newiTempLabel (NULL);
6462       toBoolean (left);
6463       emitcode ("jnz", "%05d$", tlbl->key + 100);
6464       toBoolean (right);
6465       emitLabel (tlbl);
6466       outBitAcc (result);
6467     }
6468
6469   freeAsmop (result, NULL, ic, TRUE);
6470   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6471   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6472 }
6473
6474 /*-----------------------------------------------------------------*/
6475 /* isLiteralBit - test if lit == 2^n                               */
6476 /*-----------------------------------------------------------------*/
6477 static int
6478 isLiteralBit (unsigned long lit)
6479 {
6480   unsigned long pw[32] =
6481   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6482    0x100L, 0x200L, 0x400L, 0x800L,
6483    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6484    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6485    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6486    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6487    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6488   int idx;
6489
6490   for (idx = 0; idx < 32; idx++)
6491     if (lit == pw[idx])
6492       return idx + 1;
6493   return 0;
6494 }
6495
6496 /*-----------------------------------------------------------------*/
6497 /* continueIfTrue -                                                */
6498 /*-----------------------------------------------------------------*/
6499 static void
6500 continueIfTrue (iCode * ic)
6501 {
6502   if (IC_TRUE (ic))
6503     emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6504   ic->generated = 1;
6505 }
6506
6507 /*-----------------------------------------------------------------*/
6508 /* jmpIfTrue -                                                     */
6509 /*-----------------------------------------------------------------*/
6510 static void
6511 jumpIfTrue (iCode * ic)
6512 {
6513   if (!IC_TRUE (ic))
6514     emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6515   ic->generated = 1;
6516 }
6517
6518 /*-----------------------------------------------------------------*/
6519 /* jmpTrueOrFalse -                                                */
6520 /*-----------------------------------------------------------------*/
6521 static void
6522 jmpTrueOrFalse (iCode * ic, symbol * tlbl, operand *left, operand *right, operand *result)
6523 {
6524   // ugly but optimized by peephole
6525   if (IC_TRUE (ic))
6526     {
6527       symbol *nlbl = newiTempLabel (NULL);
6528       emitcode ("sjmp", "%05d$", nlbl->key + 100);
6529       emitLabel (tlbl);
6530       freeForBranchAsmop (result);
6531       freeForBranchAsmop (right);
6532       freeForBranchAsmop (left);
6533       emitcode ("ljmp", "%05d$", IC_TRUE (ic)->key + 100);
6534       emitLabel (nlbl);
6535     }
6536   else
6537     {
6538       freeForBranchAsmop (result);
6539       freeForBranchAsmop (right);
6540       freeForBranchAsmop (left);
6541       emitcode ("ljmp", "%05d$", IC_FALSE (ic)->key + 100);
6542       emitLabel (tlbl);
6543     }
6544   ic->generated = 1;
6545 }
6546
6547 /*-----------------------------------------------------------------*/
6548 /* genAnd  - code for and                                          */
6549 /*-----------------------------------------------------------------*/
6550 static void
6551 genAnd (iCode * ic, iCode * ifx)
6552 {
6553   operand *left, *right, *result;
6554   int size, offset = 0;
6555   unsigned long lit = 0L;
6556   int bytelit = 0;
6557   char buffer[10];
6558
6559   D (emitcode (";", "genAnd"));
6560
6561   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6562   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6563   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6564
6565 #ifdef DEBUG_TYPE
6566   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6567             AOP_TYPE (result),
6568             AOP_TYPE (left), AOP_TYPE (right));
6569   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
6570             AOP_SIZE (result),
6571             AOP_SIZE (left), AOP_SIZE (right));
6572 #endif
6573
6574   /* if left is a literal & right is not then exchange them */
6575   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
6576       AOP_NEEDSACC (left))
6577     {
6578       operand *tmp = right;
6579       right = left;
6580       left = tmp;
6581     }
6582
6583   /* if result = right then exchange left and right */
6584   if (sameRegs (AOP (result), AOP (right)))
6585     {
6586       operand *tmp = right;
6587       right = left;
6588       left = tmp;
6589     }
6590
6591   /* if right is bit then exchange them */
6592   if (AOP_TYPE (right) == AOP_CRY &&
6593       AOP_TYPE (left) != AOP_CRY)
6594     {
6595       operand *tmp = right;
6596       right = left;
6597       left = tmp;
6598     }
6599   if (AOP_TYPE (right) == AOP_LIT)
6600     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6601
6602   size = AOP_SIZE (result);
6603
6604   // if(bit & yy)
6605   // result = bit & yy;
6606   if (AOP_TYPE (left) == AOP_CRY)
6607     {
6608       // c = bit & literal;
6609       if (AOP_TYPE (right) == AOP_LIT)
6610         {
6611           if (lit & 1)
6612             {
6613               if (size && sameRegs (AOP (result), AOP (left)))
6614                 // no change
6615                 goto release;
6616               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6617             }
6618           else
6619             {
6620               // bit(result) = 0;
6621               if (size && (AOP_TYPE (result) == AOP_CRY))
6622                 {
6623                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6624                   goto release;
6625                 }
6626               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6627                 {
6628                   jumpIfTrue (ifx);
6629                   goto release;
6630                 }
6631               emitcode ("clr", "c");
6632             }
6633         }
6634       else
6635         {
6636           if (AOP_TYPE (right) == AOP_CRY)
6637             {
6638               // c = bit & bit;
6639               if (IS_OP_ACCUSE (left))
6640                 {
6641                   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6642                 }
6643               else
6644                 {
6645                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6646                   emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6647                 }
6648             }
6649           else
6650             {
6651               // c = bit & val;
6652               MOVA (aopGet (right, 0, FALSE, FALSE));
6653               // c = lsb
6654               emitcode ("rrc", "a");
6655               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6656             }
6657         }
6658       // bit = c
6659       // val = c
6660       if (size)
6661         outBitC (result);
6662       // if(bit & ...)
6663       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6664         genIfxJump (ifx, "c", left, right, result);
6665       goto release;
6666     }
6667
6668   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6669   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6670   if ((AOP_TYPE (right) == AOP_LIT) &&
6671       (AOP_TYPE (result) == AOP_CRY) &&
6672       (AOP_TYPE (left) != AOP_CRY))
6673     {
6674       int posbit = isLiteralBit (lit);
6675       /* left &  2^n */
6676       if (posbit)
6677         {
6678           posbit--;
6679           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE));
6680           // bit = left & 2^n
6681           if (size)
6682             {
6683               switch (posbit & 0x07)
6684                 {
6685                   case 0: emitcode ("rrc", "a");
6686                           break;
6687                   case 7: emitcode ("rlc", "a");
6688                           break;
6689                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
6690                           break;
6691                 }
6692             }
6693           // if(left &  2^n)
6694           else
6695             {
6696               if (ifx)
6697                 {
6698                   SNPRINTF (buffer, sizeof(buffer),
6699                             "acc.%d", posbit & 0x07);
6700                   genIfxJump (ifx, buffer, left, right, result);
6701                 }
6702               else
6703                 {// what is this case? just found it in ds390/gen.c
6704                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6705                 }
6706               goto release;
6707             }
6708         }
6709       else
6710         {
6711           symbol *tlbl = newiTempLabel (NULL);
6712           int sizel = AOP_SIZE (left);
6713           if (size)
6714             emitcode ("setb", "c");
6715           while (sizel--)
6716             {
6717               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6718                 {
6719                   MOVA (aopGet (left, offset, FALSE, FALSE));
6720                   // byte ==  2^n ?
6721                   if ((posbit = isLiteralBit (bytelit)) != 0)
6722                     emitcode ("jb", "acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
6723                   else
6724                     {
6725                       if (bytelit != 0x0FFL)
6726                         emitcode ("anl", "a,%s",
6727                                   aopGet (right, offset, FALSE, TRUE));
6728                       emitcode ("jnz", "%05d$", tlbl->key + 100);
6729                     }
6730                 }
6731               offset++;
6732             }
6733           // bit = left & literal
6734           if (size)
6735             {
6736               emitcode ("clr", "c");
6737               emitLabel (tlbl);
6738             }
6739           // if(left & literal)
6740           else
6741             {
6742               if (ifx)
6743                 jmpTrueOrFalse (ifx, tlbl, left, right, result);
6744               else
6745                 emitLabel (tlbl);
6746               goto release;
6747             }
6748         }
6749       outBitC (result);
6750       goto release;
6751     }
6752
6753   /* if left is same as result */
6754   if (sameRegs (AOP (result), AOP (left)))
6755     {
6756       for (; size--; offset++)
6757         {
6758           if (AOP_TYPE (right) == AOP_LIT)
6759             {
6760               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6761               if (bytelit == 0x0FF)
6762                 {
6763                   /* dummy read of volatile operand */
6764                   if (isOperandVolatile (left, FALSE))
6765                     MOVA (aopGet (left, offset, FALSE, FALSE));
6766                   else
6767                     continue;
6768                 }
6769               else if (bytelit == 0)
6770                 {
6771                   aopPut (result, zero, offset);
6772                 }
6773               else if (IS_AOP_PREG (result))
6774                 {
6775                   MOVA (aopGet (left, offset, FALSE, TRUE));
6776                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6777                   aopPut (result, "a", offset);
6778                 }
6779               else
6780                 emitcode ("anl", "%s,%s",
6781                           aopGet (left, offset, FALSE, TRUE),
6782                           aopGet (right, offset, FALSE, FALSE));
6783             }
6784           else
6785             {
6786               if (AOP_TYPE (left) == AOP_ACC)
6787                 {
6788                   if (offset)
6789                     emitcode("mov", "a,b");
6790                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6791                 }
6792               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6793                 {
6794                   MOVB (aopGet (left, offset, FALSE, FALSE));
6795                   MOVA (aopGet (right, offset, FALSE, FALSE));
6796                   emitcode ("anl", "a,b");
6797                   aopPut (result, "a", offset);
6798                 }
6799               else if (aopGetUsesAcc (left, offset))
6800                 {
6801                   MOVA (aopGet (left, offset, FALSE, FALSE));
6802                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6803                   aopPut (result, "a", offset);
6804                 }
6805               else
6806                 {
6807                   MOVA (aopGet (right, offset, FALSE, FALSE));
6808                   if (IS_AOP_PREG (result))
6809                     {
6810                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE));
6811                       aopPut (result, "a", offset);
6812                     }
6813                   else
6814                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE));
6815                 }
6816             }
6817         }
6818     }
6819   else
6820     {
6821       // left & result in different registers
6822       if (AOP_TYPE (result) == AOP_CRY)
6823         {
6824           // result = bit
6825           // if(size), result in bit
6826           // if(!size && ifx), conditional oper: if(left & right)
6827           symbol *tlbl = newiTempLabel (NULL);
6828           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6829           if (size)
6830             emitcode ("setb", "c");
6831           while (sizer--)
6832             {
6833               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6834                   && AOP_TYPE(left)==AOP_ACC)
6835                 {
6836                   if (offset)
6837                     emitcode("mov", "a,b");
6838                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6839                 }
6840               else if (AOP_TYPE(left)==AOP_ACC)
6841                 {
6842                   if (!offset)
6843                     {
6844                       bool pushedB = pushB ();
6845                       emitcode("mov", "b,a");
6846                       MOVA (aopGet (right, offset, FALSE, FALSE));
6847                       emitcode("anl", "a,b");
6848                       popB (pushedB);
6849                     }
6850                   else
6851                     {
6852                       MOVA (aopGet (right, offset, FALSE, FALSE));
6853                       emitcode("anl", "a,b");
6854                     }
6855                 }
6856               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6857                 {
6858                   MOVB (aopGet (left, offset, FALSE, FALSE));
6859                   MOVA (aopGet (right, offset, FALSE, FALSE));
6860                   emitcode ("anl", "a,b");
6861                 }
6862               else if (aopGetUsesAcc (left, offset))
6863                 {
6864                   MOVA (aopGet (left, offset, FALSE, FALSE));
6865                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6866                     }
6867               else
6868                 {
6869                   MOVA (aopGet (right, offset, FALSE, FALSE));
6870                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6871                 }
6872
6873               emitcode ("jnz", "%05d$", tlbl->key + 100);
6874               offset++;
6875             }
6876           if (size)
6877             {
6878               CLRC;
6879               emitLabel (tlbl);
6880               outBitC (result);
6881             }
6882           else if (ifx)
6883             jmpTrueOrFalse (ifx, tlbl, left, right, result);
6884           else
6885             emitLabel (tlbl);
6886         }
6887       else
6888         {
6889           for (; (size--); offset++)
6890             {
6891               // normal case
6892               // result = left & right
6893               if (AOP_TYPE (right) == AOP_LIT)
6894                 {
6895                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6896                   if (bytelit == 0x0FF)
6897                     {
6898                       aopPut (result,
6899                               aopGet (left, offset, FALSE, FALSE),
6900                               offset);
6901                       continue;
6902                     }
6903                   else if (bytelit == 0)
6904                     {
6905                       /* dummy read of volatile operand */
6906                       if (isOperandVolatile (left, FALSE))
6907                         MOVA (aopGet (left, offset, FALSE, FALSE));
6908                       aopPut (result, zero, offset);
6909                       continue;
6910                     }
6911                   else if (AOP_TYPE (left) == AOP_ACC)
6912                     {
6913                       if (!offset)
6914                         {
6915                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6916                           aopPut (result, "a", offset);
6917                           continue;
6918                         }
6919                       else
6920                         {
6921                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE));
6922                           aopPut (result, "b", offset);
6923                           continue;
6924                         }
6925                     }
6926                 }
6927               // faster than result <- left, anl result,right
6928               // and better if result is SFR
6929               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
6930                   && AOP_TYPE(left)==AOP_ACC)
6931                 {
6932                   if (offset)
6933                     emitcode("mov", "a,b");
6934                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6935                 }
6936               else if (AOP_TYPE(left)==AOP_ACC)
6937                 {
6938                   if (!offset)
6939                     {
6940                       bool pushedB = pushB ();
6941                       emitcode("mov", "b,a");
6942                       MOVA (aopGet (right, offset, FALSE, FALSE));
6943                       emitcode("anl", "a,b");
6944                       popB (pushedB);
6945                     }
6946                   else
6947                     {
6948                       MOVA (aopGet (right, offset, FALSE, FALSE));
6949                       emitcode("anl", "a,b");
6950                     }
6951                 }
6952               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
6953                 {
6954                   MOVB (aopGet (left, offset, FALSE, FALSE));
6955                   MOVA (aopGet (right, offset, FALSE, FALSE));
6956                   emitcode ("anl", "a,b");
6957                 }
6958               else if (aopGetUsesAcc (left, offset))
6959                 {
6960                   MOVA (aopGet (left, offset, FALSE, FALSE));
6961                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE));
6962                 }
6963               else
6964                 {
6965                   MOVA (aopGet (right, offset, FALSE, FALSE));
6966                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE));
6967                 }
6968               aopPut (result, "a", offset);
6969             }
6970         }
6971     }
6972
6973 release:
6974   freeAsmop (result, NULL, ic, TRUE);
6975   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6976   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6977 }
6978
6979 /*-----------------------------------------------------------------*/
6980 /* genOr  - code for or                                            */
6981 /*-----------------------------------------------------------------*/
6982 static void
6983 genOr (iCode * ic, iCode * ifx)
6984 {
6985   operand *left, *right, *result;
6986   int size, offset = 0;
6987   unsigned long lit = 0L;
6988   int bytelit = 0;
6989
6990   D (emitcode (";", "genOr"));
6991
6992   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
6993   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
6994   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
6995
6996 #ifdef DEBUG_TYPE
6997   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
6998             AOP_TYPE (result),
6999             AOP_TYPE (left), AOP_TYPE (right));
7000   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7001             AOP_SIZE (result),
7002             AOP_SIZE (left), AOP_SIZE (right));
7003 #endif
7004
7005   /* if left is a literal & right is not then exchange them */
7006   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7007       AOP_NEEDSACC (left))
7008     {
7009       operand *tmp = right;
7010       right = left;
7011       left = tmp;
7012     }
7013
7014   /* if result = right then exchange them */
7015   if (sameRegs (AOP (result), AOP (right)))
7016     {
7017       operand *tmp = right;
7018       right = left;
7019       left = tmp;
7020     }
7021
7022   /* if right is bit then exchange them */
7023   if (AOP_TYPE (right) == AOP_CRY &&
7024       AOP_TYPE (left) != AOP_CRY)
7025     {
7026       operand *tmp = right;
7027       right = left;
7028       left = tmp;
7029     }
7030   if (AOP_TYPE (right) == AOP_LIT)
7031     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7032
7033   size = AOP_SIZE (result);
7034
7035   // if(bit | yy)
7036   // xx = bit | yy;
7037   if (AOP_TYPE (left) == AOP_CRY)
7038     {
7039       if (AOP_TYPE (right) == AOP_LIT)
7040         {
7041           // c = bit | literal;
7042           if (lit)
7043             {
7044               // lit != 0 => result = 1
7045               if (AOP_TYPE (result) == AOP_CRY)
7046                 {
7047                   if (size)
7048                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7049                   else if (ifx)
7050                     continueIfTrue (ifx);
7051                   goto release;
7052                 }
7053               emitcode ("setb", "c");
7054             }
7055           else
7056             {
7057               // lit == 0 => result = left
7058               if (size && sameRegs (AOP (result), AOP (left)))
7059                 goto release;
7060               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7061             }
7062         }
7063       else
7064         {
7065           if (AOP_TYPE (right) == AOP_CRY)
7066             {
7067               // c = bit | bit;
7068               if (IS_OP_ACCUSE (left))
7069                 {
7070                   emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7071                 }
7072               else
7073                 {
7074                   emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7075                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7076                 }
7077             }
7078           else
7079             {
7080               // c = bit | val;
7081               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7082                 {
7083                   symbol *tlbl = newiTempLabel (NULL);
7084                   emitcode ("jb", "%s,%05d$",
7085                             AOP (left)->aopu.aop_dir, tlbl->key + 100);
7086                   toBoolean (right);
7087                   emitcode ("jnz", "%05d$", tlbl->key + 100);
7088                   jmpTrueOrFalse (ifx, tlbl, left, right, result);
7089                   goto release;
7090                 }
7091               else
7092                 {
7093                   toCarry (right);
7094                   emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7095                 }
7096             }
7097         }
7098       // bit = c
7099       // val = c
7100       if (size)
7101         outBitC (result);
7102       // if(bit | ...)
7103       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7104         genIfxJump (ifx, "c", left, right, result);
7105       goto release;
7106     }
7107
7108   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7109   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7110   if ((AOP_TYPE (right) == AOP_LIT) &&
7111       (AOP_TYPE (result) == AOP_CRY) &&
7112       (AOP_TYPE (left) != AOP_CRY))
7113     {
7114       if (lit)
7115         {
7116           // result = 1
7117           if (size)
7118             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7119           else
7120             continueIfTrue (ifx);
7121           goto release;
7122         }
7123       else
7124         {
7125           // lit = 0, result = boolean(left)
7126           if (size)
7127             emitcode ("setb", "c");
7128           toBoolean (right);
7129           if (size)
7130             {
7131               symbol *tlbl = newiTempLabel (NULL);
7132               emitcode ("jnz", "%05d$", tlbl->key + 100);
7133               CLRC;
7134               emitLabel (tlbl);
7135             }
7136           else
7137             {
7138               genIfxJump (ifx, "a", left, right, result);
7139               goto release;
7140             }
7141         }
7142       outBitC (result);
7143       goto release;
7144     }
7145
7146   /* if left is same as result */
7147   if (sameRegs (AOP (result), AOP (left)))
7148     {
7149       for (; size--; offset++)
7150         {
7151           if (AOP_TYPE (right) == AOP_LIT)
7152             {
7153               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7154               if (bytelit == 0)
7155                 {
7156                   /* dummy read of volatile operand */
7157                   if (isOperandVolatile (left, FALSE))
7158                     MOVA (aopGet (left, offset, FALSE, FALSE));
7159                   else
7160                     continue;
7161                 }
7162               else if (bytelit == 0x0FF)
7163                 {
7164                   aopPut (result, "#0xFF", offset);
7165                 }
7166               else if (IS_AOP_PREG (left))
7167                 {
7168                   MOVA (aopGet (left, offset, FALSE, TRUE));
7169                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7170                   aopPut (result, "a", offset);
7171                 }
7172               else
7173                 {
7174                   emitcode ("orl", "%s,%s",
7175                             aopGet (left, offset, FALSE, TRUE),
7176                             aopGet (right, offset, FALSE, FALSE));
7177                 }
7178             }
7179           else
7180             {
7181               if (AOP_TYPE (left) == AOP_ACC)
7182                 {
7183                   if (offset)
7184                     emitcode("mov", "a,b");
7185                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7186                 }
7187               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7188                 {
7189                   MOVB (aopGet (left, offset, FALSE, FALSE));
7190                   MOVA (aopGet (right, offset, FALSE, FALSE));
7191                   emitcode ("orl", "a,b");
7192                   aopPut (result, "a", offset);
7193                 }
7194               else if (aopGetUsesAcc (left, offset))
7195                 {
7196                   MOVA (aopGet (left, offset, FALSE, FALSE));
7197                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7198                   aopPut (result, "a", offset);
7199                 }
7200               else
7201                 {
7202                   MOVA (aopGet (right, offset, FALSE, FALSE));
7203                   if (IS_AOP_PREG (left))
7204                     {
7205                       emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7206                       aopPut (result, "a", offset);
7207                     }
7208                   else
7209                     {
7210                       emitcode ("orl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7211                     }
7212                 }
7213             }
7214         }
7215     }
7216   else
7217     {
7218       // left & result in different registers
7219       if (AOP_TYPE (result) == AOP_CRY)
7220         {
7221           // result = bit
7222           // if(size), result in bit
7223           // if(!size && ifx), conditional oper: if(left | right)
7224           symbol *tlbl = newiTempLabel (NULL);
7225           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7226           if (size)
7227             emitcode ("setb", "c");
7228           while (sizer--)
7229             {
7230               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7231                   && AOP_TYPE(left)==AOP_ACC)
7232                 {
7233                   if (offset)
7234                     emitcode("mov", "a,b");
7235                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7236                 }
7237               else if (AOP_TYPE(left)==AOP_ACC)
7238                 {
7239                   if (!offset)
7240                     {
7241                       bool pushedB = pushB ();
7242                       emitcode("mov", "b,a");
7243                       MOVA (aopGet (right, offset, FALSE, FALSE));
7244                       emitcode("orl", "a,b");
7245                       popB (pushedB);
7246                     }
7247                   else
7248                     {
7249                       MOVA (aopGet (right, offset, FALSE, FALSE));
7250                       emitcode("orl", "a,b");
7251                     }
7252                 }
7253               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7254                 {
7255                   MOVB (aopGet (left, offset, FALSE, FALSE));
7256                   MOVA (aopGet (right, offset, FALSE, FALSE));
7257                   emitcode ("orl", "a,b");
7258                 }
7259               else if (aopGetUsesAcc (left, offset))
7260                 {
7261                   MOVA (aopGet (left, offset, FALSE, FALSE));
7262                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7263                 }
7264               else
7265                 {
7266                   MOVA (aopGet (right, offset, FALSE, FALSE));
7267                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7268               }
7269
7270               emitcode ("jnz", "%05d$", tlbl->key + 100);
7271               offset++;
7272             }
7273           if (size)
7274             {
7275               CLRC;
7276               emitLabel (tlbl);
7277               outBitC (result);
7278             }
7279           else if (ifx)
7280             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7281           else
7282             emitLabel (tlbl);
7283         }
7284       else
7285         {
7286           for (; (size--); offset++)
7287             {
7288               // normal case
7289               // result = left | right
7290               if (AOP_TYPE (right) == AOP_LIT)
7291                 {
7292                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7293                   if (bytelit == 0)
7294                     {
7295                       aopPut (result,
7296                               aopGet (left, offset, FALSE, FALSE),
7297                               offset);
7298                       continue;
7299                     }
7300                   else if (bytelit == 0x0FF)
7301                     {
7302                       /* dummy read of volatile operand */
7303                       if (isOperandVolatile (left, FALSE))
7304                         MOVA (aopGet (left, offset, FALSE, FALSE));
7305                       aopPut (result, "#0xFF", offset);
7306                       continue;
7307                     }
7308                 }
7309               // faster than result <- left, orl result,right
7310               // and better if result is SFR
7311               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7312                   && AOP_TYPE(left)==AOP_ACC)
7313                 {
7314                   if (offset)
7315                     emitcode("mov", "a,b");
7316                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7317                 }
7318               else if (AOP_TYPE(left)==AOP_ACC)
7319                 {
7320                   if (!offset)
7321                     {
7322                       bool pushedB = pushB ();
7323                       emitcode("mov", "b,a");
7324                       MOVA (aopGet (right, offset, FALSE, FALSE));
7325                       emitcode("orl", "a,b");
7326                       popB (pushedB);
7327                     }
7328                   else
7329                     {
7330                       MOVA (aopGet (right, offset, FALSE, FALSE));
7331                       emitcode("orl", "a,b");
7332                     }
7333                 }
7334               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7335                 {
7336                   MOVB (aopGet (left, offset, FALSE, FALSE));
7337                   MOVA (aopGet (right, offset, FALSE, FALSE));
7338                   emitcode ("orl", "a,b");
7339                 }
7340               else if (aopGetUsesAcc (left, offset))
7341                 {
7342                   MOVA (aopGet (left, offset, FALSE, FALSE));
7343                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7344                 }
7345               else
7346                 {
7347                   MOVA (aopGet (right, offset, FALSE, FALSE));
7348                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE));
7349                 }
7350               aopPut (result, "a", offset);
7351             }
7352         }
7353     }
7354
7355 release:
7356   freeAsmop (result, NULL, ic, TRUE);
7357   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7358   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7359 }
7360
7361 /*-----------------------------------------------------------------*/
7362 /* genXor - code for xclusive or                                   */
7363 /*-----------------------------------------------------------------*/
7364 static void
7365 genXor (iCode * ic, iCode * ifx)
7366 {
7367   operand *left, *right, *result;
7368   int size, offset = 0;
7369   unsigned long lit = 0L;
7370   int bytelit = 0;
7371
7372   D (emitcode (";", "genXor"));
7373
7374   aopOp ((left = IC_LEFT (ic)), ic, FALSE);
7375   aopOp ((right = IC_RIGHT (ic)), ic, FALSE);
7376   aopOp ((result = IC_RESULT (ic)), ic, TRUE);
7377
7378 #ifdef DEBUG_TYPE
7379   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7380             AOP_TYPE (result),
7381             AOP_TYPE (left), AOP_TYPE (right));
7382   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7383             AOP_SIZE (result),
7384             AOP_SIZE (left), AOP_SIZE (right));
7385 #endif
7386
7387   /* if left is a literal & right is not ||
7388      if left needs acc & right does not */
7389   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
7390       (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right)))
7391     {
7392       operand *tmp = right;
7393       right = left;
7394       left = tmp;
7395     }
7396
7397   /* if result = right then exchange them */
7398   if (sameRegs (AOP (result), AOP (right)))
7399     {
7400       operand *tmp = right;
7401       right = left;
7402       left = tmp;
7403     }
7404
7405   /* if right is bit then exchange them */
7406   if (AOP_TYPE (right) == AOP_CRY &&
7407       AOP_TYPE (left) != AOP_CRY)
7408     {
7409       operand *tmp = right;
7410       right = left;
7411       left = tmp;
7412     }
7413
7414   if (AOP_TYPE (right) == AOP_LIT)
7415     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7416
7417   size = AOP_SIZE (result);
7418
7419   // if(bit ^ yy)
7420   // xx = bit ^ yy;
7421   if (AOP_TYPE (left) == AOP_CRY)
7422     {
7423       if (AOP_TYPE (right) == AOP_LIT)
7424         {
7425           // c = bit & literal;
7426           if (lit >> 1)
7427             {
7428               // lit>>1  != 0 => result = 1
7429               if (AOP_TYPE (result) == AOP_CRY)
7430                 {
7431                   if (size)
7432                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7433                   else if (ifx)
7434                     continueIfTrue (ifx);
7435                   goto release;
7436                 }
7437               emitcode ("setb", "c");
7438             }
7439           else
7440             {
7441               // lit == (0 or 1)
7442               if (lit == 0)
7443                 {
7444                   // lit == 0, result = left
7445                   if (size && sameRegs (AOP (result), AOP (left)))
7446                     goto release;
7447                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7448                 }
7449               else
7450                 {
7451                   // lit == 1, result = not(left)
7452                   if (size && sameRegs (AOP (result), AOP (left)))
7453                     {
7454                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7455                       goto release;
7456                     }
7457                   else
7458                     {
7459                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7460                       emitcode ("cpl", "c");
7461                     }
7462                 }
7463             }
7464         }
7465       else
7466         {
7467           // right != literal
7468           symbol *tlbl = newiTempLabel (NULL);
7469           if (AOP_TYPE (right) == AOP_CRY)
7470             {
7471               // c = bit ^ bit;
7472               if (IS_OP_ACCUSE (left))
7473                 {// left already is in the carry
7474                   operand *tmp = right;
7475                   right = left;
7476                   left = tmp;
7477                 }
7478               else
7479                 {
7480                   toCarry (right);
7481                 }
7482             }
7483           else
7484             {
7485               // c = bit ^ val
7486               toCarry (right);
7487             }
7488           emitcode ("jnb", "%s,%05d$", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7489           emitcode ("cpl", "c");
7490           emitLabel (tlbl);
7491         }
7492       // bit = c
7493       // val = c
7494       if (size)
7495         outBitC (result);
7496       // if(bit ^ ...)
7497       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7498         genIfxJump (ifx, "c", left, right, result);
7499       goto release;
7500     }
7501
7502   /* if left is same as result */
7503   if (sameRegs (AOP (result), AOP (left)))
7504     {
7505       for (; size--; offset++)
7506         {
7507           if (AOP_TYPE (right) == AOP_LIT)
7508             {
7509               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7510               if (bytelit == 0)
7511                 {
7512                   /* dummy read of volatile operand */
7513                   if (isOperandVolatile (left, FALSE))
7514                     MOVA (aopGet (left, offset, FALSE, FALSE));
7515                   else
7516                     continue;
7517                 }
7518               else if (IS_AOP_PREG (left))
7519                 {
7520                   MOVA (aopGet (left, offset, FALSE, TRUE));
7521                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7522                   aopPut (result, "a", offset);
7523                 }
7524               else
7525                 {
7526                   emitcode ("xrl", "%s,%s",
7527                             aopGet (left, offset, FALSE, TRUE),
7528                             aopGet (right, offset, FALSE, FALSE));
7529                 }
7530             }
7531           else
7532             {
7533               if (AOP_TYPE (left) == AOP_ACC)
7534                 {
7535                   if (offset)
7536                     emitcode("mov", "a,b");
7537                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7538                 }
7539               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7540                 {
7541                   MOVB (aopGet (left, offset, FALSE, FALSE));
7542                   MOVA (aopGet (right, offset, FALSE, FALSE));
7543                   emitcode ("xrl", "a,b");
7544                   aopPut (result, "a", offset);
7545                 }
7546               else if (aopGetUsesAcc (left, offset))
7547                 {
7548                   MOVA (aopGet (left, offset, FALSE, FALSE));
7549                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7550                   aopPut (result, "a", offset);
7551                 }
7552               else
7553                 {
7554                   MOVA (aopGet (right, offset, FALSE, FALSE));
7555                   if (IS_AOP_PREG (left))
7556                     {
7557                       emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7558                       aopPut (result, "a", offset);
7559                     }
7560                   else
7561                     emitcode ("xrl", "%s,a", aopGet (left, offset, FALSE, TRUE));
7562                 }
7563             }
7564         }
7565     }
7566   else
7567     {
7568       // left & result in different registers
7569       if (AOP_TYPE (result) == AOP_CRY)
7570         {
7571           // result = bit
7572           // if(size), result in bit
7573           // if(!size && ifx), conditional oper: if(left ^ right)
7574           symbol *tlbl = newiTempLabel (NULL);
7575           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7576
7577           if (size)
7578             emitcode ("setb", "c");
7579           while (sizer--)
7580             {
7581               if ((AOP_TYPE (right) == AOP_LIT) &&
7582                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7583                 {
7584                   MOVA (aopGet (left, offset, FALSE, FALSE));
7585                 }
7586               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7587                   && AOP_TYPE(left)==AOP_ACC)
7588                 {
7589                   if (offset)
7590                     emitcode("mov", "a,b");
7591                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7592                 }
7593               else if (AOP_TYPE(left)==AOP_ACC)
7594                 {
7595                   if (!offset)
7596                     {
7597                       bool pushedB = pushB ();
7598                       emitcode("mov", "b,a");
7599                       MOVA (aopGet (right, offset, FALSE, FALSE));
7600                       emitcode("xrl", "a,b");
7601                       popB (pushedB);
7602                     }
7603                   else
7604                     {
7605                       MOVA (aopGet (right, offset, FALSE, FALSE));
7606                       emitcode("xrl", "a,b");
7607                     }
7608                 }
7609               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7610                 {
7611                   MOVB (aopGet (left, offset, FALSE, FALSE));
7612                   MOVA (aopGet (right, offset, FALSE, FALSE));
7613                   emitcode ("xrl", "a,b");
7614                 }
7615               else if (aopGetUsesAcc (left, offset))
7616                 {
7617                   MOVA (aopGet (left, offset, FALSE, FALSE));
7618                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7619                 }
7620               else
7621                 {
7622                   MOVA (aopGet (right, offset, FALSE, FALSE));
7623                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7624                 }
7625
7626               emitcode ("jnz", "%05d$", tlbl->key + 100);
7627               offset++;
7628             }
7629           if (size)
7630             {
7631               CLRC;
7632               emitLabel (tlbl);
7633               outBitC (result);
7634             }
7635           else if (ifx)
7636             jmpTrueOrFalse (ifx, tlbl, left, right, result);
7637         }
7638       else
7639         {
7640           for (; (size--); offset++)
7641             {
7642               // normal case
7643               // result = left ^ right
7644               if (AOP_TYPE (right) == AOP_LIT)
7645                 {
7646                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7647                   if (bytelit == 0)
7648                     {
7649                       aopPut (result,
7650                               aopGet (left, offset, FALSE, FALSE),
7651                               offset);
7652                       continue;
7653                     }
7654                 }
7655               // faster than result <- left, xrl result,right
7656               // and better if result is SFR
7657               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7658                   && AOP_TYPE(left)==AOP_ACC)
7659                 {
7660                   if (offset)
7661                     emitcode("mov", "a,b");
7662                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7663                 }
7664               else if (AOP_TYPE(left)==AOP_ACC)
7665                 {
7666                   if (!offset)
7667                     {
7668                       bool pushedB = pushB ();
7669                       emitcode("mov", "b,a");
7670                       MOVA (aopGet (right, offset, FALSE, FALSE));
7671                       emitcode("xrl", "a,b");
7672                       popB (pushedB);
7673                     }
7674                   else
7675                     {
7676                       MOVA (aopGet (right, offset, FALSE, FALSE));
7677                       emitcode("xrl", "a,b");
7678                     }
7679                 }
7680               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7681                 {
7682                   MOVB (aopGet (left, offset, FALSE, FALSE));
7683                   MOVA (aopGet (right, offset, FALSE, FALSE));
7684                   emitcode ("xrl", "a,b");
7685                 }
7686               else if (aopGetUsesAcc (left, offset))
7687                 {
7688                   MOVA (aopGet (left, offset, FALSE, FALSE));
7689                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE));
7690                 }
7691               else
7692                 {
7693                   MOVA (aopGet (right, offset, FALSE, FALSE));
7694                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE));
7695                 }
7696               aopPut (result, "a", offset);
7697             }
7698         }
7699     }
7700
7701 release:
7702   freeAsmop (result, NULL, ic, TRUE);
7703   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7704   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7705 }
7706
7707 /*-----------------------------------------------------------------*/
7708 /* genInline - write the inline code out                           */
7709 /*-----------------------------------------------------------------*/
7710 static void
7711 genInline (iCode * ic)
7712 {
7713   char *buffer, *bp, *bp1;
7714   bool inComment = FALSE;
7715
7716   D (emitcode (";", "genInline"));
7717
7718   _G.inLine += (!options.asmpeep);
7719
7720   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
7721
7722   /* emit each line as a code */
7723   while (*bp)
7724     {
7725       switch (*bp)
7726         {
7727         case ';':
7728           inComment = TRUE;
7729           ++bp;
7730           break;
7731
7732         case '\n':
7733           inComment = FALSE;
7734           *bp++ = '\0';
7735           emitcode (bp1, "");
7736           bp1 = bp;
7737           break;
7738
7739         default:
7740           /* Add \n for labels, not dirs such as c:\mydir */
7741           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
7742             {
7743               ++bp;
7744               *bp = '\0';
7745               ++bp;
7746               emitcode (bp1, "");
7747               bp1 = bp;
7748             }
7749           else
7750             ++bp;
7751           break;
7752         }
7753     }
7754   if (bp1 != bp)
7755     emitcode (bp1, "");
7756
7757   Safe_free (buffer);
7758
7759   _G.inLine -= (!options.asmpeep);
7760 }
7761
7762 /*-----------------------------------------------------------------*/
7763 /* genRRC - rotate right with carry                                */
7764 /*-----------------------------------------------------------------*/
7765 static void
7766 genRRC (iCode * ic)
7767 {
7768   operand *left, *result;
7769   int size, offset;
7770   char *l;
7771
7772   D (emitcode (";", "genRRC"));
7773
7774   /* rotate right with carry */
7775   left = IC_LEFT (ic);
7776   result = IC_RESULT (ic);
7777   aopOp (left, ic, FALSE);
7778   aopOp (result, ic, FALSE);
7779
7780   /* move it to the result */
7781   size = AOP_SIZE (result);
7782   offset = size - 1;
7783   if (size == 1) { /* special case for 1 byte */
7784       l = aopGet (left, offset, FALSE, FALSE);
7785       MOVA (l);
7786       emitcode ("rr", "a");
7787       goto release;
7788   }
7789   /* no need to clear carry, bit7 will be written later */
7790   while (size--)
7791     {
7792       l = aopGet (left, offset, FALSE, FALSE);
7793       MOVA (l);
7794       emitcode ("rrc", "a");
7795       if (AOP_SIZE (result) > 1)
7796         aopPut (result, "a", offset--);
7797     }
7798   /* now we need to put the carry into the
7799      highest order byte of the result */
7800   if (AOP_SIZE (result) > 1)
7801     {
7802       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE);
7803       MOVA (l);
7804     }
7805   emitcode ("mov", "acc.7,c");
7806  release:
7807   aopPut (result, "a", AOP_SIZE (result) - 1);
7808   freeAsmop (result, NULL, ic, TRUE);
7809   freeAsmop (left, NULL, ic, TRUE);
7810 }
7811
7812 /*-----------------------------------------------------------------*/
7813 /* genRLC - generate code for rotate left with carry               */
7814 /*-----------------------------------------------------------------*/
7815 static void
7816 genRLC (iCode * ic)
7817 {
7818   operand *left, *result;
7819   int size, offset;
7820   char *l;
7821
7822   D (emitcode (";", "genRLC"));
7823
7824   /* rotate right with carry */
7825   left = IC_LEFT (ic);
7826   result = IC_RESULT (ic);
7827   aopOp (left, ic, FALSE);
7828   aopOp (result, ic, FALSE);
7829
7830   /* move it to the result */
7831   size = AOP_SIZE (result);
7832   offset = 0;
7833   if (size--)
7834     {
7835       l = aopGet (left, offset, FALSE, FALSE);
7836       MOVA (l);
7837       if (size == 0) { /* special case for 1 byte */
7838               emitcode("rl","a");
7839               goto release;
7840       }
7841       emitcode("rlc","a"); /* bit0 will be written later */
7842       if (AOP_SIZE (result) > 1)
7843         {
7844           aopPut (result, "a", offset++);
7845         }
7846
7847       while (size--)
7848         {
7849           l = aopGet (left, offset, FALSE, FALSE);
7850           MOVA (l);
7851           emitcode ("rlc", "a");
7852           if (AOP_SIZE (result) > 1)
7853             aopPut (result, "a", offset++);
7854         }
7855     }
7856   /* now we need to put the carry into the
7857      highest order byte of the result */
7858   if (AOP_SIZE (result) > 1)
7859     {
7860       l = aopGet (result, 0, FALSE, FALSE);
7861       MOVA (l);
7862     }
7863   emitcode ("mov", "acc.0,c");
7864  release:
7865   aopPut (result, "a", 0);
7866   freeAsmop (result, NULL, ic, TRUE);
7867   freeAsmop (left, NULL, ic, TRUE);
7868 }
7869
7870 /*-----------------------------------------------------------------*/
7871 /* genGetHbit - generates code get highest order bit               */
7872 /*-----------------------------------------------------------------*/
7873 static void
7874 genGetHbit (iCode * ic)
7875 {
7876   operand *left, *result;
7877
7878   D (emitcode (";", "genGetHbit"));
7879
7880   left = IC_LEFT (ic);
7881   result = IC_RESULT (ic);
7882   aopOp (left, ic, FALSE);
7883   aopOp (result, ic, FALSE);
7884
7885   /* get the highest order byte into a */
7886   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE));
7887   if (AOP_TYPE (result) == AOP_CRY)
7888     {
7889       emitcode ("rlc", "a");
7890       outBitC (result);
7891     }
7892   else
7893     {
7894       emitcode ("rl", "a");
7895       emitcode ("anl", "a,#0x01");
7896       outAcc (result);
7897     }
7898
7899   freeAsmop (result, NULL, ic, TRUE);
7900   freeAsmop (left, NULL, ic, TRUE);
7901 }
7902
7903 /*-----------------------------------------------------------------*/
7904 /* genGetAbit - generates code get a single bit                    */
7905 /*-----------------------------------------------------------------*/
7906 static void
7907 genGetAbit (iCode * ic)
7908 {
7909   operand *left, *right, *result;
7910   int shCount;
7911
7912   D (emitcode (";", "genGetAbit"));
7913
7914   left = IC_LEFT (ic);
7915   right = IC_RIGHT (ic);
7916   result = IC_RESULT (ic);
7917   aopOp (left, ic, FALSE);
7918   aopOp (right, ic, FALSE);
7919   aopOp (result, ic, FALSE);
7920
7921   shCount = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
7922
7923   /* get the needed byte into a */
7924   MOVA (aopGet (left, shCount / 8, FALSE, FALSE));
7925   shCount %= 8;
7926   if (AOP_TYPE (result) == AOP_CRY)
7927     {
7928       if ((shCount) == 7)
7929           emitcode ("rlc", "a");
7930       else if ((shCount) == 0)
7931           emitcode ("rrc", "a");
7932       else
7933           emitcode ("mov", "c,acc[%d]", shCount);
7934       outBitC (result);
7935     }
7936   else
7937     {
7938       switch (shCount)
7939         {
7940         case 2:
7941           emitcode ("rr", "a");
7942           //fallthrough
7943         case 1:
7944           emitcode ("rr", "a");
7945           //fallthrough
7946         case 0:
7947           emitcode ("anl", "a,#0x01");
7948           break;
7949         case 3:
7950         case 5:
7951           emitcode ("mov", "c,acc[%d]", shCount);
7952           emitcode ("clr", "a");
7953           emitcode ("rlc", "a");
7954           break;
7955         case 4:
7956           emitcode ("swap", "a");
7957           emitcode ("anl", "a,#0x01");
7958           break;
7959         case 6:
7960           emitcode ("rl", "a");
7961           //fallthrough
7962         case 7:
7963           emitcode ("rl", "a");
7964           emitcode ("anl", "a,#0x01");
7965           break;
7966         }
7967       outAcc (result);
7968     }
7969
7970   freeAsmop (result, NULL, ic, TRUE);
7971   freeAsmop (right, NULL, ic, TRUE);
7972   freeAsmop (left, NULL, ic, TRUE);
7973 }
7974
7975 /*-----------------------------------------------------------------*/
7976 /* genGetByte - generates code get a single byte                   */
7977 /*-----------------------------------------------------------------*/
7978 static void
7979 genGetByte (iCode * ic)
7980 {
7981   operand *left, *right, *result;
7982   int offset;
7983
7984   D (emitcode (";", "genGetByte"));
7985
7986   left = IC_LEFT (ic);
7987   right = IC_RIGHT (ic);
7988   result = IC_RESULT (ic);
7989   aopOp (left, ic, FALSE);
7990   aopOp (right, ic, FALSE);
7991   aopOp (result, ic, FALSE);
7992
7993   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
7994   aopPut (result,
7995           aopGet (left, offset, FALSE, FALSE),
7996           0);
7997
7998   freeAsmop (result, NULL, ic, TRUE);
7999   freeAsmop (right, NULL, ic, TRUE);
8000   freeAsmop (left, NULL, ic, TRUE);
8001 }
8002
8003 /*-----------------------------------------------------------------*/
8004 /* genGetWord - generates code get two bytes                       */
8005 /*-----------------------------------------------------------------*/
8006 static void
8007 genGetWord (iCode * ic)
8008 {
8009   operand *left, *right, *result;
8010   int offset;
8011
8012   D (emitcode (";", "genGetWord"));
8013
8014   left = IC_LEFT (ic);
8015   right = IC_RIGHT (ic);
8016   result = IC_RESULT (ic);
8017   aopOp (left, ic, FALSE);
8018   aopOp (right, ic, FALSE);
8019   aopOp (result, ic, FALSE);
8020
8021   offset = (int) ulFromVal (AOP (right)->aopu.aop_lit) / 8;
8022   aopPut (result,
8023           aopGet (left, offset, FALSE, FALSE),
8024           0);
8025   aopPut (result,
8026           aopGet (left, offset+1, FALSE, FALSE),
8027           1);
8028
8029   freeAsmop (result, NULL, ic, TRUE);
8030   freeAsmop (right, NULL, ic, TRUE);
8031   freeAsmop (left, NULL, ic, TRUE);
8032 }
8033
8034 /*-----------------------------------------------------------------*/
8035 /* genSwap - generates code to swap nibbles or bytes               */
8036 /*-----------------------------------------------------------------*/
8037 static void
8038 genSwap (iCode * ic)
8039 {
8040   operand *left, *result;
8041
8042   D(emitcode (";", "genSwap"));
8043
8044   left = IC_LEFT (ic);
8045   result = IC_RESULT (ic);
8046   aopOp (left, ic, FALSE);
8047   aopOp (result, ic, FALSE);
8048
8049   switch (AOP_SIZE (left))
8050     {
8051     case 1: /* swap nibbles in byte */
8052       MOVA (aopGet (left, 0, FALSE, FALSE));
8053       emitcode ("swap", "a");
8054       aopPut (result, "a", 0);
8055       break;
8056     case 2: /* swap bytes in word */
8057       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8058         {
8059           MOVA (aopGet (left, 0, FALSE, FALSE));
8060           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8061           aopPut (result, "a", 1);
8062         }
8063       else if (operandsEqu (left, result))
8064         {
8065           char * reg = "a";
8066           bool pushedB = FALSE, leftInB = FALSE;
8067
8068           MOVA (aopGet (left, 0, FALSE, FALSE));
8069           if (aopGetUsesAcc(left, 1) || aopGetUsesAcc(result, 0))
8070             {
8071               pushedB = pushB ();
8072               emitcode ("mov", "b,a");
8073               reg = "b";
8074               leftInB = TRUE;
8075             }
8076           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8077           aopPut (result, reg, 1);
8078
8079           if (leftInB)
8080             popB (pushedB);
8081         }
8082       else
8083         {
8084           aopPut (result, aopGet (left, 1, FALSE, FALSE), 0);
8085           aopPut (result, aopGet (left, 0, FALSE, FALSE), 1);
8086         }
8087       break;
8088     default:
8089       wassertl(FALSE, "unsupported SWAP operand size");
8090     }
8091
8092   freeAsmop (result, NULL, ic, TRUE);
8093   freeAsmop (left, NULL, ic, TRUE);
8094 }
8095
8096 /*-----------------------------------------------------------------*/
8097 /* AccRol - rotate left accumulator by known count                 */
8098 /*-----------------------------------------------------------------*/
8099 static void
8100 AccRol (int shCount)
8101 {
8102   shCount &= 0x0007;            // shCount : 0..7
8103
8104   switch (shCount)
8105     {
8106     case 0:
8107       break;
8108     case 1:
8109       emitcode ("rl", "a");
8110       break;
8111     case 2:
8112       emitcode ("rl", "a");
8113       emitcode ("rl", "a");
8114       break;
8115     case 3:
8116       emitcode ("swap", "a");
8117       emitcode ("rr", "a");
8118       break;
8119     case 4:
8120       emitcode ("swap", "a");
8121       break;
8122     case 5:
8123       emitcode ("swap", "a");
8124       emitcode ("rl", "a");
8125       break;
8126     case 6:
8127       emitcode ("rr", "a");
8128       emitcode ("rr", "a");
8129       break;
8130     case 7:
8131       emitcode ("rr", "a");
8132       break;
8133     }
8134 }
8135
8136 /*-----------------------------------------------------------------*/
8137 /* AccLsh - left shift accumulator by known count                  */
8138 /*-----------------------------------------------------------------*/
8139 static void
8140 AccLsh (int shCount)
8141 {
8142   if (shCount != 0)
8143     {
8144       if (shCount == 1)
8145         emitcode ("add", "a,acc");
8146       else if (shCount == 2)
8147         {
8148           emitcode ("add", "a,acc");
8149           emitcode ("add", "a,acc");
8150         }
8151       else
8152         {
8153           /* rotate left accumulator */
8154           AccRol (shCount);
8155           /* and kill the lower order bits */
8156           emitcode ("anl", "a,#0x%02x", SLMask[shCount]);
8157         }
8158     }
8159 }
8160
8161 /*-----------------------------------------------------------------*/
8162 /* AccRsh - right shift accumulator by known count                 */
8163 /*-----------------------------------------------------------------*/
8164 static void
8165 AccRsh (int shCount)
8166 {
8167   if (shCount != 0)
8168     {
8169       if (shCount == 1)
8170         {
8171           CLRC;
8172           emitcode ("rrc", "a");
8173         }
8174       else
8175         {
8176           /* rotate right accumulator */
8177           AccRol (8 - shCount);
8178           /* and kill the higher order bits */
8179           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8180         }
8181     }
8182 }
8183
8184 /*-----------------------------------------------------------------*/
8185 /* AccSRsh - signed right shift accumulator by known count                 */
8186 /*-----------------------------------------------------------------*/
8187 static void
8188 AccSRsh (int shCount)
8189 {
8190   symbol *tlbl;
8191   if (shCount != 0)
8192     {
8193       if (shCount == 1)
8194         {
8195           emitcode ("mov", "c,acc.7");
8196           emitcode ("rrc", "a");
8197         }
8198       else if (shCount == 2)
8199         {
8200           emitcode ("mov", "c,acc.7");
8201           emitcode ("rrc", "a");
8202           emitcode ("mov", "c,acc.7");
8203           emitcode ("rrc", "a");
8204         }
8205       else
8206         {
8207           tlbl = newiTempLabel (NULL);
8208           /* rotate right accumulator */
8209           AccRol (8 - shCount);
8210           /* and kill the higher order bits */
8211           emitcode ("anl", "a,#0x%02x", SRMask[shCount]);
8212           emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8213           emitcode ("orl", "a,#0x%02x",
8214                     (unsigned char) ~SRMask[shCount]);
8215           emitLabel (tlbl);
8216         }
8217     }
8218 }
8219
8220 /*-----------------------------------------------------------------*/
8221 /* shiftR1Left2Result - shift right one byte from left to result   */
8222 /*-----------------------------------------------------------------*/
8223 static void
8224 shiftR1Left2Result (operand * left, int offl,
8225                     operand * result, int offr,
8226                     int shCount, int sign)
8227 {
8228   MOVA (aopGet (left, offl, FALSE, FALSE));
8229   /* shift right accumulator */
8230   if (sign)
8231     AccSRsh (shCount);
8232   else
8233     AccRsh (shCount);
8234   aopPut (result, "a", offr);
8235 }
8236
8237 /*-----------------------------------------------------------------*/
8238 /* shiftL1Left2Result - shift left one byte from left to result    */
8239 /*-----------------------------------------------------------------*/
8240 static void
8241 shiftL1Left2Result (operand * left, int offl,
8242                     operand * result, int offr, int shCount)
8243 {
8244   char *l;
8245   l = aopGet (left, offl, FALSE, FALSE);
8246   MOVA (l);
8247   /* shift left accumulator */
8248   AccLsh (shCount);
8249   aopPut (result, "a", offr);
8250 }
8251
8252 /*-----------------------------------------------------------------*/
8253 /* movLeft2Result - move byte from left to result                  */
8254 /*-----------------------------------------------------------------*/
8255 static void
8256 movLeft2Result (operand * left, int offl,
8257                 operand * result, int offr, int sign)
8258 {
8259   char *l;
8260   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8261     {
8262       l = aopGet (left, offl, FALSE, FALSE);
8263
8264       if (*l == '@' && (IS_AOP_PREG (result)))
8265         {
8266           emitcode ("mov", "a,%s", l);
8267           aopPut (result, "a", offr);
8268         }
8269       else
8270         {
8271           if (!sign)
8272             {
8273               aopPut (result, l, offr);
8274             }
8275           else
8276             {
8277               /* MSB sign in acc.7 ! */
8278               if (getDataSize (left) == offl + 1)
8279                 {
8280                   MOVA (l);
8281                   aopPut (result, "a", offr);
8282                 }
8283             }
8284         }
8285     }
8286 }
8287
8288 /*-----------------------------------------------------------------*/
8289 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8290 /*-----------------------------------------------------------------*/
8291 static void
8292 AccAXRrl1 (char *x)
8293 {
8294   emitcode ("rrc", "a");
8295   emitcode ("xch", "a,%s", x);
8296   emitcode ("rrc", "a");
8297   emitcode ("xch", "a,%s", x);
8298 }
8299
8300 /*-----------------------------------------------------------------*/
8301 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8302 /*-----------------------------------------------------------------*/
8303 static void
8304 AccAXLrl1 (char *x)
8305 {
8306   emitcode ("xch", "a,%s", x);
8307   emitcode ("rlc", "a");
8308   emitcode ("xch", "a,%s", x);
8309   emitcode ("rlc", "a");
8310 }
8311
8312 /*-----------------------------------------------------------------*/
8313 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8314 /*-----------------------------------------------------------------*/
8315 static void
8316 AccAXLsh1 (char *x)
8317 {
8318   emitcode ("xch", "a,%s", x);
8319   emitcode ("add", "a,acc");
8320   emitcode ("xch", "a,%s", x);
8321   emitcode ("rlc", "a");
8322 }
8323
8324 /*-----------------------------------------------------------------*/
8325 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8326 /*-----------------------------------------------------------------*/
8327 static void
8328 AccAXLsh (char *x, int shCount)
8329 {
8330   switch (shCount)
8331     {
8332     case 0:
8333       break;
8334     case 1:
8335       AccAXLsh1 (x);
8336       break;
8337     case 2:
8338       AccAXLsh1 (x);
8339       AccAXLsh1 (x);
8340       break;
8341     case 3:
8342     case 4:
8343     case 5:                     // AAAAABBB:CCCCCDDD
8344
8345       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8346
8347       emitcode ("anl", "a,#0x%02x",
8348                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8349
8350       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8351
8352       AccRol (shCount);         // DDDCCCCC:BBB00000
8353
8354       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8355
8356       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8357
8358       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8359
8360       emitcode ("anl", "a,#0x%02x",
8361                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8362
8363       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8364
8365       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8366
8367       break;
8368     case 6:                     // AAAAAABB:CCCCCCDD
8369       emitcode ("anl", "a,#0x%02x",
8370                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8371       emitcode ("mov", "c,acc.0");      // c = B
8372       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8373 #if 0 // REMOVE ME
8374       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8375       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8376 #else
8377       emitcode("rrc","a");
8378       emitcode("xch","a,%s", x);
8379       emitcode("rrc","a");
8380       emitcode("mov","c,acc.0"); //<< get correct bit
8381       emitcode("xch","a,%s", x);
8382
8383       emitcode("rrc","a");
8384       emitcode("xch","a,%s", x);
8385       emitcode("rrc","a");
8386       emitcode("xch","a,%s", x);
8387 #endif
8388       break;
8389     case 7:                     // a:x <<= 7
8390
8391       emitcode ("anl", "a,#0x%02x",
8392                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8393
8394       emitcode ("mov", "c,acc.0");      // c = B
8395
8396       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8397
8398       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8399
8400       break;
8401     default:
8402       break;
8403     }
8404 }
8405
8406 /*-----------------------------------------------------------------*/
8407 /* AccAXRsh - right shift a:x known count (0..7)                   */
8408 /*-----------------------------------------------------------------*/
8409 static void
8410 AccAXRsh (char *x, int shCount)
8411 {
8412   switch (shCount)
8413     {
8414     case 0:
8415       break;
8416     case 1:
8417       CLRC;
8418       AccAXRrl1 (x);            // 0->a:x
8419
8420       break;
8421     case 2:
8422       CLRC;
8423       AccAXRrl1 (x);            // 0->a:x
8424
8425       CLRC;
8426       AccAXRrl1 (x);            // 0->a:x
8427
8428       break;
8429     case 3:
8430     case 4:
8431     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8432
8433       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8434
8435       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8436
8437       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8438
8439       emitcode ("anl", "a,#0x%02x",
8440                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8441
8442       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8443
8444       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8445
8446       emitcode ("anl", "a,#0x%02x",
8447                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8448
8449       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8450
8451       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8452
8453       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8454
8455       break;
8456     case 6:                     // AABBBBBB:CCDDDDDD
8457
8458       emitcode ("mov", "c,acc.7");
8459       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8460
8461       emitcode ("mov", "c,acc.7");
8462       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8463
8464       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8465
8466       emitcode ("anl", "a,#0x%02x",
8467                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8468
8469       break;
8470     case 7:                     // ABBBBBBB:CDDDDDDD
8471
8472       emitcode ("mov", "c,acc.7");      // c = A
8473
8474       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8475
8476       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8477
8478       emitcode ("anl", "a,#0x%02x",
8479                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8480
8481       break;
8482     default:
8483       break;
8484     }
8485 }
8486
8487 /*-----------------------------------------------------------------*/
8488 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8489 /*-----------------------------------------------------------------*/
8490 static void
8491 AccAXRshS (char *x, int shCount)
8492 {
8493   symbol *tlbl;
8494   switch (shCount)
8495     {
8496     case 0:
8497       break;
8498     case 1:
8499       emitcode ("mov", "c,acc.7");
8500       AccAXRrl1 (x);            // s->a:x
8501
8502       break;
8503     case 2:
8504       emitcode ("mov", "c,acc.7");
8505       AccAXRrl1 (x);            // s->a:x
8506
8507       emitcode ("mov", "c,acc.7");
8508       AccAXRrl1 (x);            // s->a:x
8509
8510       break;
8511     case 3:
8512     case 4:
8513     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8514
8515       tlbl = newiTempLabel (NULL);
8516       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8517
8518       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8519
8520       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8521
8522       emitcode ("anl", "a,#0x%02x",
8523                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8524
8525       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8526
8527       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8528
8529       emitcode ("anl", "a,#0x%02x",
8530                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8531
8532       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8533
8534       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8535
8536       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8537
8538       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8539       emitcode ("orl", "a,#0x%02x",
8540                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8541
8542       emitLabel (tlbl);
8543       break;                    // SSSSAAAA:BBBCCCCC
8544
8545     case 6:                     // AABBBBBB:CCDDDDDD
8546
8547       tlbl = newiTempLabel (NULL);
8548       emitcode ("mov", "c,acc.7");
8549       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8550
8551       emitcode ("mov", "c,acc.7");
8552       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8553
8554       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8555
8556       emitcode ("anl", "a,#0x%02x",
8557                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8558
8559       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8560       emitcode ("orl", "a,#0x%02x",
8561                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8562
8563       emitLabel (tlbl);
8564       break;
8565     case 7:                     // ABBBBBBB:CDDDDDDD
8566
8567       tlbl = newiTempLabel (NULL);
8568       emitcode ("mov", "c,acc.7");      // c = A
8569
8570       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8571
8572       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8573
8574       emitcode ("anl", "a,#0x%02x",
8575                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8576
8577       emitcode ("jnb", "acc.%d,%05d$", 7 - shCount, tlbl->key + 100);
8578       emitcode ("orl", "a,#0x%02x",
8579                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8580
8581       emitLabel (tlbl);
8582       break;
8583     default:
8584       break;
8585     }
8586 }
8587
8588 /*-----------------------------------------------------------------*/
8589 /* shiftL2Left2Result - shift left two bytes from left to result   */
8590 /*-----------------------------------------------------------------*/
8591 static void
8592 shiftL2Left2Result (operand * left, int offl,
8593                     operand * result, int offr, int shCount)
8594 {
8595   char * x;
8596   bool pushedB = FALSE;
8597   bool usedB = FALSE;
8598
8599   if (sameRegs (AOP (result), AOP (left)) &&
8600       ((offl + MSB16) == offr))
8601     {
8602       /* don't crash result[offr] */
8603       MOVA (aopGet (left, offl, FALSE, FALSE));
8604       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8605       usedB = !strncmp(x, "b", 1);
8606     }
8607   else if (aopGetUsesAcc (result, offr))
8608     {
8609       movLeft2Result (left, offl, result, offr, 0);
8610       pushedB = pushB ();
8611       usedB = TRUE;
8612       emitcode ("mov", "b,%s", aopGet (left, offl + MSB16, FALSE, FALSE));
8613       MOVA (aopGet (result, offr, FALSE, FALSE));
8614       emitcode ("xch", "a,b");
8615       x = "b";
8616     }
8617   else
8618     {
8619       movLeft2Result (left, offl, result, offr, 0);
8620       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8621       x = aopGet (result, offr, FALSE, FALSE);
8622     }
8623   /* ax << shCount (x = lsb(result)) */
8624   AccAXLsh (x, shCount);
8625   if (usedB)
8626     {
8627       emitcode ("xch", "a,b");
8628       aopPut (result, "a", offr);
8629       aopPut (result, "b", offr + MSB16);
8630       popB (pushedB);
8631     }
8632   else
8633     {
8634       aopPut (result, "a", offr + MSB16);
8635     }
8636 }
8637
8638
8639 /*-----------------------------------------------------------------*/
8640 /* shiftR2Left2Result - shift right two bytes from left to result  */
8641 /*-----------------------------------------------------------------*/
8642 static void
8643 shiftR2Left2Result (operand * left, int offl,
8644                     operand * result, int offr,
8645                     int shCount, int sign)
8646 {
8647   char * x;
8648   bool pushedB = FALSE;
8649   bool usedB = FALSE;
8650
8651   if (sameRegs (AOP (result), AOP (left)) &&
8652       ((offl + MSB16) == offr))
8653     {
8654       /* don't crash result[offr] */
8655       MOVA (aopGet (left, offl, FALSE, FALSE));
8656       x = xch_a_aopGet (left, offl + MSB16, FALSE, FALSE);
8657       usedB = !strncmp(x, "b", 1);
8658     }
8659   else if (aopGetUsesAcc (result, offr))
8660     {
8661       movLeft2Result (left, offl, result, offr, 0);
8662       pushedB = pushB ();
8663       usedB = TRUE;
8664       emitcode ("mov", "b,%s", aopGet (result, offr, FALSE, FALSE));
8665       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8666       x = "b";
8667     }
8668   else
8669     {
8670       movLeft2Result (left, offl, result, offr, 0);
8671       MOVA (aopGet (left, offl + MSB16, FALSE, FALSE));
8672       x = aopGet (result, offr, FALSE, FALSE);
8673     }
8674   /* a:x >> shCount (x = lsb(result)) */
8675   if (sign)
8676     AccAXRshS (x, shCount);
8677   else
8678     AccAXRsh (x, shCount);
8679   if (usedB)
8680     {
8681       emitcode ("xch", "a,b");
8682       aopPut (result, "a", offr);
8683       emitcode ("xch", "a,b");
8684       popB (pushedB);
8685     }
8686   if (getDataSize (result) > 1)
8687     aopPut (result, "a", offr + MSB16);
8688 }
8689
8690 /*-----------------------------------------------------------------*/
8691 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8692 /*-----------------------------------------------------------------*/
8693 static void
8694 shiftLLeftOrResult (operand * left, int offl,
8695                     operand * result, int offr, int shCount)
8696 {
8697   MOVA (aopGet (left, offl, FALSE, FALSE));
8698   /* shift left accumulator */
8699   AccLsh (shCount);
8700   /* or with result */
8701   if (aopGetUsesAcc (result, offr))
8702     {
8703       emitcode ("xch", "a,b");
8704       MOVA (aopGet (result, offr, FALSE, FALSE));
8705       emitcode ("orl", "a,b");
8706     }
8707   else
8708     {
8709       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8710     }
8711   /* back to result */
8712   aopPut (result, "a", offr);
8713 }
8714
8715 /*-----------------------------------------------------------------*/
8716 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8717 /*-----------------------------------------------------------------*/
8718 static void
8719 shiftRLeftOrResult (operand * left, int offl,
8720                     operand * result, int offr, int shCount)
8721 {
8722   MOVA (aopGet (left, offl, FALSE, FALSE));
8723   /* shift right accumulator */
8724   AccRsh (shCount);
8725   /* or with result */
8726   if (aopGetUsesAcc(result, offr))
8727     {
8728       emitcode ("xch", "a,b");
8729       MOVA (aopGet (result, offr, FALSE, FALSE));
8730       emitcode ("orl", "a,b");
8731     }
8732   else
8733     {
8734       emitcode ("orl", "a,%s", aopGet (result, offr, FALSE, FALSE));
8735     }
8736   /* back to result */
8737   aopPut (result, "a", offr);
8738 }
8739
8740 /*-----------------------------------------------------------------*/
8741 /* genlshOne - left shift a one byte quantity by known count       */
8742 /*-----------------------------------------------------------------*/
8743 static void
8744 genlshOne (operand * result, operand * left, int shCount)
8745 {
8746   D (emitcode (";", "genlshOne"));
8747
8748   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8749 }
8750
8751 /*-----------------------------------------------------------------*/
8752 /* genlshTwo - left shift two bytes by known amount != 0           */
8753 /*-----------------------------------------------------------------*/
8754 static void
8755 genlshTwo (operand * result, operand * left, int shCount)
8756 {
8757   int size;
8758
8759   D (emitcode (";", "genlshTwo"));
8760
8761   size = getDataSize (result);
8762
8763   /* if shCount >= 8 */
8764   if (shCount >= 8)
8765     {
8766       shCount -= 8;
8767
8768       if (size > 1)
8769         {
8770           if (shCount)
8771             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8772           else
8773             movLeft2Result (left, LSB, result, MSB16, 0);
8774         }
8775       aopPut (result, zero, LSB);
8776     }
8777
8778   /*  1 <= shCount <= 7 */
8779   else
8780     {
8781       if (size == 1)
8782         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8783       else
8784         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8785     }
8786 }
8787
8788 /*-----------------------------------------------------------------*/
8789 /* shiftLLong - shift left one long from left to result            */
8790 /* offl = LSB or MSB16                                             */
8791 /*-----------------------------------------------------------------*/
8792 static void
8793 shiftLLong (operand * left, operand * result, int offr)
8794 {
8795   char *l;
8796   int size = AOP_SIZE (result);
8797
8798   if (size >= LSB + offr)
8799     {
8800       l = aopGet (left, LSB, FALSE, FALSE);
8801       MOVA (l);
8802       emitcode ("add", "a,acc");
8803       if (sameRegs (AOP (left), AOP (result)) &&
8804           size >= MSB16 + offr && offr != LSB)
8805         xch_a_aopGet (left, LSB + offr, FALSE, FALSE);
8806       else
8807         aopPut (result, "a", LSB + offr);
8808     }
8809
8810   if (size >= MSB16 + offr)
8811     {
8812       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8813         {
8814           l = aopGet (left, MSB16, FALSE, FALSE);
8815           MOVA (l);
8816         }
8817       emitcode ("rlc", "a");
8818       if (sameRegs (AOP (left), AOP (result)) &&
8819           size >= MSB24 + offr && offr != LSB)
8820         xch_a_aopGet (left, MSB16 + offr, FALSE, FALSE);
8821       else
8822         aopPut (result, "a", MSB16 + offr);
8823     }
8824
8825   if (size >= MSB24 + offr)
8826     {
8827       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8828         {
8829           l = aopGet (left, MSB24, FALSE, FALSE);
8830           MOVA (l);
8831         }
8832       emitcode ("rlc", "a");
8833       if (sameRegs (AOP (left), AOP (result)) &&
8834           size >= MSB32 + offr && offr != LSB)
8835         xch_a_aopGet (left, MSB24 + offr, FALSE, FALSE);
8836       else
8837         aopPut (result, "a", MSB24 + offr);
8838     }
8839
8840   if (size > MSB32 + offr)
8841     {
8842       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8843         {
8844           l = aopGet (left, MSB32, FALSE, FALSE);
8845           MOVA (l);
8846         }
8847       emitcode ("rlc", "a");
8848       aopPut (result, "a", MSB32 + offr);
8849     }
8850   if (offr != LSB)
8851     aopPut (result, zero, LSB);
8852 }
8853
8854 /*-----------------------------------------------------------------*/
8855 /* genlshFour - shift four byte by a known amount != 0             */
8856 /*-----------------------------------------------------------------*/
8857 static void
8858 genlshFour (operand * result, operand * left, int shCount)
8859 {
8860   int size;
8861
8862   D (emitcode (";", "genlshFour"));
8863
8864   size = AOP_SIZE (result);
8865
8866   /* if shifting more that 3 bytes */
8867   if (shCount >= 24)
8868     {
8869       shCount -= 24;
8870       if (shCount)
8871         /* lowest order of left goes to the highest
8872            order of the destination */
8873         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8874       else
8875         movLeft2Result (left, LSB, result, MSB32, 0);
8876       aopPut (result, zero, LSB);
8877       aopPut (result, zero, MSB16);
8878       aopPut (result, zero, MSB24);
8879       return;
8880     }
8881
8882   /* more than two bytes */
8883   else if (shCount >= 16)
8884     {
8885       /* lower order two bytes goes to higher order two bytes */
8886       shCount -= 16;
8887       /* if some more remaining */
8888       if (shCount)
8889         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8890       else
8891         {
8892           movLeft2Result (left, MSB16, result, MSB32, 0);
8893           movLeft2Result (left, LSB, result, MSB24, 0);
8894         }
8895       aopPut (result, zero, MSB16);
8896       aopPut (result, zero, LSB);
8897       return;
8898     }
8899
8900   /* if more than 1 byte */
8901   else if (shCount >= 8)
8902     {
8903       /* lower order three bytes goes to higher order  three bytes */
8904       shCount -= 8;
8905       if (size == 2)
8906         {
8907           if (shCount)
8908             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8909           else
8910             movLeft2Result (left, LSB, result, MSB16, 0);
8911         }
8912       else
8913         {                       /* size = 4 */
8914           if (shCount == 0)
8915             {
8916               movLeft2Result (left, MSB24, result, MSB32, 0);
8917               movLeft2Result (left, MSB16, result, MSB24, 0);
8918               movLeft2Result (left, LSB, result, MSB16, 0);
8919               aopPut (result, zero, LSB);
8920             }
8921           else if (shCount == 1)
8922             shiftLLong (left, result, MSB16);
8923           else
8924             {
8925               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8926               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8927               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8928               aopPut (result, zero, LSB);
8929             }
8930         }
8931     }
8932
8933   /* 1 <= shCount <= 7 */
8934   else if (shCount <= 2)
8935     {
8936       shiftLLong (left, result, LSB);
8937       if (shCount == 2)
8938         shiftLLong (result, result, LSB);
8939     }
8940   /* 3 <= shCount <= 7, optimize */
8941   else
8942     {
8943       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8944       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8945       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8946     }
8947 }
8948
8949 /*-----------------------------------------------------------------*/
8950 /* genLeftShiftLiteral - left shifting by known count              */
8951 /*-----------------------------------------------------------------*/
8952 static void
8953 genLeftShiftLiteral (operand * left,
8954                      operand * right,
8955                      operand * result,
8956                      iCode * ic)
8957 {
8958   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
8959   int size;
8960
8961   D (emitcode (";", "genLeftShiftLiteral"));
8962
8963   freeAsmop (right, NULL, ic, TRUE);
8964
8965   aopOp (left, ic, FALSE);
8966   aopOp (result, ic, FALSE);
8967
8968   size = getSize (operandType (result));
8969
8970 #if VIEW_SIZE
8971   emitcode ("; shift left ", "result %d, left %d", size,
8972             AOP_SIZE (left));
8973 #endif
8974
8975   /* I suppose that the left size >= result size */
8976   if (shCount == 0)
8977     {
8978       while (size--)
8979         {
8980           movLeft2Result (left, size, result, size, 0);
8981         }
8982     }
8983   else if (shCount >= (size * 8))
8984     {
8985       while (size--)
8986         {
8987           aopPut (result, zero, size);
8988         }
8989     }
8990   else
8991     {
8992       switch (size)
8993         {
8994         case 1:
8995           genlshOne (result, left, shCount);
8996           break;
8997
8998         case 2:
8999           genlshTwo (result, left, shCount);
9000           break;
9001
9002         case 4:
9003           genlshFour (result, left, shCount);
9004           break;
9005         default:
9006           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9007                   "*** ack! mystery literal shift!\n");
9008           break;
9009         }
9010     }
9011   freeAsmop (result, NULL, ic, TRUE);
9012   freeAsmop (left, NULL, ic, TRUE);
9013 }
9014
9015 /*-----------------------------------------------------------------*/
9016 /* genLeftShift - generates code for left shifting                 */
9017 /*-----------------------------------------------------------------*/
9018 static void
9019 genLeftShift (iCode * ic)
9020 {
9021   operand *left, *right, *result;
9022   int size, offset;
9023   char *l;
9024   symbol *tlbl, *tlbl1;
9025   bool pushedB;
9026
9027   D (emitcode (";", "genLeftShift"));
9028
9029   right = IC_RIGHT (ic);
9030   left = IC_LEFT (ic);
9031   result = IC_RESULT (ic);
9032
9033   aopOp (right, ic, FALSE);
9034
9035   /* if the shift count is known then do it
9036      as efficiently as possible */
9037   if (AOP_TYPE (right) == AOP_LIT)
9038     {
9039       genLeftShiftLiteral (left, right, result, ic);
9040       return;
9041     }
9042
9043   /* shift count is unknown then we have to form
9044      a loop get the loop count in B : Note: we take
9045      only the lower order byte since shifting
9046      more that 32 bits make no sense anyway, ( the
9047      largest size of an object can be only 32 bits ) */
9048
9049   pushedB = pushB ();
9050   MOVB (aopGet (right, 0, FALSE, FALSE));
9051   emitcode ("inc", "b");
9052   freeAsmop (right, NULL, ic, TRUE);
9053   aopOp (left, ic, FALSE);
9054   aopOp (result, ic, FALSE);
9055
9056   /* now move the left to the result if they are not the same */
9057   if (!sameRegs (AOP (left), AOP (result)) &&
9058       AOP_SIZE (result) > 1)
9059     {
9060
9061       size = AOP_SIZE (result);
9062       offset = 0;
9063       while (size--)
9064         {
9065           l = aopGet (left, offset, FALSE, TRUE);
9066           if (*l == '@' && (IS_AOP_PREG (result)))
9067             {
9068
9069               emitcode ("mov", "a,%s", l);
9070               aopPut (result, "a", offset);
9071             }
9072           else
9073             aopPut (result, l, offset);
9074           offset++;
9075         }
9076     }
9077
9078   tlbl = newiTempLabel (NULL);
9079   size = AOP_SIZE (result);
9080   offset = 0;
9081   tlbl1 = newiTempLabel (NULL);
9082
9083   /* if it is only one byte then */
9084   if (size == 1)
9085     {
9086       symbol *tlbl1 = newiTempLabel (NULL);
9087
9088       l = aopGet (left, 0, FALSE, FALSE);
9089       MOVA (l);
9090       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9091       emitLabel (tlbl);
9092       emitcode ("add", "a,acc");
9093       emitLabel (tlbl1);
9094       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9095       popB (pushedB);
9096       aopPut (result, "a", 0);
9097       goto release;
9098     }
9099
9100   reAdjustPreg (AOP (result));
9101
9102   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9103   emitLabel (tlbl);
9104   l = aopGet (result, offset, FALSE, FALSE);
9105   MOVA (l);
9106   emitcode ("add", "a,acc");
9107   aopPut (result, "a", offset++);
9108   while (--size)
9109     {
9110       l = aopGet (result, offset, FALSE, FALSE);
9111       MOVA (l);
9112       emitcode ("rlc", "a");
9113       aopPut (result, "a", offset++);
9114     }
9115   reAdjustPreg (AOP (result));
9116
9117   emitLabel (tlbl1);
9118   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9119   popB (pushedB);
9120 release:
9121   freeAsmop (result, NULL, ic, TRUE);
9122   freeAsmop (left, NULL, ic, TRUE);
9123 }
9124
9125 /*-----------------------------------------------------------------*/
9126 /* genrshOne - right shift a one byte quantity by known count      */
9127 /*-----------------------------------------------------------------*/
9128 static void
9129 genrshOne (operand * result, operand * left,
9130            int shCount, int sign)
9131 {
9132   D (emitcode (";", "genrshOne"));
9133
9134   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9135 }
9136
9137 /*-----------------------------------------------------------------*/
9138 /* genrshTwo - right shift two bytes by known amount != 0          */
9139 /*-----------------------------------------------------------------*/
9140 static void
9141 genrshTwo (operand * result, operand * left,
9142            int shCount, int sign)
9143 {
9144   D (emitcode (";", "genrshTwo"));
9145
9146   /* if shCount >= 8 */
9147   if (shCount >= 8)
9148     {
9149       shCount -= 8;
9150       if (shCount)
9151         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9152       else
9153         movLeft2Result (left, MSB16, result, LSB, sign);
9154       addSign (result, MSB16, sign);
9155     }
9156
9157   /*  1 <= shCount <= 7 */
9158   else
9159     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9160 }
9161
9162 /*-----------------------------------------------------------------*/
9163 /* shiftRLong - shift right one long from left to result           */
9164 /* offl = LSB or MSB16                                             */
9165 /*-----------------------------------------------------------------*/
9166 static void
9167 shiftRLong (operand * left, int offl,
9168             operand * result, int sign)
9169 {
9170   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9171
9172   if (overlapping && offl>1)
9173     {
9174       // we are in big trouble, but this shouldn't happen
9175       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9176     }
9177
9178   MOVA (aopGet (left, MSB32, FALSE, FALSE));
9179
9180   if (offl==MSB16)
9181     {
9182       // shift is > 8
9183       if (sign)
9184         {
9185           emitcode ("rlc", "a");
9186           emitcode ("subb", "a,acc");
9187           if (overlapping && sameByte (AOP (left), MSB32, AOP (result), MSB32))
9188             {
9189               xch_a_aopGet (left, MSB32, FALSE, FALSE);
9190             }
9191           else
9192             {
9193               aopPut (result, "a", MSB32);
9194               MOVA (aopGet (left, MSB32, FALSE, FALSE));
9195             }
9196         }
9197       else
9198         {
9199           if (aopPutUsesAcc (result, zero, MSB32))
9200             {
9201               emitcode("xch", "a,b");
9202               aopPut (result, zero, MSB32);
9203               emitcode("xch", "a,b");
9204             }
9205           else
9206             {
9207               aopPut (result, zero, MSB32);
9208             }
9209         }
9210     }
9211
9212   if (!sign)
9213     {
9214       emitcode ("clr", "c");
9215     }
9216   else
9217     {
9218       emitcode ("mov", "c,acc.7");
9219     }
9220
9221   emitcode ("rrc", "a");
9222
9223   if (overlapping && offl==MSB16 &&
9224       sameByte (AOP (left), MSB24, AOP (result), MSB32-offl))
9225     {
9226       xch_a_aopGet (left, MSB24, FALSE, FALSE);
9227     }
9228   else
9229     {
9230       aopPut (result, "a", MSB32 - offl);
9231       MOVA (aopGet (left, MSB24, FALSE, FALSE));
9232     }
9233
9234   emitcode ("rrc", "a");
9235   if (overlapping && offl==MSB16 &&
9236       sameByte (AOP (left), MSB16, AOP (result), MSB24-offl))
9237     {
9238       xch_a_aopGet (left, MSB16, FALSE, FALSE);
9239     }
9240   else
9241     {
9242       aopPut (result, "a", MSB24 - offl);
9243       MOVA (aopGet (left, MSB16, FALSE, FALSE));
9244     }
9245
9246   emitcode ("rrc", "a");
9247   if (offl != LSB)
9248     {
9249       aopPut (result, "a", MSB16 - offl);
9250     }
9251   else
9252     {
9253       if (overlapping &&
9254           sameByte (AOP (left), LSB, AOP (result), MSB16-offl))
9255         {
9256           xch_a_aopGet (left, LSB, FALSE, FALSE);
9257         }
9258       else
9259         {
9260           aopPut (result, "a", MSB16 - offl);
9261           MOVA (aopGet (left, LSB, FALSE, FALSE));
9262         }
9263       emitcode ("rrc", "a");
9264       aopPut (result, "a", LSB);
9265     }
9266 }
9267
9268 /*-----------------------------------------------------------------*/
9269 /* genrshFour - shift four byte by a known amount != 0             */
9270 /*-----------------------------------------------------------------*/
9271 static void
9272 genrshFour (operand * result, operand * left,
9273             int shCount, int sign)
9274 {
9275   D (emitcode (";", "genrshFour"));
9276
9277   /* if shifting more that 3 bytes */
9278   if (shCount >= 24)
9279     {
9280       shCount -= 24;
9281       if (shCount)
9282         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9283       else
9284         movLeft2Result (left, MSB32, result, LSB, sign);
9285       addSign (result, MSB16, sign);
9286     }
9287   else if (shCount >= 16)
9288     {
9289       shCount -= 16;
9290       if (shCount)
9291         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9292       else
9293         {
9294           movLeft2Result (left, MSB24, result, LSB, 0);
9295           movLeft2Result (left, MSB32, result, MSB16, sign);
9296         }
9297       addSign (result, MSB24, sign);
9298     }
9299   else if (shCount >= 8)
9300     {
9301       shCount -= 8;
9302       if (shCount == 1)
9303         {
9304           shiftRLong (left, MSB16, result, sign);
9305         }
9306       else if (shCount == 0)
9307         {
9308           movLeft2Result (left, MSB16, result, LSB, 0);
9309           movLeft2Result (left, MSB24, result, MSB16, 0);
9310           movLeft2Result (left, MSB32, result, MSB24, sign);
9311           addSign (result, MSB32, sign);
9312         }
9313       else
9314         {
9315           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9316           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9317           /* the last shift is signed */
9318           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9319           addSign (result, MSB32, sign);
9320         }
9321     }
9322   else
9323     {
9324       /* 1 <= shCount <= 7 */
9325       if (shCount <= 2)
9326         {
9327           shiftRLong (left, LSB, result, sign);
9328           if (shCount == 2)
9329             shiftRLong (result, LSB, result, sign);
9330         }
9331       else
9332         {
9333           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9334           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9335           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9336         }
9337     }
9338 }
9339
9340 /*-----------------------------------------------------------------*/
9341 /* genRightShiftLiteral - right shifting by known count            */
9342 /*-----------------------------------------------------------------*/
9343 static void
9344 genRightShiftLiteral (operand * left,
9345                       operand * right,
9346                       operand * result,
9347                       iCode * ic,
9348                       int sign)
9349 {
9350   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9351   int size;
9352
9353   D (emitcode (";", "genRightShiftLiteral"));
9354
9355   freeAsmop (right, NULL, ic, TRUE);
9356
9357   aopOp (left, ic, FALSE);
9358   aopOp (result, ic, FALSE);
9359
9360 #if VIEW_SIZE
9361   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9362             AOP_SIZE (left));
9363 #endif
9364
9365   size = getDataSize (left);
9366   /* test the LEFT size !!! */
9367
9368   /* I suppose that the left size >= result size */
9369   if (shCount == 0)
9370     {
9371       size = getDataSize (result);
9372       while (size--)
9373         movLeft2Result (left, size, result, size, 0);
9374     }
9375
9376   else if (shCount >= (size * 8))
9377     {
9378       if (sign)
9379         {
9380           /* get sign in acc.7 */
9381           MOVA (aopGet (left, size - 1, FALSE, FALSE));
9382         }
9383       addSign (result, LSB, sign);
9384     }
9385   else
9386     {
9387       switch (size)
9388         {
9389         case 1:
9390           genrshOne (result, left, shCount, sign);
9391           break;
9392
9393         case 2:
9394           genrshTwo (result, left, shCount, sign);
9395           break;
9396
9397         case 4:
9398           genrshFour (result, left, shCount, sign);
9399           break;
9400         default:
9401           break;
9402         }
9403     }
9404   freeAsmop (result, NULL, ic, TRUE);
9405   freeAsmop (left, NULL, ic, TRUE);
9406 }
9407
9408 /*-----------------------------------------------------------------*/
9409 /* genSignedRightShift - right shift of signed number              */
9410 /*-----------------------------------------------------------------*/
9411 static void
9412 genSignedRightShift (iCode * ic)
9413 {
9414   operand *right, *left, *result;
9415   int size, offset;
9416   char *l;
9417   symbol *tlbl, *tlbl1;
9418   bool pushedB;
9419
9420   D (emitcode (";", "genSignedRightShift"));
9421
9422   /* we do it the hard way put the shift count in b
9423      and loop thru preserving the sign */
9424
9425   right = IC_RIGHT (ic);
9426   left = IC_LEFT (ic);
9427   result = IC_RESULT (ic);
9428
9429   aopOp (right, ic, FALSE);
9430
9431
9432   if (AOP_TYPE (right) == AOP_LIT)
9433     {
9434       genRightShiftLiteral (left, right, result, ic, 1);
9435       return;
9436     }
9437   /* shift count is unknown then we have to form
9438      a loop get the loop count in B : Note: we take
9439      only the lower order byte since shifting
9440      more that 32 bits make no sense anyway, ( the
9441      largest size of an object can be only 32 bits ) */
9442
9443   pushedB = pushB ();
9444   MOVB (aopGet (right, 0, FALSE, FALSE));
9445   emitcode ("inc", "b");
9446   freeAsmop (right, NULL, ic, TRUE);
9447   aopOp (left, ic, FALSE);
9448   aopOp (result, ic, FALSE);
9449
9450   /* now move the left to the result if they are not the
9451      same */
9452   if (!sameRegs (AOP (left), AOP (result)) &&
9453       AOP_SIZE (result) > 1)
9454     {
9455
9456       size = AOP_SIZE (result);
9457       offset = 0;
9458       while (size--)
9459         {
9460           l = aopGet (left, offset, FALSE, TRUE);
9461           if (*l == '@' && IS_AOP_PREG (result))
9462             {
9463
9464               emitcode ("mov", "a,%s", l);
9465               aopPut (result, "a", offset);
9466             }
9467           else
9468             aopPut (result, l, offset);
9469           offset++;
9470         }
9471     }
9472
9473   /* mov the highest order bit to OVR */
9474   tlbl = newiTempLabel (NULL);
9475   tlbl1 = newiTempLabel (NULL);
9476
9477   size = AOP_SIZE (result);
9478   offset = size - 1;
9479   MOVA (aopGet (left, offset, FALSE, FALSE));
9480   emitcode ("rlc", "a");
9481   emitcode ("mov", "ov,c");
9482   /* if it is only one byte then */
9483   if (size == 1)
9484     {
9485       l = aopGet (left, 0, FALSE, FALSE);
9486       MOVA (l);
9487       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9488       emitLabel (tlbl);
9489       emitcode ("mov", "c,ov");
9490       emitcode ("rrc", "a");
9491       emitLabel (tlbl1);
9492       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9493       popB (pushedB);
9494       aopPut (result, "a", 0);
9495       goto release;
9496     }
9497
9498   reAdjustPreg (AOP (result));
9499   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9500   emitLabel (tlbl);
9501   emitcode ("mov", "c,ov");
9502   while (size--)
9503     {
9504       l = aopGet (result, offset, FALSE, FALSE);
9505       MOVA (l);
9506       emitcode ("rrc", "a");
9507       aopPut (result, "a", offset--);
9508     }
9509   reAdjustPreg (AOP (result));
9510   emitLabel (tlbl1);
9511   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9512   popB (pushedB);
9513
9514 release:
9515   freeAsmop (result, NULL, ic, TRUE);
9516   freeAsmop (left, NULL, ic, TRUE);
9517 }
9518
9519 /*-----------------------------------------------------------------*/
9520 /* genRightShift - generate code for right shifting                */
9521 /*-----------------------------------------------------------------*/
9522 static void
9523 genRightShift (iCode * ic)
9524 {
9525   operand *right, *left, *result;
9526   sym_link *letype;
9527   int size, offset;
9528   char *l;
9529   symbol *tlbl, *tlbl1;
9530   bool pushedB;
9531
9532   D (emitcode (";", "genRightShift"));
9533
9534   /* if signed then we do it the hard way preserve the
9535      sign bit moving it inwards */
9536   letype = getSpec (operandType (IC_LEFT (ic)));
9537
9538   if (!SPEC_USIGN (letype))
9539     {
9540       genSignedRightShift (ic);
9541       return;
9542     }
9543
9544   /* signed & unsigned types are treated the same : i.e. the
9545      signed is NOT propagated inwards : quoting from the
9546      ANSI - standard : "for E1 >> E2, is equivalent to division
9547      by 2**E2 if unsigned or if it has a non-negative value,
9548      otherwise the result is implementation defined ", MY definition
9549      is that the sign does not get propagated */
9550
9551   right = IC_RIGHT (ic);
9552   left = IC_LEFT (ic);
9553   result = IC_RESULT (ic);
9554
9555   aopOp (right, ic, FALSE);
9556
9557   /* if the shift count is known then do it
9558      as efficiently as possible */
9559   if (AOP_TYPE (right) == AOP_LIT)
9560     {
9561       genRightShiftLiteral (left, right, result, ic, 0);
9562       return;
9563     }
9564
9565   /* shift count is unknown then we have to form
9566      a loop get the loop count in B : Note: we take
9567      only the lower order byte since shifting
9568      more that 32 bits make no sense anyway, ( the
9569      largest size of an object can be only 32 bits ) */
9570
9571   pushedB = pushB ();
9572   MOVB (aopGet (right, 0, FALSE, FALSE));
9573   emitcode ("inc", "b");
9574   freeAsmop (right, NULL, ic, TRUE);
9575   aopOp (left, ic, FALSE);
9576   aopOp (result, ic, FALSE);
9577
9578   /* now move the left to the result if they are not the
9579      same */
9580   if (!sameRegs (AOP (left), AOP (result)) &&
9581       AOP_SIZE (result) > 1)
9582     {
9583       size = AOP_SIZE (result);
9584       offset = 0;
9585       while (size--)
9586         {
9587           l = aopGet (left, offset, FALSE, TRUE);
9588           if (*l == '@' && IS_AOP_PREG (result))
9589             {
9590
9591               emitcode ("mov", "a,%s", l);
9592               aopPut (result, "a", offset);
9593             }
9594           else
9595             aopPut (result, l, offset);
9596           offset++;
9597         }
9598     }
9599
9600   tlbl = newiTempLabel (NULL);
9601   tlbl1 = newiTempLabel (NULL);
9602   size = AOP_SIZE (result);
9603   offset = size - 1;
9604
9605   /* if it is only one byte then */
9606   if (size == 1)
9607     {
9608       l = aopGet (left, 0, FALSE, FALSE);
9609       MOVA (l);
9610       emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9611       emitLabel (tlbl);
9612       CLRC;
9613       emitcode ("rrc", "a");
9614       emitLabel (tlbl1);
9615       emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9616       popB (pushedB);
9617       aopPut (result, "a", 0);
9618       goto release;
9619     }
9620
9621   reAdjustPreg (AOP (result));
9622   emitcode ("sjmp", "%05d$", tlbl1->key + 100);
9623   emitLabel (tlbl);
9624   CLRC;
9625   while (size--)
9626     {
9627       l = aopGet (result, offset, FALSE, FALSE);
9628       MOVA (l);
9629       emitcode ("rrc", "a");
9630       aopPut (result, "a", offset--);
9631     }
9632   reAdjustPreg (AOP (result));
9633
9634   emitLabel (tlbl1);
9635   emitcode ("djnz", "b,%05d$", tlbl->key + 100);
9636   popB (pushedB);
9637
9638 release:
9639   freeAsmop (result, NULL, ic, TRUE);
9640   freeAsmop (left, NULL, ic, TRUE);
9641 }
9642
9643 /*-----------------------------------------------------------------*/
9644 /* emitPtrByteGet - emits code to get a byte into A through a      */
9645 /*                  pointer register (R0, R1, or DPTR). The        */
9646 /*                  original value of A can be preserved in B.     */
9647 /*-----------------------------------------------------------------*/
9648 static void
9649 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9650 {
9651   switch (p_type)
9652     {
9653     case IPOINTER:
9654     case POINTER:
9655       if (preserveAinB)
9656         emitcode ("mov", "b,a");
9657       emitcode ("mov", "a,@%s", rname);
9658       break;
9659
9660     case PPOINTER:
9661       if (preserveAinB)
9662         emitcode ("mov", "b,a");
9663       emitcode ("movx", "a,@%s", rname);
9664       break;
9665
9666     case FPOINTER:
9667       if (preserveAinB)
9668         emitcode ("mov", "b,a");
9669       emitcode ("movx", "a,@dptr");
9670       break;
9671
9672     case CPOINTER:
9673       if (preserveAinB)
9674         emitcode ("mov", "b,a");
9675       emitcode ("clr", "a");
9676       emitcode ("movc", "a,@a+dptr");
9677       break;
9678
9679     case GPOINTER:
9680       if (preserveAinB)
9681         {
9682           emitcode ("push", "b");
9683           emitcode ("push", "acc");
9684         }
9685       emitcode ("lcall", "__gptrget");
9686       if (preserveAinB)
9687         emitcode ("pop", "b");
9688       break;
9689     }
9690 }
9691
9692 /*-----------------------------------------------------------------*/
9693 /* emitPtrByteSet - emits code to set a byte from src through a    */
9694 /*                  pointer register (R0, R1, or DPTR).            */
9695 /*-----------------------------------------------------------------*/
9696 static void
9697 emitPtrByteSet (char *rname, int p_type, char *src)
9698 {
9699   switch (p_type)
9700     {
9701     case IPOINTER:
9702     case POINTER:
9703       if (*src=='@')
9704         {
9705           MOVA (src);
9706           emitcode ("mov", "@%s,a", rname);
9707         }
9708       else
9709         emitcode ("mov", "@%s,%s", rname, src);
9710       break;
9711
9712     case PPOINTER:
9713       MOVA (src);
9714       emitcode ("movx", "@%s,a", rname);
9715       break;
9716
9717     case FPOINTER:
9718       MOVA (src);
9719       emitcode ("movx", "@dptr,a");
9720       break;
9721
9722     case GPOINTER:
9723       MOVA (src);
9724       emitcode ("lcall", "__gptrput");
9725       break;
9726     }
9727 }
9728
9729 /*-----------------------------------------------------------------*/
9730 /* genUnpackBits - generates code for unpacking bits               */
9731 /*-----------------------------------------------------------------*/
9732 static void
9733 genUnpackBits (operand * result, char *rname, int ptype, iCode *ifx)
9734 {
9735   int offset = 0;       /* result byte offset */
9736   int rsize;            /* result size */
9737   int rlen = 0;         /* remaining bitfield length */
9738   sym_link *etype;      /* bitfield type information */
9739   int blen;             /* bitfield length */
9740   int bstr;             /* bitfield starting bit within byte */
9741   char buffer[10];
9742
9743   D(emitcode (";", "genUnpackBits"));
9744
9745   etype = getSpec (operandType (result));
9746   rsize = getSize (operandType (result));
9747   blen = SPEC_BLEN (etype);
9748   bstr = SPEC_BSTR (etype);
9749
9750   if (ifx && blen <= 8)
9751     {
9752       emitPtrByteGet (rname, ptype, FALSE);
9753       if (blen == 1)
9754         {
9755           SNPRINTF (buffer, sizeof(buffer),
9756                     "acc.%d", bstr);
9757           genIfxJump (ifx, buffer, NULL, NULL, NULL);
9758         }
9759       else
9760         {
9761           if (blen < 8)
9762             emitcode ("anl", "a,#0x%02x",
9763                       (((unsigned char) -1) >> (8 - blen)) << bstr);
9764           genIfxJump (ifx, "a", NULL, NULL, NULL);
9765         }
9766       return;
9767     }
9768   wassert (!ifx);
9769
9770   /* If the bitfield length is less than a byte */
9771   if (blen < 8)
9772     {
9773       emitPtrByteGet (rname, ptype, FALSE);
9774       AccRol (8 - bstr);
9775       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8 - blen));
9776       if (!SPEC_USIGN (etype))
9777         {
9778           /* signed bitfield */
9779           symbol *tlbl = newiTempLabel (NULL);
9780
9781           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
9782           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
9783           emitLabel (tlbl);
9784         }
9785       aopPut (result, "a", offset++);
9786       goto finish;
9787     }
9788
9789   /* Bit field did not fit in a byte. Copy all
9790      but the partial byte at the end.  */
9791   for (rlen=blen;rlen>=8;rlen-=8)
9792     {
9793       emitPtrByteGet (rname, ptype, FALSE);
9794       aopPut (result, "a", offset++);
9795       if (rlen>8)
9796         emitcode ("inc", "%s", rname);
9797     }
9798
9799   /* Handle the partial byte at the end */
9800   if (rlen)
9801     {
9802       emitPtrByteGet (rname, ptype, FALSE);
9803       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
9804       if (!SPEC_USIGN (etype))
9805         {
9806           /* signed bitfield */
9807           symbol *tlbl = newiTempLabel (NULL);
9808
9809           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
9810           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
9811           emitLabel (tlbl);
9812         }
9813       aopPut (result, "a", offset++);
9814     }
9815
9816 finish:
9817   if (offset < rsize)
9818     {
9819       char *source;
9820
9821       if (SPEC_USIGN (etype))
9822         source = zero;
9823       else
9824         {
9825           /* signed bitfield: sign extension with 0x00 or 0xff */
9826           emitcode ("rlc", "a");
9827           emitcode ("subb", "a,acc");
9828
9829           source = "a";
9830         }
9831       rsize -= offset;
9832       while (rsize--)
9833         aopPut (result, source, offset++);
9834     }
9835 }
9836
9837
9838 /*-----------------------------------------------------------------*/
9839 /* genDataPointerGet - generates code when ptr offset is known     */
9840 /*-----------------------------------------------------------------*/
9841 static void
9842 genDataPointerGet (operand * left,
9843                    operand * result,
9844                    iCode * ic)
9845 {
9846   char *l;
9847   char buffer[256];
9848   int size, offset = 0;
9849
9850   D (emitcode (";", "genDataPointerGet"));
9851
9852   aopOp (result, ic, TRUE);
9853
9854   /* get the string representation of the name */
9855   l = aopGet (left, 0, FALSE, TRUE);
9856   l++; // remove #
9857   size = AOP_SIZE (result);
9858   while (size--)
9859     {
9860       if (offset)
9861         {
9862           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
9863         }
9864       else
9865         {
9866           SNPRINTF (buffer, sizeof(buffer), "%s", l);
9867         }
9868       aopPut (result, buffer, offset++);
9869     }
9870
9871   freeAsmop (result, NULL, ic, TRUE);
9872   freeAsmop (left, NULL, ic, TRUE);
9873 }
9874
9875 /*-----------------------------------------------------------------*/
9876 /* genNearPointerGet - emitcode for near pointer fetch             */
9877 /*-----------------------------------------------------------------*/
9878 static void
9879 genNearPointerGet (operand * left,
9880                    operand * result,
9881                    iCode * ic,
9882                    iCode * pi,
9883                    iCode * ifx)
9884 {
9885   asmop *aop = NULL;
9886   regs *preg = NULL;
9887   char *rname;
9888   sym_link *rtype, *retype;
9889   sym_link *ltype = operandType (left);
9890   char buffer[80];
9891
9892   D (emitcode (";", "genNearPointerGet"));
9893
9894   rtype = operandType (result);
9895   retype = getSpec (rtype);
9896
9897   aopOp (left, ic, FALSE);
9898
9899   /* if left is rematerialisable and
9900      result is not bitfield variable type and
9901      the left is pointer to data space i.e
9902      lower 128 bytes of space */
9903   if (AOP_TYPE (left) == AOP_IMMD &&
9904       !IS_BITFIELD (retype) &&
9905       DCL_TYPE (ltype) == POINTER)
9906     {
9907       genDataPointerGet (left, result, ic);
9908       return;
9909     }
9910
9911  /* if the value is already in a pointer register
9912      then don't need anything more */
9913   if (!AOP_INPREG (AOP (left)))
9914     {
9915       if (IS_AOP_PREG (left))
9916         {
9917           // Aha, it is a pointer, just in disguise.
9918           rname = aopGet (left, 0, FALSE, FALSE);
9919           if (*rname != '@')
9920             {
9921               fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
9922                       __FILE__, __LINE__);
9923             }
9924           else
9925             {
9926               // Expected case.
9927               emitcode ("mov", "a%s,%s", rname + 1, rname);
9928               rname++;  // skip the '@'.
9929             }
9930         }
9931       else
9932         {
9933           /* otherwise get a free pointer register */
9934           aop = newAsmop (0);
9935           preg = getFreePtr (ic, &aop, FALSE);
9936           emitcode ("mov", "%s,%s",
9937                     preg->name,
9938                     aopGet (left, 0, FALSE, TRUE));
9939           rname = preg->name;
9940         }
9941     }
9942   else
9943     rname = aopGet (left, 0, FALSE, FALSE);
9944
9945   //aopOp (result, ic, FALSE);
9946   aopOp (result, ic, result?TRUE:FALSE);
9947
9948   /* if bitfield then unpack the bits */
9949   if (IS_BITFIELD (retype))
9950     genUnpackBits (result, rname, POINTER, ifx);
9951   else
9952     {
9953       /* we have can just get the values */
9954       int size = AOP_SIZE (result);
9955       int offset = 0;
9956
9957       while (size--)
9958         {
9959           if (ifx || IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9960             {
9961
9962               emitcode ("mov", "a,@%s", rname);
9963               if (!ifx)
9964                 aopPut (result, "a", offset);
9965             }
9966           else
9967             {
9968               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
9969               aopPut (result, buffer, offset);
9970             }
9971           offset++;
9972           if (size || pi)
9973             emitcode ("inc", "%s", rname);
9974         }
9975     }
9976
9977   /* now some housekeeping stuff */
9978   if (aop)       /* we had to allocate for this iCode */
9979     {
9980       if (pi) { /* post increment present */
9981         aopPut (left, rname, 0);
9982       }
9983       freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
9984     }
9985   else
9986     {
9987       /* we did not allocate which means left
9988          already in a pointer register, then
9989          if size > 0 && this could be used again
9990          we have to point it back to where it
9991          belongs */
9992       if ((AOP_SIZE (result) > 1 &&
9993            !OP_SYMBOL (left)->remat &&
9994            (OP_SYMBOL (left)->liveTo > ic->seq ||
9995             ic->depth)) &&
9996           !pi)
9997         {
9998           int size = AOP_SIZE (result) - 1;
9999           while (size--)
10000             emitcode ("dec", "%s", rname);
10001         }
10002     }
10003
10004   if (ifx && !ifx->generated)
10005     {
10006       genIfxJump (ifx, "a", left, NULL, result);
10007     }
10008
10009   /* done */
10010   freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
10011   freeAsmop (left, NULL, ic, TRUE);
10012   if (pi) pi->generated = 1;
10013 }
10014
10015 /*-----------------------------------------------------------------*/
10016 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10017 /*-----------------------------------------------------------------*/
10018 static void
10019 genPagedPointerGet (operand * left,
10020                     operand * result,
10021                     iCode * ic,
10022                     iCode *pi,
10023                     iCode *ifx)
10024 {
10025   asmop *aop = NULL;
10026   regs *preg = NULL;
10027   char *rname;
10028   sym_link *rtype, *retype;
10029
10030   D (emitcode (";", "genPagedPointerGet"));
10031
10032   rtype = operandType (result);
10033   retype = getSpec (rtype);
10034
10035   aopOp (left, ic, FALSE);
10036
10037   /* if the value is already in a pointer register
10038      then don't need anything more */
10039   if (!AOP_INPREG (AOP (left)))
10040     {
10041       /* otherwise get a free pointer register */
10042       aop = newAsmop (0);
10043       preg = getFreePtr (ic, &aop, FALSE);
10044       emitcode ("mov", "%s,%s",
10045                 preg->name,
10046                 aopGet (left, 0, FALSE, TRUE));
10047       rname = preg->name;
10048     }
10049   else
10050     rname = aopGet (left, 0, FALSE, FALSE);
10051
10052   aopOp (result, ic, FALSE);
10053
10054   /* if bitfield then unpack the bits */
10055   if (IS_BITFIELD (retype))
10056     genUnpackBits (result, rname, PPOINTER, ifx);
10057   else
10058     {
10059       /* we have can just get the values */
10060       int size = AOP_SIZE (result);
10061       int offset = 0;
10062
10063       while (size--)
10064         {
10065
10066           emitcode ("movx", "a,@%s", rname);
10067           if (!ifx)
10068             aopPut (result, "a", offset);
10069
10070           offset++;
10071
10072           if (size || pi)
10073             emitcode ("inc", "%s", rname);
10074         }
10075     }
10076
10077   /* now some housekeeping stuff */
10078   if (aop) /* we had to allocate for this iCode */
10079     {
10080       if (pi)
10081         aopPut (left, rname, 0);
10082       freeAsmop (NULL, aop, ic, TRUE);
10083     }
10084   else
10085     {
10086       /* we did not allocate which means left
10087          already in a pointer register, then
10088          if size > 0 && this could be used again
10089          we have to point it back to where it
10090          belongs */
10091       if ((AOP_SIZE (result) > 1 &&
10092            !OP_SYMBOL (left)->remat &&
10093            (OP_SYMBOL (left)->liveTo > ic->seq ||
10094             ic->depth)) &&
10095           !pi)
10096         {
10097           int size = AOP_SIZE (result) - 1;
10098           while (size--)
10099             emitcode ("dec", "%s", rname);
10100         }
10101     }
10102
10103   if (ifx && !ifx->generated)
10104     {
10105       genIfxJump (ifx, "a", left, NULL, result);
10106     }
10107
10108   /* done */
10109   freeAsmop (result, NULL, ic, TRUE);
10110   freeAsmop (left, NULL, ic, TRUE);
10111   if (pi) pi->generated = 1;
10112 }
10113
10114 /*--------------------------------------------------------------------*/
10115 /* loadDptrFromOperand - load dptr (and optionally B) from operand op */
10116 /*--------------------------------------------------------------------*/
10117 static void
10118 loadDptrFromOperand (operand *op, bool loadBToo)
10119 {
10120   if (AOP_TYPE (op) != AOP_STR)
10121     {
10122       /* if this is rematerializable */
10123       if (AOP_TYPE (op) == AOP_IMMD)
10124         {
10125           emitcode ("mov", "dptr,%s", aopGet (op, 0, TRUE, FALSE));
10126           if (loadBToo)
10127             {
10128               if (AOP(op)->aopu.aop_immd.from_cast_remat)
10129                 emitcode ("mov", "b,%s",aopGet (op, AOP_SIZE(op)-1, FALSE, FALSE));
10130               else
10131                 {
10132                   wassertl(FALSE, "need pointerCode");
10133                   emitcode (";", "mov b,???");
10134                   /* genPointerGet and genPointerSet originally did different
10135                   ** things for this case. Both seem wrong.
10136                   ** from genPointerGet:
10137                   **  emitcode ("mov", "b,#%d", pointerCode (retype));
10138                   ** from genPointerSet:
10139                   **  emitcode ("mov", "b,%s + 1", aopGet (result, 0, TRUE, FALSE));
10140                   */
10141                 }
10142             }
10143         }
10144       else if (AOP_TYPE (op) == AOP_DPTR)
10145         {
10146           if (loadBToo)
10147             {
10148               MOVA (aopGet (op, 0, FALSE, FALSE));
10149               emitcode ("push", "acc");
10150               MOVA (aopGet (op, 1, FALSE, FALSE));
10151               emitcode ("push", "acc");
10152               emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10153               emitcode ("pop", "dph");
10154               emitcode ("pop", "dpl");
10155             }
10156           else
10157             {
10158               MOVA (aopGet (op, 0, FALSE, FALSE));
10159               emitcode ("push", "acc");
10160               emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10161               emitcode ("pop", "dpl");
10162             }
10163         }
10164       else
10165         {                       /* we need to get it byte by byte */
10166           emitcode ("mov", "dpl,%s", aopGet (op, 0, FALSE, FALSE));
10167           emitcode ("mov", "dph,%s", aopGet (op, 1, FALSE, FALSE));
10168           if (loadBToo)
10169             emitcode ("mov", "b,%s", aopGet (op, 2, FALSE, FALSE));
10170         }
10171     }
10172 }
10173
10174 /*-----------------------------------------------------------------*/
10175 /* genFarPointerGet - get value from far space                     */
10176 /*-----------------------------------------------------------------*/
10177 static void
10178 genFarPointerGet (operand * left,
10179                   operand * result, iCode * ic, iCode * pi, iCode * ifx)
10180 {
10181   int size, offset;
10182   sym_link *retype = getSpec (operandType (result));
10183
10184   D (emitcode (";", "genFarPointerGet"));
10185
10186   aopOp (left, ic, FALSE);
10187   loadDptrFromOperand (left, FALSE);
10188
10189   /* so dptr now contains the address */
10190   aopOp (result, ic, FALSE);
10191
10192   /* if bit then unpack */
10193   if (IS_BITFIELD (retype))
10194     genUnpackBits (result, "dptr", FPOINTER, ifx);
10195   else
10196     {
10197       size = AOP_SIZE (result);
10198       offset = 0;
10199
10200       while (size--)
10201         {
10202           emitcode ("movx", "a,@dptr");
10203           if (!ifx)
10204             aopPut (result, "a", offset++);
10205           if (size || pi)
10206             emitcode ("inc", "dptr");
10207         }
10208     }
10209
10210   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10211     {
10212       aopPut (left, "dpl", 0);
10213       aopPut (left, "dph", 1);
10214       pi->generated = 1;
10215     }
10216
10217   if (ifx && !ifx->generated)
10218     {
10219       genIfxJump (ifx, "a", left, NULL, result);
10220     }
10221
10222   freeAsmop (result, NULL, ic, TRUE);
10223   freeAsmop (left, NULL, ic, TRUE);
10224 }
10225
10226 /*-----------------------------------------------------------------*/
10227 /* genCodePointerGet - get value from code space                   */
10228 /*-----------------------------------------------------------------*/
10229 static void
10230 genCodePointerGet (operand * left,
10231                     operand * result, iCode * ic, iCode *pi, iCode *ifx)
10232 {
10233   int size, offset;
10234   sym_link *retype = getSpec (operandType (result));
10235
10236   D (emitcode (";", "genCodePointerGet"));
10237
10238   aopOp (left, ic, FALSE);
10239   loadDptrFromOperand (left, FALSE);
10240
10241   /* so dptr now contains the address */
10242   aopOp (result, ic, FALSE);
10243
10244   /* if bit then unpack */
10245   if (IS_BITFIELD (retype))
10246     genUnpackBits (result, "dptr", CPOINTER, ifx);
10247   else
10248     {
10249       size = AOP_SIZE (result);
10250       offset = 0;
10251
10252       while (size--)
10253         {
10254           emitcode ("clr", "a");
10255           emitcode ("movc", "a,@a+dptr");
10256           if (!ifx)
10257             aopPut (result, "a", offset++);
10258           if (size || pi)
10259             emitcode ("inc", "dptr");
10260         }
10261     }
10262
10263   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10264     {
10265       aopPut (left, "dpl", 0);
10266       aopPut (left, "dph", 1);
10267       pi->generated = 1;
10268     }
10269
10270   if (ifx && !ifx->generated)
10271     {
10272       genIfxJump (ifx, "a", left, NULL, result);
10273     }
10274
10275   freeAsmop (result, NULL, ic, TRUE);
10276   freeAsmop (left, NULL, ic, TRUE);
10277 }
10278
10279 /*-----------------------------------------------------------------*/
10280 /* genGenPointerGet - get value from generic pointer space         */
10281 /*-----------------------------------------------------------------*/
10282 static void
10283 genGenPointerGet (operand * left,
10284                   operand * result, iCode * ic, iCode *pi, iCode *ifx)
10285 {
10286   int size, offset;
10287   sym_link *retype = getSpec (operandType (result));
10288
10289   D (emitcode (";", "genGenPointerGet"));
10290
10291   aopOp (left, ic, FALSE);
10292   loadDptrFromOperand (left, TRUE);
10293
10294   /* so dptr now contains the address */
10295   aopOp (result, ic, FALSE);
10296
10297   /* if bit then unpack */
10298   if (IS_BITFIELD (retype))
10299     {
10300       genUnpackBits (result, "dptr", GPOINTER, ifx);
10301     }
10302   else
10303     {
10304       size = AOP_SIZE (result);
10305       offset = 0;
10306
10307       while (size--)
10308         {
10309           emitcode ("lcall", "__gptrget");
10310           if (!ifx)
10311             aopPut (result, "a", offset++);
10312           if (size || pi)
10313             emitcode ("inc", "dptr");
10314         }
10315     }
10316
10317   if (pi && AOP_TYPE (left) != AOP_IMMD && AOP_TYPE (left) != AOP_STR)
10318     {
10319       aopPut (left, "dpl", 0);
10320       aopPut (left, "dph", 1);
10321       pi->generated = 1;
10322     }
10323
10324   if (ifx && !ifx->generated)
10325     {
10326       genIfxJump (ifx, "a", left, NULL, result);
10327     }
10328
10329   freeAsmop (result, NULL, ic, TRUE);
10330   freeAsmop (left, NULL, ic, TRUE);
10331 }
10332
10333 /*-----------------------------------------------------------------*/
10334 /* genPointerGet - generate code for pointer get                   */
10335 /*-----------------------------------------------------------------*/
10336 static void
10337 genPointerGet (iCode * ic, iCode *pi, iCode *ifx)
10338 {
10339   operand *left, *result;
10340   sym_link *type, *etype;
10341   int p_type;
10342
10343   D (emitcode (";", "genPointerGet"));
10344
10345   left = IC_LEFT (ic);
10346   result = IC_RESULT (ic);
10347
10348   if (getSize (operandType (result))>1)
10349     ifx = NULL;
10350
10351   /* depending on the type of pointer we need to
10352      move it to the correct pointer register */
10353   type = operandType (left);
10354   etype = getSpec (type);
10355   /* if left is of type of pointer then it is simple */
10356   if (IS_PTR (type) && !IS_FUNC (type->next))
10357     {
10358       p_type = DCL_TYPE (type);
10359     }
10360   else
10361     {
10362       /* we have to go by the storage class */
10363       p_type = PTR_TYPE (SPEC_OCLS (etype));
10364     }
10365
10366   /* special case when cast remat */
10367   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10368       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10369     {
10370       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10371       type = operandType (left);
10372       p_type = DCL_TYPE (type);
10373     }
10374   /* now that we have the pointer type we assign
10375      the pointer values */
10376   switch (p_type)
10377     {
10378
10379     case POINTER:
10380     case IPOINTER:
10381       genNearPointerGet (left, result, ic, pi, ifx);
10382       break;
10383
10384     case PPOINTER:
10385       genPagedPointerGet (left, result, ic, pi, ifx);
10386       break;
10387
10388     case FPOINTER:
10389       genFarPointerGet (left, result, ic, pi, ifx);
10390       break;
10391
10392     case CPOINTER:
10393       genCodePointerGet (left, result, ic, pi, ifx);
10394       break;
10395
10396     case GPOINTER:
10397       genGenPointerGet (left, result, ic, pi, ifx);
10398       break;
10399     }
10400 }
10401
10402
10403 /*-----------------------------------------------------------------*/
10404 /* genPackBits - generates code for packed bit storage             */
10405 /*-----------------------------------------------------------------*/
10406 static void
10407 genPackBits (sym_link * etype,
10408              operand * right,
10409              char *rname, int p_type)
10410 {
10411   int offset = 0;       /* source byte offset */
10412   int rlen = 0;         /* remaining bitfield length */
10413   int blen;             /* bitfield length */
10414   int bstr;             /* bitfield starting bit within byte */
10415   int litval;           /* source literal value (if AOP_LIT) */
10416   unsigned char mask;   /* bitmask within current byte */
10417
10418   D(emitcode (";", "genPackBits"));
10419
10420   blen = SPEC_BLEN (etype);
10421   bstr = SPEC_BSTR (etype);
10422
10423   /* If the bitfield length is less than a byte */
10424   if (blen < 8)
10425     {
10426       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10427               (unsigned char) (0xFF >> (8 - bstr)));
10428
10429       if (AOP_TYPE (right) == AOP_LIT)
10430         {
10431           /* Case with a bitfield length <8 and literal source
10432           */
10433           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10434           litval <<= bstr;
10435           litval &= (~mask) & 0xff;
10436           emitPtrByteGet (rname, p_type, FALSE);
10437           if ((mask|litval)!=0xff)
10438             emitcode ("anl","a,#0x%02x", mask);
10439           if (litval)
10440             emitcode ("orl","a,#0x%02x", litval);
10441         }
10442       else
10443         {
10444           if ((blen==1) && (p_type!=GPOINTER))
10445             {
10446               /* Case with a bitfield length == 1 and no generic pointer
10447               */
10448               if (AOP_TYPE (right) == AOP_CRY)
10449                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10450               else
10451                 {
10452                   MOVA (aopGet (right, 0, FALSE, FALSE));
10453                   emitcode ("rrc","a");
10454                 }
10455               emitPtrByteGet (rname, p_type, FALSE);
10456               emitcode ("mov","acc.%d,c",bstr);
10457             }
10458           else
10459             {
10460               bool pushedB;
10461               /* Case with a bitfield length < 8 and arbitrary source
10462               */
10463               MOVA (aopGet (right, 0, FALSE, FALSE));
10464               /* shift and mask source value */
10465               AccLsh (bstr);
10466               emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10467
10468               pushedB = pushB ();
10469               /* transfer A to B and get next byte */
10470               emitPtrByteGet (rname, p_type, TRUE);
10471
10472               emitcode ("anl", "a,#0x%02x", mask);
10473               emitcode ("orl", "a,b");
10474               if (p_type == GPOINTER)
10475                 emitcode ("pop", "b");
10476
10477               popB (pushedB);
10478            }
10479         }
10480
10481       emitPtrByteSet (rname, p_type, "a");
10482       return;
10483     }
10484
10485   /* Bit length is greater than 7 bits. In this case, copy  */
10486   /* all except the partial byte at the end                 */
10487   for (rlen=blen;rlen>=8;rlen-=8)
10488     {
10489       emitPtrByteSet (rname, p_type,
10490                       aopGet (right, offset++, FALSE, TRUE) );
10491       if (rlen>8)
10492         emitcode ("inc", "%s", rname);
10493     }
10494
10495   /* If there was a partial byte at the end */
10496   if (rlen)
10497     {
10498       mask = (((unsigned char) -1 << rlen) & 0xff);
10499
10500       if (AOP_TYPE (right) == AOP_LIT)
10501         {
10502           /* Case with partial byte and literal source
10503           */
10504           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10505           litval >>= (blen-rlen);
10506           litval &= (~mask) & 0xff;
10507           emitPtrByteGet (rname, p_type, FALSE);
10508           if ((mask|litval)!=0xff)
10509             emitcode ("anl","a,#0x%02x", mask);
10510           if (litval)
10511             emitcode ("orl","a,#0x%02x", litval);
10512         }
10513       else
10514         {
10515           bool pushedB;
10516           /* Case with partial byte and arbitrary source
10517           */
10518           MOVA (aopGet (right, offset++, FALSE, FALSE));
10519           emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
10520
10521           pushedB = pushB ();
10522           /* transfer A to B and get next byte */
10523           emitPtrByteGet (rname, p_type, TRUE);
10524
10525           emitcode ("anl", "a,#0x%02x", mask);
10526           emitcode ("orl", "a,b");
10527           if (p_type == GPOINTER)
10528             emitcode ("pop", "b");
10529
10530           popB (pushedB);
10531         }
10532       emitPtrByteSet (rname, p_type, "a");
10533     }
10534 }
10535
10536
10537 /*-----------------------------------------------------------------*/
10538 /* genDataPointerSet - remat pointer to data space                 */
10539 /*-----------------------------------------------------------------*/
10540 static void
10541 genDataPointerSet (operand * right,
10542                    operand * result,
10543                    iCode * ic)
10544 {
10545   int size, offset = 0;
10546   char *l, buffer[256];
10547
10548   D (emitcode (";", "genDataPointerSet"));
10549
10550   aopOp (right, ic, FALSE);
10551
10552   l = aopGet (result, 0, FALSE, TRUE);
10553   l++; //remove #
10554   size = max (AOP_SIZE (right), AOP_SIZE (result));
10555   while (size--)
10556     {
10557       if (offset)
10558         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l, offset);
10559       else
10560         SNPRINTF (buffer, sizeof(buffer), "%s", l);
10561       emitcode ("mov", "%s,%s", buffer,
10562                 aopGet (right, offset++, FALSE, FALSE));
10563     }
10564
10565   freeAsmop (right, NULL, ic, TRUE);
10566   freeAsmop (result, NULL, ic, TRUE);
10567 }
10568
10569 /*-----------------------------------------------------------------*/
10570 /* genNearPointerSet - emitcode for near pointer put               */
10571 /*-----------------------------------------------------------------*/
10572 static void
10573 genNearPointerSet (operand * right,
10574                    operand * result,
10575                    iCode * ic,
10576                    iCode * pi)
10577 {
10578   asmop *aop = NULL;
10579   regs *preg = NULL;
10580   char *rname, *l;
10581   sym_link *retype, *letype;
10582   sym_link *ptype = operandType (result);
10583
10584   D (emitcode (";", "genNearPointerSet"));
10585
10586   retype = getSpec (operandType (right));
10587   letype = getSpec (ptype);
10588
10589   aopOp (result, ic, FALSE);
10590
10591   /* if the result is rematerializable &
10592      in data space & not a bit variable */
10593   if (AOP_TYPE (result) == AOP_IMMD &&
10594       DCL_TYPE (ptype) == POINTER &&
10595       !IS_BITVAR (retype) &&
10596       !IS_BITVAR (letype))
10597     {
10598       genDataPointerSet (right, result, ic);
10599       return;
10600     }
10601
10602   /* if the value is already in a pointer register
10603      then don't need anything more */
10604   if (!AOP_INPREG (AOP (result)))
10605     {
10606         if (
10607             //AOP_TYPE (result) == AOP_STK
10608             IS_AOP_PREG(result)
10609             )
10610         {
10611             // Aha, it is a pointer, just in disguise.
10612             rname = aopGet (result, 0, FALSE, FALSE);
10613             if (*rname != '@')
10614             {
10615                 fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
10616                         __FILE__, __LINE__);
10617             }
10618             else
10619             {
10620                 // Expected case.
10621                 emitcode ("mov", "a%s,%s", rname + 1, rname);
10622                 rname++;  // skip the '@'.
10623             }
10624         }
10625         else
10626         {
10627             /* otherwise get a free pointer register */
10628             aop = newAsmop (0);
10629             preg = getFreePtr (ic, &aop, FALSE);
10630             emitcode ("mov", "%s,%s",
10631                       preg->name,
10632                       aopGet (result, 0, FALSE, TRUE));
10633             rname = preg->name;
10634         }
10635     }
10636     else
10637     {
10638         rname = aopGet (result, 0, FALSE, FALSE);
10639     }
10640
10641   aopOp (right, ic, FALSE);
10642
10643   /* if bitfield then unpack the bits */
10644   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10645     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10646   else
10647     {
10648       /* we can just get the values */
10649       int size = AOP_SIZE (right);
10650       int offset = 0;
10651
10652       while (size--)
10653         {
10654           l = aopGet (right, offset, FALSE, TRUE);
10655           if ((*l == '@') || (strcmp (l, "acc") == 0))
10656             {
10657               MOVA (l);
10658               emitcode ("mov", "@%s,a", rname);
10659             }
10660           else
10661             emitcode ("mov", "@%s,%s", rname, l);
10662           if (size || pi)
10663             emitcode ("inc", "%s", rname);
10664           offset++;
10665         }
10666     }
10667
10668   /* now some housekeeping stuff */
10669   if (aop) /* we had to allocate for this iCode */
10670     {
10671       if (pi)
10672         aopPut (result, rname, 0);
10673       freeAsmop (NULL, aop, ic, TRUE);
10674     }
10675   else
10676     {
10677       /* we did not allocate which means left
10678          already in a pointer register, then
10679          if size > 0 && this could be used again
10680          we have to point it back to where it
10681          belongs */
10682       if ((AOP_SIZE (right) > 1 &&
10683            !OP_SYMBOL (result)->remat &&
10684            (OP_SYMBOL (result)->liveTo > ic->seq ||
10685             ic->depth)) &&
10686           !pi)
10687         {
10688           int size = AOP_SIZE (right) - 1;
10689           while (size--)
10690             emitcode ("dec", "%s", rname);
10691         }
10692     }
10693
10694   /* done */
10695   if (pi)
10696     pi->generated = 1;
10697   freeAsmop (right, NULL, ic, TRUE);
10698   freeAsmop (result, NULL, ic, TRUE);
10699 }
10700
10701 /*-----------------------------------------------------------------*/
10702 /* genPagedPointerSet - emitcode for Paged pointer put             */
10703 /*-----------------------------------------------------------------*/
10704 static void
10705 genPagedPointerSet (operand * right,
10706                     operand * result,
10707                     iCode * ic,
10708                     iCode * pi)
10709 {
10710   asmop *aop = NULL;
10711   regs *preg = NULL;
10712   char *rname, *l;
10713   sym_link *retype, *letype;
10714
10715   D (emitcode (";", "genPagedPointerSet"));
10716
10717   retype = getSpec (operandType (right));
10718   letype = getSpec (operandType (result));
10719
10720   aopOp (result, ic, FALSE);
10721
10722   /* if the value is already in a pointer register
10723      then don't need anything more */
10724   if (!AOP_INPREG (AOP (result)))
10725     {
10726       /* otherwise get a free pointer register */
10727       aop = newAsmop (0);
10728       preg = getFreePtr (ic, &aop, FALSE);
10729       emitcode ("mov", "%s,%s",
10730                 preg->name,
10731                 aopGet (result, 0, FALSE, TRUE));
10732       rname = preg->name;
10733     }
10734   else
10735     rname = aopGet (result, 0, FALSE, FALSE);
10736
10737   aopOp (right, ic, FALSE);
10738
10739   /* if bitfield then unpack the bits */
10740   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10741     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10742   else
10743     {
10744       /* we have can just get the values */
10745       int size = AOP_SIZE (right);
10746       int offset = 0;
10747
10748       while (size--)
10749         {
10750           l = aopGet (right, offset, FALSE, TRUE);
10751           MOVA (l);
10752           emitcode ("movx", "@%s,a", rname);
10753
10754           if (size || pi)
10755             emitcode ("inc", "%s", rname);
10756
10757           offset++;
10758         }
10759     }
10760
10761   /* now some housekeeping stuff */
10762   if (aop) /* we had to allocate for this iCode */
10763     {
10764       if (pi)
10765         aopPut (result, rname, 0);
10766       freeAsmop (NULL, aop, ic, TRUE);
10767     }
10768   else
10769     {
10770       /* we did not allocate which means left
10771          already in a pointer register, then
10772          if size > 0 && this could be used again
10773          we have to point it back to where it
10774          belongs */
10775       if (AOP_SIZE (right) > 1 &&
10776           !OP_SYMBOL (result)->remat &&
10777           (OP_SYMBOL (result)->liveTo > ic->seq ||
10778            ic->depth))
10779         {
10780           int size = AOP_SIZE (right) - 1;
10781           while (size--)
10782             emitcode ("dec", "%s", rname);
10783         }
10784     }
10785
10786   /* done */
10787   if (pi) pi->generated = 1;
10788   freeAsmop (result, NULL, ic, TRUE);
10789   freeAsmop (right, NULL, ic, TRUE);
10790 }
10791
10792 /*-----------------------------------------------------------------*/
10793 /* genFarPointerSet - set value from far space                     */
10794 /*-----------------------------------------------------------------*/
10795 static void
10796 genFarPointerSet (operand * right,
10797                   operand * result, iCode * ic, iCode * pi)
10798 {
10799   int size, offset;
10800   sym_link *retype = getSpec (operandType (right));
10801   sym_link *letype = getSpec (operandType (result));
10802
10803   D(emitcode (";", "genFarPointerSet"));
10804
10805   aopOp (result, ic, FALSE);
10806   loadDptrFromOperand (result, FALSE);
10807
10808   /* so dptr now contains the address */
10809   aopOp (right, ic, FALSE);
10810
10811   /* if bit then unpack */
10812   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10813     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10814   else
10815     {
10816       size = AOP_SIZE (right);
10817       offset = 0;
10818
10819       while (size--)
10820         {
10821           char *l = aopGet (right, offset++, FALSE, FALSE);
10822           MOVA (l);
10823           emitcode ("movx", "@dptr,a");
10824           if (size || pi)
10825             emitcode ("inc", "dptr");
10826         }
10827     }
10828   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10829     aopPut (result, "dpl", 0);
10830     aopPut (result, "dph", 1);
10831     pi->generated=1;
10832   }
10833   freeAsmop (result, NULL, ic, TRUE);
10834   freeAsmop (right, NULL, ic, TRUE);
10835 }
10836
10837 /*-----------------------------------------------------------------*/
10838 /* genGenPointerSet - set value from generic pointer space         */
10839 /*-----------------------------------------------------------------*/
10840 static void
10841 genGenPointerSet (operand * right,
10842                   operand * result, iCode * ic, iCode * pi)
10843 {
10844   int size, offset;
10845   sym_link *retype = getSpec (operandType (right));
10846   sym_link *letype = getSpec (operandType (result));
10847
10848   D (emitcode (";", "genGenPointerSet"));
10849
10850   aopOp (result, ic, FALSE);
10851   loadDptrFromOperand (result, TRUE);
10852
10853   /* so dptr now contains the address */
10854   aopOp (right, ic, FALSE);
10855
10856   /* if bit then unpack */
10857   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10858     {
10859       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10860     }
10861   else
10862     {
10863       size = AOP_SIZE (right);
10864       offset = 0;
10865
10866       while (size--)
10867         {
10868           char *l = aopGet (right, offset++, FALSE, FALSE);
10869           MOVA (l);
10870           emitcode ("lcall", "__gptrput");
10871           if (size || pi)
10872             emitcode ("inc", "dptr");
10873         }
10874     }
10875
10876   if (pi && AOP_TYPE (result) != AOP_STR && AOP_TYPE (result) != AOP_IMMD) {
10877     aopPut (result, "dpl", 0);
10878     aopPut (result, "dph", 1);
10879     pi->generated=1;
10880   }
10881   freeAsmop (result, NULL, ic, TRUE);
10882   freeAsmop (right, NULL, ic, TRUE);
10883 }
10884
10885 /*-----------------------------------------------------------------*/
10886 /* genPointerSet - stores the value into a pointer location        */
10887 /*-----------------------------------------------------------------*/
10888 static void
10889 genPointerSet (iCode * ic, iCode *pi)
10890 {
10891   operand *right, *result;
10892   sym_link *type, *etype;
10893   int p_type;
10894
10895   D (emitcode (";", "genPointerSet"));
10896
10897   right = IC_RIGHT (ic);
10898   result = IC_RESULT (ic);
10899
10900   /* depending on the type of pointer we need to
10901      move it to the correct pointer register */
10902   type = operandType (result);
10903   etype = getSpec (type);
10904   /* if left is of type of pointer then it is simple */
10905   if (IS_PTR (type) && !IS_FUNC (type->next))
10906     {
10907       p_type = DCL_TYPE (type);
10908     }
10909   else
10910     {
10911       /* we have to go by the storage class */
10912       p_type = PTR_TYPE (SPEC_OCLS (etype));
10913     }
10914
10915   /* special case when cast remat */
10916   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10917       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10918           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10919           type = operandType (result);
10920           p_type = DCL_TYPE (type);
10921   }
10922
10923   /* now that we have the pointer type we assign
10924      the pointer values */
10925   switch (p_type)
10926     {
10927
10928     case POINTER:
10929     case IPOINTER:
10930       genNearPointerSet (right, result, ic, pi);
10931       break;
10932
10933     case PPOINTER:
10934       genPagedPointerSet (right, result, ic, pi);
10935       break;
10936
10937     case FPOINTER:
10938       genFarPointerSet (right, result, ic, pi);
10939       break;
10940
10941     case GPOINTER:
10942       genGenPointerSet (right, result, ic, pi);
10943       break;
10944
10945     default:
10946       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
10947               "genPointerSet: illegal pointer type");
10948     }
10949 }
10950
10951 /*-----------------------------------------------------------------*/
10952 /* genIfx - generate code for Ifx statement                        */
10953 /*-----------------------------------------------------------------*/
10954 static void
10955 genIfx (iCode * ic, iCode * popIc)
10956 {
10957   operand *cond = IC_COND (ic);
10958   int isbit = 0;
10959   char *dup = NULL;
10960
10961   D (emitcode (";", "genIfx"));
10962
10963   aopOp (cond, ic, FALSE);
10964
10965   /* get the value into acc */
10966   if (AOP_TYPE (cond) != AOP_CRY)
10967     {
10968       toBoolean (cond);
10969     }
10970   else
10971     {
10972       isbit = 1;
10973       if (AOP(cond)->aopu.aop_dir)
10974         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
10975     }
10976
10977   /* the result is now in the accumulator or a directly addressable bit */
10978   freeAsmop (cond, NULL, ic, TRUE);
10979
10980   /* if there was something to be popped then do it */
10981   if (popIc)
10982     genIpop (popIc);
10983
10984   /* if the condition is a bit variable */
10985   if (isbit && dup)
10986     genIfxJump(ic, dup, NULL, NULL, NULL);
10987   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
10988     genIfxJump (ic, SPIL_LOC (cond)->rname, NULL, NULL, NULL);
10989   else if (isbit && !IS_ITEMP (cond))
10990     genIfxJump (ic, OP_SYMBOL (cond)->rname, NULL, NULL, NULL);
10991   else
10992     genIfxJump (ic, "a", NULL, NULL, NULL);
10993
10994   ic->generated = 1;
10995 }
10996
10997 /*-----------------------------------------------------------------*/
10998 /* genAddrOf - generates code for address of                       */
10999 /*-----------------------------------------------------------------*/
11000 static void
11001 genAddrOf (iCode * ic)
11002 {
11003   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11004   int size, offset;
11005
11006   D (emitcode (";", "genAddrOf"));
11007
11008   aopOp (IC_RESULT (ic), ic, FALSE);
11009
11010   /* if the operand is on the stack then we
11011      need to get the stack offset of this
11012      variable */
11013   if (sym->onStack)
11014     {
11015       /* if it has an offset then we need to compute it */
11016       if (sym->stack)
11017         {
11018           int stack_offset = ((sym->stack < 0) ?
11019                               ((char) (sym->stack - _G.nRegsSaved)) :
11020                               ((char) sym->stack)) & 0xff;
11021           if ((abs(stack_offset) == 1) &&
11022               !AOP_NEEDSACC(IC_RESULT (ic)) &&
11023               !isOperandVolatile (IC_RESULT (ic), FALSE))
11024             {
11025               aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11026               if (stack_offset > 0)
11027                 emitcode ("inc", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11028               else
11029                 emitcode ("dec", "%s", aopGet (IC_RESULT (ic), LSB, FALSE, FALSE));
11030             }
11031           else
11032             {
11033               emitcode ("mov", "a,%s", SYM_BP (sym));
11034               emitcode ("add", "a,#0x%02x", stack_offset & 0xff);
11035               aopPut (IC_RESULT (ic), "a", 0);
11036             }
11037         }
11038       else
11039         {
11040           /* we can just move _bp */
11041           aopPut (IC_RESULT (ic), SYM_BP (sym), 0);
11042         }
11043       /* fill the result with zero */
11044       size = AOP_SIZE (IC_RESULT (ic)) - 1;
11045
11046       offset = 1;
11047       while (size--)
11048         {
11049           aopPut (IC_RESULT (ic), zero, offset++);
11050         }
11051       goto release;
11052     }
11053
11054   /* object not on stack then we need the name */
11055   size = AOP_SIZE (IC_RESULT (ic));
11056   offset = 0;
11057
11058   while (size--)
11059     {
11060       char s[SDCC_NAME_MAX];
11061       if (offset)
11062         sprintf (s, "#(%s >> %d)",
11063                  sym->rname,
11064                  offset * 8);
11065       else
11066         SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11067       aopPut (IC_RESULT (ic), s, offset++);
11068     }
11069
11070 release:
11071   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11072
11073 }
11074
11075 /*-----------------------------------------------------------------*/
11076 /* genFarFarAssign - assignment when both are in far space         */
11077 /*-----------------------------------------------------------------*/
11078 static void
11079 genFarFarAssign (operand * result, operand * right, iCode * ic)
11080 {
11081   int size = AOP_SIZE (right);
11082   int offset = 0;
11083   char *l;
11084
11085   D (emitcode (";", "genFarFarAssign"));
11086
11087   /* first push the right side on to the stack */
11088   while (size--)
11089     {
11090       l = aopGet (right, offset++, FALSE, FALSE);
11091       MOVA (l);
11092       emitcode ("push", "acc");
11093     }
11094
11095   freeAsmop (right, NULL, ic, FALSE);
11096   /* now assign DPTR to result */
11097   aopOp (result, ic, FALSE);
11098   size = AOP_SIZE (result);
11099   while (size--)
11100     {
11101       emitcode ("pop", "acc");
11102       aopPut (result, "a", --offset);
11103     }
11104   freeAsmop (result, NULL, ic, FALSE);
11105 }
11106
11107 /*-----------------------------------------------------------------*/
11108 /* genAssign - generate code for assignment                        */
11109 /*-----------------------------------------------------------------*/
11110 static void
11111 genAssign (iCode * ic)
11112 {
11113   operand *result, *right;
11114   int size, offset;
11115   unsigned long lit = 0L;
11116
11117   D (emitcode (";", "genAssign"));
11118
11119   result = IC_RESULT (ic);
11120   right = IC_RIGHT (ic);
11121
11122   /* if they are the same */
11123   if (operandsEqu (result, right) &&
11124       !isOperandVolatile (result, FALSE) &&
11125       !isOperandVolatile (right, FALSE))
11126     return;
11127
11128   aopOp (right, ic, FALSE);
11129
11130   /* special case both in far space */
11131   if (AOP_TYPE (right) == AOP_DPTR &&
11132       IS_TRUE_SYMOP (result) &&
11133       isOperandInFarSpace (result))
11134     {
11135       genFarFarAssign (result, right, ic);
11136       return;
11137     }
11138
11139   aopOp (result, ic, TRUE);
11140
11141   /* if they are the same registers */
11142   if (sameRegs (AOP (right), AOP (result)) &&
11143       !isOperandVolatile (result, FALSE) &&
11144       !isOperandVolatile (right, FALSE))
11145     goto release;
11146
11147   /* if the result is a bit */
11148   if (AOP_TYPE (result) == AOP_CRY)
11149     {
11150       assignBit (result, right);
11151       goto release;
11152     }
11153
11154   /* bit variables done */
11155   /* general case */
11156   size = AOP_SIZE (result);
11157   offset = 0;
11158   if (AOP_TYPE (right) == AOP_LIT)
11159     lit = ulFromVal (AOP (right)->aopu.aop_lit);
11160
11161   if ((size > 1) &&
11162       (AOP_TYPE (result) != AOP_REG) &&
11163       (AOP_TYPE (right) == AOP_LIT) &&
11164       !IS_FLOAT (operandType (right)) &&
11165       (lit < 256L))
11166     {
11167       while ((size) && (lit))
11168         {
11169           aopPut (result,
11170                   aopGet (right, offset, FALSE, FALSE),
11171                   offset);
11172           lit >>= 8;
11173           offset++;
11174           size--;
11175         }
11176       /* And now fill the rest with zeros. */
11177       if (size)
11178         {
11179           emitcode ("clr", "a");
11180         }
11181       while (size--)
11182         {
11183           aopPut (result, "a", offset);
11184           offset++;
11185         }
11186     }
11187   else
11188     {
11189       while (size--)
11190         {
11191           aopPut (result,
11192                   aopGet (right, offset, FALSE, FALSE),
11193                   offset);
11194           offset++;
11195         }
11196     }
11197
11198 release:
11199   freeAsmop (result, NULL, ic, TRUE);
11200   freeAsmop (right, NULL, ic, TRUE);
11201 }
11202
11203 /*-----------------------------------------------------------------*/
11204 /* genJumpTab - generates code for jump table                      */
11205 /*-----------------------------------------------------------------*/
11206 static void
11207 genJumpTab (iCode * ic)
11208 {
11209   symbol *jtab,*jtablo,*jtabhi;
11210   char *l;
11211   unsigned int count;
11212
11213   D (emitcode (";", "genJumpTab"));
11214
11215   count = elementsInSet( IC_JTLABELS (ic) );
11216
11217   if( count <= 16 )
11218     {
11219       /* this algorithm needs 9 cycles and 7 + 3*n bytes
11220          if the switch argument is in a register.
11221          (8 cycles and 6+2*n bytes if peepholes can change ljmp to sjmp) */
11222       /* Peephole may not convert ljmp to sjmp or ret
11223          labelIsReturnOnly & labelInRange must check
11224          currPl->ic->op != JUMPTABLE */
11225       aopOp (IC_JTCOND (ic), ic, FALSE);
11226       /* get the condition into accumulator */
11227       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11228       MOVA (l);
11229       /* multiply by three */
11230       if (aopGetUsesAcc (IC_JTCOND (ic), 0))
11231         {
11232           emitcode ("mov", "b,#3");
11233           emitcode ("mul", "ab");
11234         }
11235       else
11236         {
11237           emitcode ("add", "a,acc");
11238           emitcode ("add", "a,%s", aopGet (IC_JTCOND (ic), 0, FALSE, FALSE));
11239         }
11240       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11241
11242       jtab = newiTempLabel (NULL);
11243       emitcode ("mov", "dptr,#%05d$", jtab->key + 100);
11244       emitcode ("jmp", "@a+dptr");
11245       emitLabel (jtab);
11246       /* now generate the jump labels */
11247       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11248            jtab = setNextItem (IC_JTLABELS (ic)))
11249         emitcode ("ljmp", "%05d$", jtab->key + 100);
11250     }
11251   else
11252     {
11253       /* this algorithm needs 14 cycles and 13 + 2*n bytes
11254          if the switch argument is in a register.
11255          For n>6 this algorithm may be more compact */
11256       jtablo = newiTempLabel (NULL);
11257       jtabhi = newiTempLabel (NULL);
11258
11259       /* get the condition into accumulator.
11260          Using b as temporary storage, if register push/pop is needed */
11261       aopOp (IC_JTCOND (ic), ic, FALSE);
11262       l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE);
11263       if ((AOP_TYPE (IC_JTCOND (ic)) == AOP_R0 && _G.r0Pushed) ||
11264           (AOP_TYPE (IC_JTCOND (ic)) == AOP_R1 && _G.r1Pushed))
11265         {
11266           // (MB) what if B is in use???
11267           wassertl(!BINUSE, "B was in use");
11268           emitcode ("mov", "b,%s", l);
11269           l = "b";
11270         }
11271       freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11272       MOVA (l);
11273       if( count <= 112 )
11274         {
11275           emitcode ("add", "a,#(%05d$-3-.)", jtablo->key + 100);
11276           emitcode ("movc", "a,@a+pc");
11277           emitcode ("push", "acc");
11278
11279           MOVA (l);
11280           emitcode ("add", "a,#(%05d$-3-.)", jtabhi->key + 100);
11281           emitcode ("movc", "a,@a+pc");
11282           emitcode ("push", "acc");
11283         }
11284       else
11285         {
11286           /* this scales up to n<=255, but needs two more bytes
11287              and changes dptr */
11288           emitcode ("mov", "dptr,#%05d$", jtablo->key + 100);
11289           emitcode ("movc", "a,@a+dptr");
11290           emitcode ("push", "acc");
11291
11292           MOVA (l);
11293           emitcode ("mov", "dptr,#%05d$", jtabhi->key + 100);
11294           emitcode ("movc", "a,@a+dptr");
11295           emitcode ("push", "acc");
11296         }
11297
11298       emitcode ("ret", "");
11299
11300       /* now generate jump table, LSB */
11301       emitLabel (jtablo);
11302       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11303            jtab = setNextItem (IC_JTLABELS (ic)))
11304         emitcode (".db", "%05d$", jtab->key + 100);
11305
11306       /* now generate jump table, MSB */
11307       emitLabel (jtabhi);
11308       for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11309            jtab = setNextItem (IC_JTLABELS (ic)))
11310          emitcode (".db", "%05d$>>8", jtab->key + 100);
11311     }
11312 }
11313
11314 /*-----------------------------------------------------------------*/
11315 /* genCast - gen code for casting                                  */
11316 /*-----------------------------------------------------------------*/
11317 static void
11318 genCast (iCode * ic)
11319 {
11320   operand *result = IC_RESULT (ic);
11321   sym_link *ctype = operandType (IC_LEFT (ic));
11322   sym_link *rtype = operandType (IC_RIGHT (ic));
11323   operand *right = IC_RIGHT (ic);
11324   int size, offset;
11325
11326   D (emitcode (";", "genCast"));
11327
11328   /* if they are equivalent then do nothing */
11329   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11330     return;
11331
11332   aopOp (right, ic, FALSE);
11333   aopOp (result, ic, FALSE);
11334
11335   /* if the result is a bit (and not a bitfield) */
11336   if (IS_BIT (OP_SYMBOL (result)->type))
11337     {
11338       assignBit (result, right);
11339       goto release;
11340     }
11341
11342   /* if they are the same size : or less */
11343   if (AOP_SIZE (result) <= AOP_SIZE (right))
11344     {
11345
11346       /* if they are in the same place */
11347       if (sameRegs (AOP (right), AOP (result)))
11348         goto release;
11349
11350       /* if they in different places then copy */
11351       size = AOP_SIZE (result);
11352       offset = 0;
11353       while (size--)
11354         {
11355           aopPut (result,
11356                   aopGet (right, offset, FALSE, FALSE),
11357                   offset);
11358           offset++;
11359         }
11360       goto release;
11361     }
11362
11363   /* if the result is of type pointer */
11364   if (IS_PTR (ctype))
11365     {
11366
11367       int p_type;
11368       sym_link *type = operandType (right);
11369       sym_link *etype = getSpec (type);
11370
11371       /* pointer to generic pointer */
11372       if (IS_GENPTR (ctype))
11373         {
11374           if (IS_PTR (type))
11375             {
11376               p_type = DCL_TYPE (type);
11377             }
11378           else
11379             {
11380               if (SPEC_SCLS(etype)==S_REGISTER) {
11381                 // let's assume it is a generic pointer
11382                 p_type=GPOINTER;
11383               } else {
11384                 /* we have to go by the storage class */
11385                 p_type = PTR_TYPE (SPEC_OCLS (etype));
11386               }
11387             }
11388
11389           /* the first two bytes are known */
11390           size = GPTRSIZE - 1;
11391           offset = 0;
11392           while (size--)
11393             {
11394               aopPut (result,
11395                       aopGet (right, offset, FALSE, FALSE),
11396                       offset);
11397               offset++;
11398             }
11399           /* the last byte depending on type */
11400             {
11401                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11402                 char gpValStr[10];
11403
11404                 if (gpVal == -1)
11405                 {
11406                     // pointerTypeToGPByte will have bitched.
11407                     exit(1);
11408                 }
11409
11410                 sprintf(gpValStr, "#0x%x", gpVal);
11411                 aopPut (result, gpValStr, GPTRSIZE - 1);
11412             }
11413           goto release;
11414         }
11415
11416       /* just copy the pointers */
11417       size = AOP_SIZE (result);
11418       offset = 0;
11419       while (size--)
11420         {
11421           aopPut (result,
11422                   aopGet (right, offset, FALSE, FALSE),
11423                   offset);
11424           offset++;
11425         }
11426       goto release;
11427     }
11428
11429   /* so we now know that the size of destination is greater
11430      than the size of the source */
11431   /* we move to result for the size of source */
11432   size = AOP_SIZE (right);
11433   offset = 0;
11434   while (size--)
11435     {
11436       aopPut (result,
11437               aopGet (right, offset, FALSE, FALSE),
11438               offset);
11439       offset++;
11440     }
11441
11442   /* now depending on the sign of the source && destination */
11443   size = AOP_SIZE (result) - AOP_SIZE (right);
11444   /* if unsigned or not an integral type */
11445   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
11446     {
11447       while (size--)
11448         aopPut (result, zero, offset++);
11449     }
11450   else
11451     {
11452       /* we need to extend the sign :{ */
11453       char *l = aopGet (right, AOP_SIZE (right) - 1,
11454                         FALSE, FALSE);
11455       MOVA (l);
11456       emitcode ("rlc", "a");
11457       emitcode ("subb", "a,acc");
11458       while (size--)
11459         aopPut (result, "a", offset++);
11460     }
11461
11462   /* we are done hurray !!!! */
11463
11464 release:
11465   freeAsmop (result, NULL, ic, TRUE);
11466   freeAsmop (right, NULL, ic, TRUE);
11467 }
11468
11469 /*-----------------------------------------------------------------*/
11470 /* genDjnz - generate decrement & jump if not zero instrucion      */
11471 /*-----------------------------------------------------------------*/
11472 static int
11473 genDjnz (iCode * ic, iCode * ifx)
11474 {
11475   symbol *lbl, *lbl1;
11476   if (!ifx)
11477     return 0;
11478
11479   /* if the if condition has a false label
11480      then we cannot save */
11481   if (IC_FALSE (ifx))
11482     return 0;
11483
11484   /* if the minus is not of the form a = a - 1 */
11485   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11486       !IS_OP_LITERAL (IC_RIGHT (ic)))
11487     return 0;
11488
11489   if (operandLitValue (IC_RIGHT (ic)) != 1)
11490     return 0;
11491
11492   /* if the size of this greater than one then no
11493      saving */
11494   if (getSize (operandType (IC_RESULT (ic))) > 1)
11495     return 0;
11496
11497   /* otherwise we can save BIG */
11498
11499   D (emitcode (";", "genDjnz"));
11500
11501   lbl = newiTempLabel (NULL);
11502   lbl1 = newiTempLabel (NULL);
11503
11504   aopOp (IC_RESULT (ic), ic, FALSE);
11505
11506   if (AOP_NEEDSACC(IC_RESULT(ic)))
11507   {
11508       /* If the result is accessed indirectly via
11509        * the accumulator, we must explicitly write
11510        * it back after the decrement.
11511        */
11512       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE);
11513
11514       if (strcmp(rByte, "a"))
11515       {
11516            /* Something is hopelessly wrong */
11517            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11518                    __FILE__, __LINE__);
11519            /* We can just give up; the generated code will be inefficient,
11520             * but what the hey.
11521             */
11522            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11523            return 0;
11524       }
11525       emitcode ("dec", "%s", rByte);
11526       aopPut (IC_RESULT (ic), rByte, 0);
11527       emitcode ("jnz", "%05d$", lbl->key + 100);
11528   }
11529   else if (IS_AOP_PREG (IC_RESULT (ic)))
11530     {
11531       emitcode ("dec", "%s",
11532                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11533       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE));
11534       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11535       ifx->generated = 1;
11536       emitcode ("jnz", "%05d$", lbl->key + 100);
11537     }
11538   else
11539     {
11540       emitcode ("djnz", "%s,%05d$", aopGet (IC_RESULT (ic), 0, FALSE, FALSE),
11541                 lbl->key + 100);
11542     }
11543   emitcode ("sjmp", "%05d$", lbl1->key + 100);
11544   emitLabel (lbl);
11545   emitcode ("ljmp", "%05d$", IC_TRUE (ifx)->key + 100);
11546   emitLabel (lbl1);
11547
11548   if (!ifx->generated)
11549       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11550   ifx->generated = 1;
11551   return 1;
11552 }
11553
11554 /*-----------------------------------------------------------------*/
11555 /* genReceive - generate code for a receive iCode                  */
11556 /*-----------------------------------------------------------------*/
11557 static void
11558 genReceive (iCode * ic)
11559 {
11560   int size = getSize (operandType (IC_RESULT (ic)));
11561   int offset = 0;
11562
11563   D (emitcode (";", "genReceive"));
11564
11565   if (ic->argreg == 1)
11566     { /* first parameter */
11567       if ((isOperandInFarSpace (IC_RESULT (ic)) ||
11568            isOperandInPagedSpace (IC_RESULT (ic))) &&
11569           (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11570            IS_TRUE_SYMOP (IC_RESULT (ic))))
11571         {
11572           regs *tempRegs[4];
11573           int receivingA = 0;
11574           int roffset = 0;
11575
11576           for (offset = 0; offset<size; offset++)
11577             if (!strcmp (fReturn[offset], "a"))
11578               receivingA = 1;
11579
11580           if (!receivingA)
11581             {
11582               if (size==1 || getTempRegs(tempRegs, size-1, ic))
11583                 {
11584                   for (offset = size-1; offset>0; offset--)
11585                     emitcode("mov","%s,%s", tempRegs[roffset++]->name, fReturn[offset]);
11586                   emitcode("mov","a,%s", fReturn[0]);
11587                   _G.accInUse++;
11588                   aopOp (IC_RESULT (ic), ic, FALSE);
11589                   _G.accInUse--;
11590                   aopPut (IC_RESULT (ic), "a", offset);
11591                   for (offset = 1; offset<size; offset++)
11592                     aopPut (IC_RESULT (ic), tempRegs[--roffset]->name, offset);
11593                   goto release;
11594                 }
11595             }
11596           else
11597             {
11598               if (getTempRegs(tempRegs, size, ic))
11599                 {
11600                   for (offset = 0; offset<size; offset++)
11601                     emitcode("mov","%s,%s", tempRegs[offset]->name, fReturn[offset]);
11602                   aopOp (IC_RESULT (ic), ic, FALSE);
11603                   for (offset = 0; offset<size; offset++)
11604                     aopPut (IC_RESULT (ic), tempRegs[offset]->name, offset);
11605                   goto release;
11606                 }
11607             }
11608
11609           offset = fReturnSizeMCS51 - size;
11610           while (size--)
11611             {
11612               emitcode ("push", "%s", (strcmp (fReturn[fReturnSizeMCS51 - offset - 1], "a") ?
11613                                        fReturn[fReturnSizeMCS51 - offset - 1] : "acc"));
11614               offset++;
11615             }
11616           aopOp (IC_RESULT (ic), ic, FALSE);
11617           size = AOP_SIZE (IC_RESULT (ic));
11618           offset = 0;
11619           while (size--)
11620             {
11621               emitcode ("pop", "acc");
11622               aopPut (IC_RESULT (ic), "a", offset++);
11623             }
11624         }
11625       else
11626         {
11627           _G.accInUse++;
11628           aopOp (IC_RESULT (ic), ic, FALSE);
11629           _G.accInUse--;
11630           assignResultValue (IC_RESULT (ic), NULL);
11631         }
11632     }
11633   else if (ic->argreg > 12)
11634     { /* bit parameters */
11635       regs *reg = OP_SYMBOL (IC_RESULT (ic))->regs[0];
11636
11637       BitBankUsed = 1;
11638       if (!reg || reg->rIdx != ic->argreg-5)
11639         {
11640           aopOp (IC_RESULT (ic), ic, FALSE);
11641           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
11642           outBitC(IC_RESULT (ic));
11643         }
11644     }
11645   else
11646     { /* other parameters */
11647       int rb1off ;
11648       aopOp (IC_RESULT (ic), ic, FALSE);
11649       rb1off = ic->argreg;
11650       while (size--)
11651         {
11652           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
11653         }
11654     }
11655
11656 release:
11657   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11658 }
11659
11660 /*-----------------------------------------------------------------*/
11661 /* genDummyRead - generate code for dummy read of volatiles        */
11662 /*-----------------------------------------------------------------*/
11663 static void
11664 genDummyRead (iCode * ic)
11665 {
11666   operand *op;
11667   int size, offset;
11668
11669   D (emitcode(";", "genDummyRead"));
11670
11671   op = IC_RIGHT (ic);
11672   if (op && IS_SYMOP (op))
11673     {
11674       aopOp (op, ic, FALSE);
11675
11676       /* if the result is a bit */
11677       if (AOP_TYPE (op) == AOP_CRY)
11678         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11679       else
11680         {
11681           /* bit variables done */
11682           /* general case */
11683           size = AOP_SIZE (op);
11684           offset = 0;
11685           while (size--)
11686           {
11687             MOVA (aopGet (op, offset, FALSE, FALSE));
11688             offset++;
11689           }
11690         }
11691
11692       freeAsmop (op, NULL, ic, TRUE);
11693     }
11694
11695   op = IC_LEFT (ic);
11696   if (op && IS_SYMOP (op))
11697     {
11698       aopOp (op, ic, FALSE);
11699
11700       /* if the result is a bit */
11701       if (AOP_TYPE (op) == AOP_CRY)
11702         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
11703       else
11704         {
11705           /* bit variables done */
11706           /* general case */
11707           size = AOP_SIZE (op);
11708           offset = 0;
11709           while (size--)
11710           {
11711             MOVA (aopGet (op, offset, FALSE, FALSE));
11712             offset++;
11713           }
11714         }
11715
11716       freeAsmop (op, NULL, ic, TRUE);
11717     }
11718 }
11719
11720 /*-----------------------------------------------------------------*/
11721 /* genCritical - generate code for start of a critical sequence    */
11722 /*-----------------------------------------------------------------*/
11723 static void
11724 genCritical (iCode *ic)
11725 {
11726   symbol *tlbl = newiTempLabel (NULL);
11727
11728   D (emitcode(";", "genCritical"));
11729
11730   if (IC_RESULT (ic))
11731     {
11732       aopOp (IC_RESULT (ic), ic, TRUE);
11733       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
11734       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11735       aopPut (IC_RESULT (ic), zero, 0);
11736       emitLabel (tlbl);
11737       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11738     }
11739   else
11740     {
11741       emitcode ("setb", "c");
11742       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
11743       emitcode ("clr", "c");
11744       emitLabel (tlbl);
11745       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
11746     }
11747 }
11748
11749 /*-----------------------------------------------------------------*/
11750 /* genEndCritical - generate code for end of a critical sequence   */
11751 /*-----------------------------------------------------------------*/
11752 static void
11753 genEndCritical (iCode *ic)
11754 {
11755   D(emitcode(";", "genEndCritical"));
11756
11757   if (IC_RIGHT (ic))
11758     {
11759       aopOp (IC_RIGHT (ic), ic, FALSE);
11760       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
11761         {
11762           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
11763           emitcode ("mov", "ea,c");
11764         }
11765       else
11766         {
11767           if (AOP_TYPE (IC_RIGHT (ic)) != AOP_DUMMY)
11768             MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE));
11769           emitcode ("rrc", "a");
11770           emitcode ("mov", "ea,c");
11771         }
11772       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
11773     }
11774   else
11775     {
11776       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
11777       emitcode ("mov", "ea,c");
11778     }
11779 }
11780
11781 /*-----------------------------------------------------------------*/
11782 /* gen51Code - generate code for 8051 based controllers            */
11783 /*-----------------------------------------------------------------*/
11784 void
11785 gen51Code (iCode * lic)
11786 {
11787   iCode *ic;
11788   int cln = 0;
11789   /* int cseq = 0; */
11790
11791   _G.currentFunc = NULL;
11792   lineHead = lineCurr = NULL;
11793
11794   /* print the allocation information */
11795   if (allocInfo && currFunc)
11796     printAllocInfo (currFunc, codeOutBuf);
11797   /* if debug information required */
11798   if (options.debug && currFunc)
11799     {
11800       debugFile->writeFunction (currFunc, lic);
11801     }
11802   /* stack pointer name */
11803   if (options.useXstack)
11804     spname = "_spx";
11805   else
11806     spname = "sp";
11807
11808
11809   for (ic = lic; ic; ic = ic->next)
11810     {
11811       _G.current_iCode = ic;
11812
11813       if (ic->lineno && cln != ic->lineno)
11814         {
11815           if (options.debug)
11816             {
11817               debugFile->writeCLine (ic);
11818             }
11819           if (!options.noCcodeInAsm) {
11820             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
11821                       printCLine(ic->filename, ic->lineno));
11822           }
11823           cln = ic->lineno;
11824         }
11825       #if 0
11826       if (ic->seqPoint && ic->seqPoint != cseq)
11827         {
11828           emitcode (";", "sequence point %d", ic->seqPoint);
11829           cseq = ic->seqPoint;
11830         }
11831       #endif
11832       if (options.iCodeInAsm) {
11833         char regsInUse[80];
11834         int i;
11835         char *iLine;
11836
11837         #if 0
11838         for (i=0; i<8; i++) {
11839           sprintf (&regsInUse[i],
11840                    "%c", ic->riu & (1<<i) ? i+'0' : '-'); /* show riu */
11841         regsInUse[i]=0;
11842         #else
11843         strcpy (regsInUse, "--------");
11844         for (i=0; i < 8; i++) {
11845           if (bitVectBitValue (ic->rMask, i))
11846             {
11847               int offset = regs8051[i].offset;
11848               regsInUse[offset] = offset + '0'; /* show rMask */
11849             }
11850         #endif
11851         }
11852         iLine = printILine(ic);
11853         emitcode(";", "[%s] ic:%d: %s", regsInUse, ic->seq, iLine);
11854         dbuf_free(iLine);
11855       }
11856       /* if the result is marked as
11857          spilt and rematerializable or code for
11858          this has already been generated then
11859          do nothing */
11860       if (resultRemat (ic) || ic->generated)
11861         continue;
11862
11863       /* depending on the operation */
11864       switch (ic->op)
11865         {
11866         case '!':
11867           genNot (ic);
11868           break;
11869
11870         case '~':
11871           genCpl (ic);
11872           break;
11873
11874         case UNARYMINUS:
11875           genUminus (ic);
11876           break;
11877
11878         case IPUSH:
11879           genIpush (ic);
11880           break;
11881
11882         case IPOP:
11883           /* IPOP happens only when trying to restore a
11884              spilt live range, if there is an ifx statement
11885              following this pop then the if statement might
11886              be using some of the registers being popped which
11887              would destory the contents of the register so
11888              we need to check for this condition and handle it */
11889           if (ic->next &&
11890               ic->next->op == IFX &&
11891               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
11892             genIfx (ic->next, ic);
11893           else
11894             genIpop (ic);
11895           break;
11896
11897         case CALL:
11898           genCall (ic);
11899           break;
11900
11901         case PCALL:
11902           genPcall (ic);
11903           break;
11904
11905         case FUNCTION:
11906           genFunction (ic);
11907           break;
11908
11909         case ENDFUNCTION:
11910           genEndFunction (ic);
11911           break;
11912
11913         case RETURN:
11914           genRet (ic);
11915           break;
11916
11917         case LABEL:
11918           genLabel (ic);
11919           break;
11920
11921         case GOTO:
11922           genGoto (ic);
11923           break;
11924
11925         case '+':
11926           genPlus (ic);
11927           break;
11928
11929         case '-':
11930           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
11931             genMinus (ic);
11932           break;
11933
11934         case '*':
11935           genMult (ic);
11936           break;
11937
11938         case '/':
11939           genDiv (ic);
11940           break;
11941
11942         case '%':
11943           genMod (ic);
11944           break;
11945
11946         case '>':
11947           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
11948           break;
11949
11950         case '<':
11951           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
11952           break;
11953
11954         case LE_OP:
11955         case GE_OP:
11956         case NE_OP:
11957
11958           /* note these two are xlated by algebraic equivalence
11959              in decorateType() in SDCCast.c */
11960           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11961                   "got '>=' or '<=' shouldn't have come here");
11962           break;
11963
11964         case EQ_OP:
11965           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
11966           break;
11967
11968         case AND_OP:
11969           genAndOp (ic);
11970           break;
11971
11972         case OR_OP:
11973           genOrOp (ic);
11974           break;
11975
11976         case '^':
11977           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
11978           break;
11979
11980         case '|':
11981           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
11982           break;
11983
11984         case BITWISEAND:
11985           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
11986           break;
11987
11988         case INLINEASM:
11989           genInline (ic);
11990           break;
11991
11992         case RRC:
11993           genRRC (ic);
11994           break;
11995
11996         case RLC:
11997           genRLC (ic);
11998           break;
11999
12000         case GETHBIT:
12001           genGetHbit (ic);
12002           break;
12003
12004         case GETABIT:
12005           genGetAbit (ic);
12006           break;
12007
12008         case GETBYTE:
12009           genGetByte (ic);
12010           break;
12011
12012         case GETWORD:
12013           genGetWord (ic);
12014           break;
12015
12016         case LEFT_OP:
12017           genLeftShift (ic);
12018           break;
12019
12020         case RIGHT_OP:
12021           genRightShift (ic);
12022           break;
12023
12024         case GET_VALUE_AT_ADDRESS:
12025           genPointerGet (ic,
12026                          hasInc (IC_LEFT (ic), ic,
12027                                  getSize (operandType (IC_RESULT (ic)))),
12028                          ifxForOp (IC_RESULT (ic), ic) );
12029           break;
12030
12031         case '=':
12032           if (POINTER_SET (ic))
12033             genPointerSet (ic,
12034                            hasInc (IC_RESULT (ic), ic,
12035                                    getSize (operandType (IC_RIGHT (ic)))));
12036           else
12037             genAssign (ic);
12038           break;
12039
12040         case IFX:
12041           genIfx (ic, NULL);
12042           break;
12043
12044         case ADDRESS_OF:
12045           genAddrOf (ic);
12046           break;
12047
12048         case JUMPTABLE:
12049           genJumpTab (ic);
12050           break;
12051
12052         case CAST:
12053           genCast (ic);
12054           break;
12055
12056         case RECEIVE:
12057           genReceive (ic);
12058           break;
12059
12060         case SEND:
12061           addSet (&_G.sendSet, ic);
12062           break;
12063
12064         case DUMMY_READ_VOLATILE:
12065           genDummyRead (ic);
12066           break;
12067
12068         case CRITICAL:
12069           genCritical (ic);
12070           break;
12071
12072         case ENDCRITICAL:
12073           genEndCritical (ic);
12074           break;
12075
12076         case SWAP:
12077           genSwap (ic);
12078           break;
12079
12080         default:
12081           ic = ic;
12082         }
12083     }
12084
12085   _G.current_iCode = NULL;
12086
12087   /* now we are ready to call the
12088      peep hole optimizer */
12089   if (!options.nopeep)
12090     peepHole (&lineHead);
12091
12092   /* now do the actual printing */
12093   printLine (lineHead, codeOutBuf);
12094   return;
12095 }